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