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