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