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