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