xref: /illumos-gate/usr/src/lib/libc/port/threads/assfail.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 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) _private_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) _private_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) _private_sigemptyset(&sigmask);
82 	(void) _private_sigaddset(&sigmask, SIGABRT);
83 	(void) __lwp_sigmask(SIG_UNBLOCK, &sigmask, NULL);
84 
85 	(void) __lwp_kill(lwpid, SIGABRT);	/* never returns */
86 	(void) _kill(_private_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 void
95 thr_panic(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) _private_lwp_mutex_lock(&assert_lock);
104 
105 	(void) _private_memset(msg, 0, sizeof (msg));
106 	(void) strcpy(msg, "*** libc thread failure: ");
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 /*
120  * Utility function for converting a long integer to a string, avoiding stdio.
121  * 'base' must be one of 10 or 16
122  */
123 void
124 ultos(uint64_t n, int base, char *s)
125 {
126 	char lbuf[24];		/* 64 bits fits in 16 hex digits, 20 decimal */
127 	char *cp = lbuf;
128 
129 	do {
130 		*cp++ = "0123456789abcdef"[n%base];
131 		n /= base;
132 	} while (n);
133 	if (base == 16) {
134 		*s++ = '0';
135 		*s++ = 'x';
136 	}
137 	do {
138 		*s++ = *--cp;
139 	} while (cp > lbuf);
140 	*s = '\0';
141 }
142 
143 /*
144  * Report application lock usage error for mutexes and condvars.
145  * Not called if _THREAD_ERROR_DETECTION=0.
146  * Continue execution if _THREAD_ERROR_DETECTION=1.
147  * Dump core if _THREAD_ERROR_DETECTION=2.
148  */
149 void
150 lock_error(const mutex_t *mp, const char *who, void *cv, const char *msg)
151 {
152 	/* take a snapshot of the mutex before it changes (we hope!) */
153 	mutex_t mcopy = *mp;
154 	char buf[800];
155 	uberdata_t *udp;
156 	ulwp_t *self;
157 	lwpid_t lwpid;
158 	pid_t pid;
159 
160 	/* avoid recursion deadlock */
161 	if ((self = __curthread()) != NULL) {
162 		if (assert_thread == self)
163 			_exit(127);
164 		enter_critical(self);
165 		(void) _private_lwp_mutex_lock(&assert_lock);
166 		assert_thread = self;
167 		lwpid = self->ul_lwpid;
168 		udp = self->ul_uberdata;
169 		pid = udp->pid;
170 	} else {
171 		self = NULL;
172 		(void) _private_lwp_mutex_lock(&assert_lock);
173 		lwpid = __lwp_self();
174 		udp = &__uberdata;
175 		pid = _private_getpid();
176 	}
177 
178 	(void) strcpy(buf,
179 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
180 	(void) strcat(buf, who);
181 	(void) strcat(buf, "(");
182 	if (cv != NULL) {
183 		ultos((uint64_t)(uintptr_t)cv, 16, buf + strlen(buf));
184 		(void) strcat(buf, ", ");
185 	}
186 	ultos((uint64_t)(uintptr_t)mp, 16, buf + strlen(buf));
187 	(void) strcat(buf, ")");
188 	if (msg != NULL) {
189 		(void) strcat(buf, ": ");
190 		(void) strcat(buf, msg);
191 	} else if (!mutex_is_held(&mcopy)) {
192 		(void) strcat(buf, ": calling thread does not own the lock");
193 	} else if (mcopy.mutex_rcount) {
194 		(void) strcat(buf, ": mutex rcount = ");
195 		ultos((uint64_t)mcopy.mutex_rcount, 10, buf + strlen(buf));
196 	} else {
197 		(void) strcat(buf, ": calling thread already owns the lock");
198 	}
199 	(void) strcat(buf, "\ncalling thread is ");
200 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
201 	(void) strcat(buf, " thread-id ");
202 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
203 	if (msg != NULL || mutex_is_held(&mcopy))
204 		/* EMPTY */;
205 	else if (mcopy.mutex_lockw == 0)
206 		(void) strcat(buf, "\nthe lock is unowned");
207 	else if (!(mcopy.mutex_type & (USYNC_PROCESS|USYNC_PROCESS_ROBUST))) {
208 		(void) strcat(buf, "\nthe lock owner is ");
209 		ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
210 	} else {
211 		(void) strcat(buf, " in process ");
212 		ultos((uint64_t)pid, 10, buf + strlen(buf));
213 		(void) strcat(buf, "\nthe lock owner is ");
214 		ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
215 		(void) strcat(buf, " in process ");
216 		ultos((uint64_t)mcopy.mutex_ownerpid, 10, buf + strlen(buf));
217 	}
218 	(void) strcat(buf, "\n\n");
219 	(void) _write(2, buf, strlen(buf));
220 	if (udp->uberflags.uf_thread_error_detection >= 2)
221 		Abort(buf);
222 	assert_thread = NULL;
223 	(void) _private_lwp_mutex_unlock(&assert_lock);
224 	if (self != NULL)
225 		exit_critical(self);
226 }
227 
228 /*
229  * Report application lock usage error for rwlocks.
230  * Not called if _THREAD_ERROR_DETECTION=0.
231  * Continue execution if _THREAD_ERROR_DETECTION=1.
232  * Dump core if _THREAD_ERROR_DETECTION=2.
233  */
234 void
235 rwlock_error(const rwlock_t *rp, const char *who, const char *msg)
236 {
237 	/* take a snapshot of the rwlock before it changes (we hope) */
238 	rwlock_t rcopy = *rp;
239 	char buf[800];
240 	uberdata_t *udp;
241 	ulwp_t *self;
242 	lwpid_t lwpid;
243 	pid_t pid;
244 
245 	/* avoid recursion deadlock */
246 	if ((self = __curthread()) != NULL) {
247 		if (assert_thread == self)
248 			_exit(127);
249 		enter_critical(self);
250 		(void) _private_lwp_mutex_lock(&assert_lock);
251 		assert_thread = self;
252 		lwpid = self->ul_lwpid;
253 		udp = self->ul_uberdata;
254 		pid = udp->pid;
255 	} else {
256 		self = NULL;
257 		(void) _private_lwp_mutex_lock(&assert_lock);
258 		lwpid = __lwp_self();
259 		udp = &__uberdata;
260 		pid = _private_getpid();
261 	}
262 
263 	(void) strcpy(buf,
264 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
265 	(void) strcat(buf, who);
266 	(void) strcat(buf, "(");
267 	ultos((uint64_t)(uintptr_t)rp, 16, buf + strlen(buf));
268 	(void) strcat(buf, "): ");
269 	(void) strcat(buf, msg);
270 	(void) strcat(buf, "\ncalling thread is ");
271 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
272 	(void) strcat(buf, " thread-id ");
273 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
274 	if (rcopy.rwlock_type & USYNC_PROCESS) {
275 		uint32_t *rwstate = (uint32_t *)&rcopy.rwlock_readers;
276 
277 		(void) strcat(buf, " in process ");
278 		ultos((uint64_t)pid, 10, buf + strlen(buf));
279 
280 		if (*rwstate & URW_WRITE_LOCKED) {
281 			(void) strcat(buf, "\nthe lock writer owner is ");
282 			ultos((uint64_t)rcopy.rwlock_owner, 16,
283 			    buf + strlen(buf));
284 			(void) strcat(buf, " in process ");
285 			ultos((uint64_t)rcopy.rwlock_ownerpid, 10,
286 			    buf + strlen(buf));
287 		} else if (*rwstate & URW_READERS_MASK) {
288 			(void) strcat(buf, "\nthe lock is owned by ");
289 			ultos((uint64_t)(*rwstate & URW_READERS_MASK), 10,
290 			    buf + strlen(buf));
291 			(void) strcat(buf, " readers");
292 		} else
293 			(void) strcat(buf, "\nthe lock is unowned");
294 
295 		if (*rwstate & URW_HAS_WAITERS) {
296 			(void) strcat(buf, "\nand appears to have waiters");
297 			if (*rwstate & URW_WRITE_WANTED)
298 				(void) strcat(buf,
299 				    " (including at least one writer)");
300 		}
301 	} else if (rcopy.rwlock_readers < 0) {
302 		(void) strcat(buf, "\nthe lock writer owner is ");
303 		ultos((uint64_t)rcopy.rwlock_mowner, 16, buf + strlen(buf));
304 	} else if (rcopy.rwlock_readers > 0) {
305 		(void) strcat(buf, "\nthe lock is owned by ");
306 		ultos((uint64_t)rcopy.rwlock_readers, 10, buf + strlen(buf));
307 		(void) strcat(buf, "readers");
308 	} else {
309 		(void) strcat(buf, "\nthe lock is unowned");
310 	}
311 	(void) strcat(buf, "\n\n");
312 	(void) _write(2, buf, strlen(buf));
313 	if (udp->uberflags.uf_thread_error_detection >= 2)
314 		Abort(buf);
315 	assert_thread = NULL;
316 	(void) _private_lwp_mutex_unlock(&assert_lock);
317 	if (self != NULL)
318 		exit_critical(self);
319 }
320 
321 /*
322  * Report a thread usage error.
323  * Not called if _THREAD_ERROR_DETECTION=0.
324  * Writes message and continues execution if _THREAD_ERROR_DETECTION=1.
325  * Writes message and dumps core if _THREAD_ERROR_DETECTION=2.
326  */
327 void
328 thread_error(const char *msg)
329 {
330 	char buf[800];
331 	uberdata_t *udp;
332 	ulwp_t *self;
333 	lwpid_t lwpid;
334 
335 	/* avoid recursion deadlock */
336 	if ((self = __curthread()) != NULL) {
337 		if (assert_thread == self)
338 			_exit(127);
339 		enter_critical(self);
340 		(void) _private_lwp_mutex_lock(&assert_lock);
341 		assert_thread = self;
342 		lwpid = self->ul_lwpid;
343 		udp = self->ul_uberdata;
344 	} else {
345 		self = NULL;
346 		(void) _private_lwp_mutex_lock(&assert_lock);
347 		lwpid = __lwp_self();
348 		udp = &__uberdata;
349 	}
350 
351 	(void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: "
352 		"thread usage error detected ***\n*** ");
353 	(void) strcat(buf, msg);
354 
355 	(void) strcat(buf, "\n*** calling thread is ");
356 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
357 	(void) strcat(buf, " thread-id ");
358 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
359 	(void) strcat(buf, "\n\n");
360 	(void) _write(2, buf, strlen(buf));
361 	if (udp->uberflags.uf_thread_error_detection >= 2)
362 		Abort(buf);
363 	assert_thread = NULL;
364 	(void) _private_lwp_mutex_unlock(&assert_lock);
365 	if (self != NULL)
366 		exit_critical(self);
367 }
368 
369 /*
370  * We use __assfail() because the libc __assert() calls
371  * gettext() which calls malloc() which grabs a mutex.
372  * We do everything without calling standard i/o.
373  * _assfail() is an exported function, __assfail() is private to libc.
374  */
375 #pragma weak _assfail = __assfail
376 void
377 __assfail(const char *assertion, const char *filename, int line_num)
378 {
379 	char buf[800];	/* no assert() message in the library is this long */
380 	ulwp_t *self;
381 	lwpid_t lwpid;
382 
383 	/* avoid recursion deadlock */
384 	if ((self = __curthread()) != NULL) {
385 		if (assert_thread == self)
386 			_exit(127);
387 		enter_critical(self);
388 		(void) _private_lwp_mutex_lock(&assert_lock);
389 		assert_thread = self;
390 		lwpid = self->ul_lwpid;
391 	} else {
392 		self = NULL;
393 		(void) _private_lwp_mutex_lock(&assert_lock);
394 		lwpid = __lwp_self();
395 	}
396 
397 	(void) strcpy(buf, "assertion failed for thread ");
398 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
399 	(void) strcat(buf, ", thread-id ");
400 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
401 	(void) strcat(buf, ": ");
402 	(void) strcat(buf, assertion);
403 	(void) strcat(buf, ", file ");
404 	(void) strcat(buf, filename);
405 	(void) strcat(buf, ", line ");
406 	ultos((uint64_t)line_num, 10, buf + strlen(buf));
407 	(void) strcat(buf, "\n");
408 	(void) _write(2, buf, strlen(buf));
409 	/*
410 	 * We could replace the call to Abort() with the following code
411 	 * if we want just to issue a warning message and not die.
412 	 *	assert_thread = NULL;
413 	 *	_private_lwp_mutex_unlock(&assert_lock);
414 	 *	if (self != NULL)
415 	 *		exit_critical(self);
416 	 */
417 	Abort(buf);
418 }
419