|
11 | 11 | //===----------------------------------------------------------------------===//
|
12 | 12 |
|
13 | 13 | #include <sanitizer_common/sanitizer_deadlock_detector_interface.h>
|
| 14 | +#include <sanitizer_common/sanitizer_placement_new.h> |
14 | 15 | #include <sanitizer_common/sanitizer_stackdepot.h>
|
15 | 16 |
|
16 |
| -#include "tsan_rtl.h" |
17 | 17 | #include "tsan_flags.h"
|
18 |
| -#include "tsan_sync.h" |
| 18 | +#include "tsan_platform.h" |
19 | 19 | #include "tsan_report.h"
|
| 20 | +#include "tsan_rtl.h" |
20 | 21 | #include "tsan_symbolize.h"
|
21 |
| -#include "tsan_platform.h" |
| 22 | +#include "tsan_sync.h" |
22 | 23 |
|
23 | 24 | namespace __tsan {
|
24 | 25 |
|
@@ -55,14 +56,28 @@ static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
|
55 | 56 | return;
|
56 | 57 | if (!ShouldReport(thr, typ))
|
57 | 58 | return;
|
58 |
| - ThreadRegistryLock l(&ctx->thread_registry); |
59 |
| - ScopedReport rep(typ); |
60 |
| - rep.AddMutex(addr, creation_stack_id); |
61 |
| - VarSizeStackTrace trace; |
62 |
| - ObtainCurrentStack(thr, pc, &trace); |
63 |
| - rep.AddStack(trace, true); |
64 |
| - rep.AddLocation(addr, 1); |
65 |
| - OutputReport(thr, rep); |
| 59 | + // Use alloca, because malloc during signal handling deadlocks |
| 60 | + ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport)); |
| 61 | + // Take a new scope as Apple platforms require the below locks released |
| 62 | + // before symbolizing in order to avoid a deadlock |
| 63 | + { |
| 64 | + ThreadRegistryLock l(&ctx->thread_registry); |
| 65 | + new (rep) ScopedReport(typ); |
| 66 | + rep->AddMutex(addr, creation_stack_id); |
| 67 | + VarSizeStackTrace trace; |
| 68 | + ObtainCurrentStack(thr, pc, &trace); |
| 69 | + rep->AddStack(trace, true); |
| 70 | + rep->AddLocation(addr, 1); |
| 71 | +#if SANITIZER_APPLE |
| 72 | + } // Close this scope to release the locks |
| 73 | +#endif |
| 74 | + OutputReport(thr, *rep); |
| 75 | + |
| 76 | + // Need to manually destroy this because we used placement new to allocate |
| 77 | + rep->~ScopedReport(); |
| 78 | +#if !SANITIZER_APPLE |
| 79 | + } |
| 80 | +#endif |
66 | 81 | }
|
67 | 82 |
|
68 | 83 | static void RecordMutexLock(ThreadState *thr, uptr pc, uptr addr,
|
@@ -528,53 +543,81 @@ void AfterSleep(ThreadState *thr, uptr pc) {
|
528 | 543 | void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
|
529 | 544 | if (r == 0 || !ShouldReport(thr, ReportTypeDeadlock))
|
530 | 545 | return;
|
531 |
| - ThreadRegistryLock l(&ctx->thread_registry); |
532 |
| - ScopedReport rep(ReportTypeDeadlock); |
533 |
| - for (int i = 0; i < r->n; i++) { |
534 |
| - rep.AddMutex(r->loop[i].mtx_ctx0, r->loop[i].stk[0]); |
535 |
| - rep.AddUniqueTid((int)r->loop[i].thr_ctx); |
536 |
| - rep.AddThread((int)r->loop[i].thr_ctx); |
537 |
| - } |
538 |
| - uptr dummy_pc = 0x42; |
539 |
| - for (int i = 0; i < r->n; i++) { |
540 |
| - for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) { |
541 |
| - u32 stk = r->loop[i].stk[j]; |
542 |
| - StackTrace stack; |
543 |
| - if (stk && stk != kInvalidStackID) { |
544 |
| - stack = StackDepotGet(stk); |
545 |
| - } else { |
546 |
| - // Sometimes we fail to extract the stack trace (FIXME: investigate), |
547 |
| - // but we should still produce some stack trace in the report. |
548 |
| - stack = StackTrace(&dummy_pc, 1); |
| 546 | + // Use alloca, because malloc during signal handling deadlocks |
| 547 | + ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport)); |
| 548 | + // Take a new scope as Apple platforms require the below locks released |
| 549 | + // before symbolizing in order to avoid a deadlock |
| 550 | + { |
| 551 | + ThreadRegistryLock l(&ctx->thread_registry); |
| 552 | + new (rep) ScopedReport(ReportTypeDeadlock); |
| 553 | + for (int i = 0; i < r->n; i++) { |
| 554 | + rep->AddMutex(r->loop[i].mtx_ctx0, r->loop[i].stk[0]); |
| 555 | + rep->AddUniqueTid((int)r->loop[i].thr_ctx); |
| 556 | + rep->AddThread((int)r->loop[i].thr_ctx); |
| 557 | + } |
| 558 | + uptr dummy_pc = 0x42; |
| 559 | + for (int i = 0; i < r->n; i++) { |
| 560 | + for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) { |
| 561 | + u32 stk = r->loop[i].stk[j]; |
| 562 | + StackTrace stack; |
| 563 | + if (stk && stk != kInvalidStackID) { |
| 564 | + stack = StackDepotGet(stk); |
| 565 | + } else { |
| 566 | + // Sometimes we fail to extract the stack trace (FIXME: investigate), |
| 567 | + // but we should still produce some stack trace in the report. |
| 568 | + stack = StackTrace(&dummy_pc, 1); |
| 569 | + } |
| 570 | + rep->AddStack(stack, true); |
549 | 571 | }
|
550 |
| - rep.AddStack(stack, true); |
551 | 572 | }
|
| 573 | +#if SANITIZER_APPLE |
| 574 | + } // Close this scope to release the locks |
| 575 | +#endif |
| 576 | + OutputReport(thr, *rep); |
| 577 | + |
| 578 | + // Need to manually destroy this because we used placement new to allocate |
| 579 | + rep->~ScopedReport(); |
| 580 | +#if !SANITIZER_APPLE |
552 | 581 | }
|
553 |
| - OutputReport(thr, rep); |
| 582 | +#endif |
554 | 583 | }
|
555 | 584 |
|
556 | 585 | void ReportDestroyLocked(ThreadState *thr, uptr pc, uptr addr,
|
557 | 586 | FastState last_lock, StackID creation_stack_id) {
|
558 |
| - // We need to lock the slot during RestoreStack because it protects |
559 |
| - // the slot journal. |
560 |
| - Lock slot_lock(&ctx->slots[static_cast<uptr>(last_lock.sid())].mtx); |
561 |
| - ThreadRegistryLock l0(&ctx->thread_registry); |
562 |
| - Lock slots_lock(&ctx->slot_mtx); |
563 |
| - ScopedReport rep(ReportTypeMutexDestroyLocked); |
564 |
| - rep.AddMutex(addr, creation_stack_id); |
565 |
| - VarSizeStackTrace trace; |
566 |
| - ObtainCurrentStack(thr, pc, &trace); |
567 |
| - rep.AddStack(trace, true); |
568 |
| - |
569 |
| - Tid tid; |
570 |
| - DynamicMutexSet mset; |
571 |
| - uptr tag; |
572 |
| - if (!RestoreStack(EventType::kLock, last_lock.sid(), last_lock.epoch(), addr, |
573 |
| - 0, kAccessWrite, &tid, &trace, mset, &tag)) |
574 |
| - return; |
575 |
| - rep.AddStack(trace, true); |
576 |
| - rep.AddLocation(addr, 1); |
577 |
| - OutputReport(thr, rep); |
| 587 | + // Use alloca, because malloc during signal handling deadlocks |
| 588 | + ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport)); |
| 589 | + // Take a new scope as Apple platforms require the below locks released |
| 590 | + // before symbolizing in order to avoid a deadlock |
| 591 | + { |
| 592 | + // We need to lock the slot during RestoreStack because it protects |
| 593 | + // the slot journal. |
| 594 | + Lock slot_lock(&ctx->slots[static_cast<uptr>(last_lock.sid())].mtx); |
| 595 | + ThreadRegistryLock l0(&ctx->thread_registry); |
| 596 | + Lock slots_lock(&ctx->slot_mtx); |
| 597 | + new (rep) ScopedReport(ReportTypeMutexDestroyLocked); |
| 598 | + rep->AddMutex(addr, creation_stack_id); |
| 599 | + VarSizeStackTrace trace; |
| 600 | + ObtainCurrentStack(thr, pc, &trace); |
| 601 | + rep->AddStack(trace, true); |
| 602 | + |
| 603 | + Tid tid; |
| 604 | + DynamicMutexSet mset; |
| 605 | + uptr tag; |
| 606 | + if (!RestoreStack(EventType::kLock, last_lock.sid(), last_lock.epoch(), |
| 607 | + addr, 0, kAccessWrite, &tid, &trace, mset, &tag)) |
| 608 | + return; |
| 609 | + rep->AddStack(trace, true); |
| 610 | + rep->AddLocation(addr, 1); |
| 611 | +#if SANITIZER_APPLE |
| 612 | + } // Close this scope to release the locks |
| 613 | +#endif |
| 614 | + OutputReport(thr, *rep); |
| 615 | + |
| 616 | + // Need to manually destroy this because we used placement new to allocate |
| 617 | + rep->~ScopedReport(); |
| 618 | +#if !SANITIZER_APPLE |
| 619 | + } |
| 620 | +#endif |
578 | 621 | }
|
579 | 622 |
|
580 | 623 | } // namespace __tsan
|
0 commit comments