|
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,51 +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 | | - if (stk && stk != kInvalidStackID) { |
543 | | - rep.AddStack(StackDepotGet(stk), true); |
544 | | - } else { |
545 | | - // Sometimes we fail to extract the stack trace (FIXME: investigate), |
546 | | - // but we should still produce some stack trace in the report. |
547 | | - rep.AddStack(StackTrace(&dummy_pc, 1), true); |
| 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); |
548 | 571 | } |
549 | 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 |
550 | 581 | } |
551 | | - OutputReport(thr, rep); |
| 582 | +#endif |
552 | 583 | } |
553 | 584 |
|
554 | 585 | void ReportDestroyLocked(ThreadState *thr, uptr pc, uptr addr, |
555 | 586 | FastState last_lock, StackID creation_stack_id) { |
556 | | - // We need to lock the slot during RestoreStack because it protects |
557 | | - // the slot journal. |
558 | | - Lock slot_lock(&ctx->slots[static_cast<uptr>(last_lock.sid())].mtx); |
559 | | - ThreadRegistryLock l0(&ctx->thread_registry); |
560 | | - Lock slots_lock(&ctx->slot_mtx); |
561 | | - ScopedReport rep(ReportTypeMutexDestroyLocked); |
562 | | - rep.AddMutex(addr, creation_stack_id); |
563 | | - VarSizeStackTrace trace; |
564 | | - ObtainCurrentStack(thr, pc, &trace); |
565 | | - rep.AddStack(trace, true); |
566 | | - |
567 | | - Tid tid; |
568 | | - DynamicMutexSet mset; |
569 | | - uptr tag; |
570 | | - if (!RestoreStack(EventType::kLock, last_lock.sid(), last_lock.epoch(), addr, |
571 | | - 0, kAccessWrite, &tid, &trace, mset, &tag)) |
572 | | - return; |
573 | | - rep.AddStack(trace, true); |
574 | | - rep.AddLocation(addr, 1); |
575 | | - 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 |
576 | 621 | } |
577 | 622 |
|
578 | 623 | } // namespace __tsan |
0 commit comments