xref: /illumos-gate/usr/src/lib/libc/port/threads/assfail.c (revision dd72704bd9e794056c558153663c739e2012d721)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /*
27  * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
28  * Copyright 2015 Joyent, Inc.
29  * Copyright 2020 Oxide Computer Company
30  */
31 
32 #include "lint.h"
33 #include "thr_uberdata.h"
34 #include <upanic.h>
35 
36 const char *panicstr;
37 ulwp_t *panic_thread;
38 
39 static mutex_t assert_lock = DEFAULTMUTEX;
40 static ulwp_t *assert_thread = NULL;
41 
42 mutex_t *panic_mutex = NULL;
43 
44 /*
45  * Called from __assert() to set panicstr and panic_thread.
46  */
47 void
48 __set_panicstr(const char *msg)
49 {
50 	panicstr = msg;
51 	panic_thread = __curthread();
52 }
53 
54 /*
55  * Called from exit() (atexit function) to give precedence
56  * to assertion failures and a core dump over _exit().
57  */
58 void
59 grab_assert_lock()
60 {
61 	(void) _lwp_mutex_lock(&assert_lock);
62 }
63 
64 static void
65 Abort(const char *msg, size_t buflen)
66 {
67 	ulwp_t *self;
68 
69 	/* to help with core file debugging */
70 	panicstr = msg;
71 	if ((self = __curthread()) != NULL) {
72 		panic_thread = self;
73 	}
74 
75 	upanic(msg, buflen);
76 }
77 
78 /*
79  * Write a panic message w/o grabbing any locks other than assert_lock.
80  * We have no idea what locks are held at this point.
81  */
82 void
83 common_panic(const char *head, const char *why)
84 {
85 	char msg[400];	/* no panic() message in the library is this long */
86 	ulwp_t *self;
87 	size_t len1, len2;
88 
89 	if ((self = __curthread()) != NULL)
90 		enter_critical(self);
91 	(void) _lwp_mutex_lock(&assert_lock);
92 
93 	(void) memset(msg, 0, sizeof (msg));
94 	(void) strcpy(msg, head);
95 	len1 = strlen(msg);
96 	len2 = strlen(why);
97 	if (len1 + len2 >= sizeof (msg))
98 		len2 = sizeof (msg) - len1 - 1;
99 	(void) strncat(msg, why, len2);
100 	len1 = strlen(msg);
101 	if (msg[len1 - 1] != '\n')
102 		msg[len1++] = '\n';
103 	(void) __write(2, msg, len1);
104 	Abort(msg, sizeof (msg));
105 }
106 
107 void
108 thr_panic(const char *why)
109 {
110 	common_panic("*** libc thread failure: ", why);
111 }
112 
113 void
114 aio_panic(const char *why)
115 {
116 	common_panic("*** libc aio system failure: ", why);
117 }
118 
119 void
120 mutex_panic(mutex_t *mp, const char *why)
121 {
122 	panic_mutex = mp;
123 	common_panic("*** libc mutex system failure: ", why);
124 }
125 
126 /*
127  * Utility function for converting a long integer to a string, avoiding stdio.
128  * 'base' must be one of 10 or 16
129  */
130 void
131 ultos(uint64_t n, int base, char *s)
132 {
133 	char lbuf[24];		/* 64 bits fits in 16 hex digits, 20 decimal */
134 	char *cp = lbuf;
135 
136 	do {
137 		*cp++ = "0123456789abcdef"[n%base];
138 		n /= base;
139 	} while (n);
140 	if (base == 16) {
141 		*s++ = '0';
142 		*s++ = 'x';
143 	}
144 	do {
145 		*s++ = *--cp;
146 	} while (cp > lbuf);
147 	*s = '\0';
148 }
149 
150 /*
151  * Report application lock usage error for mutexes and condvars.
152  * Not called if _THREAD_ERROR_DETECTION=0.
153  * Continue execution if _THREAD_ERROR_DETECTION=1.
154  * Dump core if _THREAD_ERROR_DETECTION=2.
155  */
156 void
157 lock_error(const mutex_t *mp, const char *who, void *cv, const char *msg)
158 {
159 	mutex_t mcopy;
160 	char buf[800];
161 	uberdata_t *udp;
162 	ulwp_t *self;
163 	lwpid_t lwpid;
164 	pid_t pid;
165 
166 	/*
167 	 * Take a snapshot of the mutex before it changes (we hope!).
168 	 * Use memcpy() rather than 'mcopy = *mp' in case mp is unaligned.
169 	 */
170 	(void) memcpy(&mcopy, mp, sizeof (mcopy));
171 
172 	/* avoid recursion deadlock */
173 	if ((self = __curthread()) != NULL) {
174 		if (assert_thread == self)
175 			_exit(127);
176 		enter_critical(self);
177 		(void) _lwp_mutex_lock(&assert_lock);
178 		assert_thread = self;
179 		lwpid = self->ul_lwpid;
180 		udp = self->ul_uberdata;
181 		pid = udp->pid;
182 	} else {
183 		self = NULL;
184 		(void) _lwp_mutex_lock(&assert_lock);
185 		lwpid = _lwp_self();
186 		udp = &__uberdata;
187 		pid = getpid();
188 	}
189 
190 	(void) strcpy(buf,
191 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
192 	(void) strcat(buf, who);
193 	(void) strcat(buf, "(");
194 	if (cv != NULL) {
195 		ultos((uint64_t)(uintptr_t)cv, 16, buf + strlen(buf));
196 		(void) strcat(buf, ", ");
197 	}
198 	ultos((uint64_t)(uintptr_t)mp, 16, buf + strlen(buf));
199 	(void) strcat(buf, ")");
200 	if (msg != NULL) {
201 		(void) strcat(buf, ": ");
202 		(void) strcat(buf, msg);
203 	} else if (!mutex_held(&mcopy)) {
204 		(void) strcat(buf, ": calling thread does not own the lock");
205 	} else if (mcopy.mutex_rcount) {
206 		(void) strcat(buf, ": mutex rcount = ");
207 		ultos((uint64_t)mcopy.mutex_rcount, 10, buf + strlen(buf));
208 	} else {
209 		(void) strcat(buf, ": calling thread already owns the lock");
210 	}
211 	(void) strcat(buf, "\ncalling thread is ");
212 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
213 	(void) strcat(buf, " thread-id ");
214 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
215 	if (msg != NULL || mutex_held(&mcopy))
216 		/* EMPTY */;
217 	else if (mcopy.mutex_lockw == 0)
218 		(void) strcat(buf, "\nthe lock is unowned");
219 	else if (!(mcopy.mutex_type & USYNC_PROCESS)) {
220 		(void) strcat(buf, "\nthe lock owner is ");
221 		ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
222 	} else {
223 		(void) strcat(buf, " in process ");
224 		ultos((uint64_t)pid, 10, buf + strlen(buf));
225 		(void) strcat(buf, "\nthe lock owner is ");
226 		ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
227 		(void) strcat(buf, " in process ");
228 		ultos((uint64_t)mcopy.mutex_ownerpid, 10, buf + strlen(buf));
229 	}
230 	(void) strcat(buf, "\n\n");
231 	(void) __write(2, buf, strlen(buf));
232 	if (udp->uberflags.uf_thread_error_detection >= 2)
233 		Abort(buf, sizeof (buf));
234 	assert_thread = NULL;
235 	(void) _lwp_mutex_unlock(&assert_lock);
236 	if (self != NULL)
237 		exit_critical(self);
238 }
239 
240 /*
241  * Report application lock usage error for rwlocks.
242  * Not called if _THREAD_ERROR_DETECTION=0.
243  * Continue execution if _THREAD_ERROR_DETECTION=1.
244  * Dump core if _THREAD_ERROR_DETECTION=2.
245  */
246 void
247 rwlock_error(const rwlock_t *rp, const char *who, const char *msg)
248 {
249 	rwlock_t rcopy;
250 	uint32_t rwstate;
251 	char buf[800];
252 	uberdata_t *udp;
253 	ulwp_t *self;
254 	lwpid_t lwpid;
255 	pid_t pid;
256 	int process;
257 
258 	/*
259 	 * Take a snapshot of the rwlock before it changes (we hope!).
260 	 * Use memcpy() rather than 'rcopy = *rp' in case rp is unaligned.
261 	 */
262 	(void) memcpy(&rcopy, rp, sizeof (rcopy));
263 
264 	/* avoid recursion deadlock */
265 	if ((self = __curthread()) != NULL) {
266 		if (assert_thread == self)
267 			_exit(127);
268 		enter_critical(self);
269 		(void) _lwp_mutex_lock(&assert_lock);
270 		assert_thread = self;
271 		lwpid = self->ul_lwpid;
272 		udp = self->ul_uberdata;
273 		pid = udp->pid;
274 	} else {
275 		self = NULL;
276 		(void) _lwp_mutex_lock(&assert_lock);
277 		lwpid = _lwp_self();
278 		udp = &__uberdata;
279 		pid = getpid();
280 	}
281 
282 	rwstate = (uint32_t)rcopy.rwlock_readers;
283 	process = (rcopy.rwlock_type & USYNC_PROCESS);
284 
285 	(void) strcpy(buf,
286 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
287 	(void) strcat(buf, who);
288 	(void) strcat(buf, "(");
289 	ultos((uint64_t)(uintptr_t)rp, 16, buf + strlen(buf));
290 	(void) strcat(buf, "): ");
291 	(void) strcat(buf, msg);
292 	(void) strcat(buf, "\ncalling thread is ");
293 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
294 	(void) strcat(buf, " thread-id ");
295 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
296 	if (process) {
297 		(void) strcat(buf, " in process ");
298 		ultos((uint64_t)pid, 10, buf + strlen(buf));
299 	}
300 	if (rwstate & URW_WRITE_LOCKED) {
301 		(void) strcat(buf, "\nthe writer lock owner is ");
302 		ultos((uint64_t)rcopy.rwlock_owner, 16,
303 		    buf + strlen(buf));
304 		if (process) {
305 			(void) strcat(buf, " in process ");
306 			ultos((uint64_t)rcopy.rwlock_ownerpid, 10,
307 			    buf + strlen(buf));
308 		}
309 	} else if (rwstate & URW_READERS_MASK) {
310 		(void) strcat(buf, "\nthe reader lock is held by ");
311 		ultos((uint64_t)(rwstate & URW_READERS_MASK), 10,
312 		    buf + strlen(buf));
313 		(void) strcat(buf, " readers");
314 	} else {
315 		(void) strcat(buf, "\nthe lock is unowned");
316 	}
317 	if (rwstate & URW_HAS_WAITERS)
318 		(void) strcat(buf, "\nand the lock appears to have waiters");
319 	(void) strcat(buf, "\n\n");
320 	(void) __write(2, buf, strlen(buf));
321 	if (udp->uberflags.uf_thread_error_detection >= 2)
322 		Abort(buf, sizeof (buf));
323 	assert_thread = NULL;
324 	(void) _lwp_mutex_unlock(&assert_lock);
325 	if (self != NULL)
326 		exit_critical(self);
327 }
328 
329 /*
330  * Report a thread usage error.
331  * Not called if _THREAD_ERROR_DETECTION=0.
332  * Writes message and continues execution if _THREAD_ERROR_DETECTION=1.
333  * Writes message and dumps core if _THREAD_ERROR_DETECTION=2.
334  */
335 void
336 thread_error(const char *msg)
337 {
338 	char buf[800];
339 	uberdata_t *udp;
340 	ulwp_t *self;
341 	lwpid_t lwpid;
342 
343 	/* avoid recursion deadlock */
344 	if ((self = __curthread()) != NULL) {
345 		if (assert_thread == self)
346 			_exit(127);
347 		enter_critical(self);
348 		(void) _lwp_mutex_lock(&assert_lock);
349 		assert_thread = self;
350 		lwpid = self->ul_lwpid;
351 		udp = self->ul_uberdata;
352 	} else {
353 		self = NULL;
354 		(void) _lwp_mutex_lock(&assert_lock);
355 		lwpid = _lwp_self();
356 		udp = &__uberdata;
357 	}
358 
359 	(void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: "
360 	    "thread usage error detected ***\n*** ");
361 	(void) strcat(buf, msg);
362 
363 	(void) strcat(buf, "\n*** calling thread is ");
364 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
365 	(void) strcat(buf, " thread-id ");
366 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
367 	(void) strcat(buf, "\n\n");
368 	(void) __write(2, buf, strlen(buf));
369 	if (udp->uberflags.uf_thread_error_detection >= 2)
370 		Abort(buf, sizeof (buf));
371 	assert_thread = NULL;
372 	(void) _lwp_mutex_unlock(&assert_lock);
373 	if (self != NULL)
374 		exit_critical(self);
375 }
376 
377 /*
378  * We use __assfail() because the libc __assert() calls
379  * gettext() which calls malloc() which grabs a mutex.
380  * We do everything without calling standard i/o.
381  * assfail() and _assfail() are exported functions;
382  * __assfail() is private to libc.
383  */
384 #pragma weak _assfail = __assfail
385 void
386 __assfail(const char *assertion, const char *filename, int line_num)
387 {
388 	char buf[800];	/* no assert() message in the library is this long */
389 	ulwp_t *self;
390 	lwpid_t lwpid;
391 
392 	/* avoid recursion deadlock */
393 	if ((self = __curthread()) != NULL) {
394 		if (assert_thread == self)
395 			_exit(127);
396 		enter_critical(self);
397 		(void) _lwp_mutex_lock(&assert_lock);
398 		assert_thread = self;
399 		lwpid = self->ul_lwpid;
400 	} else {
401 		self = NULL;
402 		(void) _lwp_mutex_lock(&assert_lock);
403 		lwpid = _lwp_self();
404 	}
405 
406 	/*
407 	 * This is a hack, but since the Abort function isn't exported
408 	 * to outside consumers, libzpool's vpanic() function calls
409 	 * assfail() with a filename set to NULL. In that case, it'd be
410 	 * best not to print "assertion failed" since it was a panic and
411 	 * not an assertion failure.
412 	 */
413 	if (filename == NULL) {
414 		(void) strcpy(buf, "failure for thread ");
415 	} else {
416 		(void) strcpy(buf, "assertion failed for thread ");
417 	}
418 
419 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
420 	(void) strcat(buf, ", thread-id ");
421 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
422 	(void) strcat(buf, ": ");
423 	(void) strcat(buf, assertion);
424 
425 	if (filename != NULL) {
426 		(void) strcat(buf, ", file ");
427 		(void) strcat(buf, filename);
428 		(void) strcat(buf, ", line ");
429 		ultos((uint64_t)line_num, 10, buf + strlen(buf));
430 	}
431 
432 	(void) strcat(buf, "\n");
433 	(void) __write(2, buf, strlen(buf));
434 	/*
435 	 * We could replace the call to Abort() with the following code
436 	 * if we want just to issue a warning message and not die.
437 	 *	assert_thread = NULL;
438 	 *	_lwp_mutex_unlock(&assert_lock);
439 	 *	if (self != NULL)
440 	 *		exit_critical(self);
441 	 */
442 	Abort(buf, sizeof (buf));
443 }
444 
445 /*
446  * We define and export this version of assfail() just because libaio
447  * used to define and export it, needlessly.  Now that libaio is folded
448  * into libc, we need to continue this for ABI/version reasons.
449  * We don't use "#pragma weak assfail __assfail" in order to avoid
450  * warnings from the check_fnames utility at build time for libraries
451  * that define their own version of assfail().
452  */
453 void
454 assfail(const char *assertion, const char *filename, int line_num)
455 {
456 	__assfail(assertion, filename, line_num);
457 }
458 
459 void
460 assfail3(const char *assertion, uintmax_t lv, const char *op, uintmax_t rv,
461     const char *filename, int line_num)
462 {
463 	char buf[1000];
464 	(void) strcpy(buf, assertion);
465 	(void) strcat(buf, " (");
466 	ultos((uint64_t)lv, 16, buf + strlen(buf));
467 	(void) strcat(buf, " ");
468 	(void) strcat(buf, op);
469 	(void) strcat(buf, " ");
470 	ultos((uint64_t)rv, 16, buf + strlen(buf));
471 	(void) strcat(buf, ")");
472 	__assfail(buf, filename, line_num);
473 }
474