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