Alexey Samsonov | 603c4be | 2012-06-04 13:55:19 +0000 | [diff] [blame] | 1 | //===-- tsan_suppressions.cc ----------------------------------------------===// |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file is a part of ThreadSanitizer (TSan), a race detector. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
Alexey Samsonov | 0969bcf | 2012-06-18 08:44:30 +0000 | [diff] [blame] | 14 | #include "sanitizer_common/sanitizer_common.h" |
Alexey Samsonov | 7f9c5a2 | 2012-06-05 07:46:31 +0000 | [diff] [blame] | 15 | #include "sanitizer_common/sanitizer_libc.h" |
Sergey Matveev | a52e5c6 | 2013-06-26 15:37:14 +0000 | [diff] [blame] | 16 | #include "sanitizer_common/sanitizer_placement_new.h" |
| 17 | #include "sanitizer_common/sanitizer_suppressions.h" |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 18 | #include "tsan_suppressions.h" |
| 19 | #include "tsan_rtl.h" |
| 20 | #include "tsan_flags.h" |
| 21 | #include "tsan_mman.h" |
| 22 | #include "tsan_platform.h" |
| 23 | |
Dmitry Vyukov | c2b9f1c | 2013-01-24 13:50:10 +0000 | [diff] [blame] | 24 | // Can be overriden in frontend. |
| 25 | #ifndef TSAN_GO |
| 26 | extern "C" const char *WEAK __tsan_default_suppressions() { |
| 27 | return 0; |
| 28 | } |
| 29 | #endif |
| 30 | |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 31 | namespace __tsan { |
| 32 | |
Sergey Matveev | a52e5c6 | 2013-06-26 15:37:14 +0000 | [diff] [blame] | 33 | static SuppressionContext* g_ctx; |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 34 | |
| 35 | static char *ReadFile(const char *filename) { |
| 36 | if (filename == 0 || filename[0] == 0) |
| 37 | return 0; |
Alexey Samsonov | 14c8bd7 | 2012-08-22 07:25:52 +0000 | [diff] [blame] | 38 | InternalScopedBuffer<char> tmp(4*1024); |
Dmitry Vyukov | 6422c32 | 2012-12-04 07:27:32 +0000 | [diff] [blame] | 39 | if (filename[0] == '/' || GetPwd() == 0) |
Alexey Samsonov | 1dc4cf7 | 2012-09-05 07:23:44 +0000 | [diff] [blame] | 40 | internal_snprintf(tmp.data(), tmp.size(), "%s", filename); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 41 | else |
Alexey Samsonov | 1dc4cf7 | 2012-09-05 07:23:44 +0000 | [diff] [blame] | 42 | internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename); |
Peter Collingbourne | 9578a3e | 2013-05-08 14:43:49 +0000 | [diff] [blame] | 43 | uptr openrv = OpenFile(tmp.data(), false); |
| 44 | if (internal_iserror(openrv)) { |
Alexey Samsonov | b1fe302 | 2012-11-02 12:17:51 +0000 | [diff] [blame] | 45 | Printf("ThreadSanitizer: failed to open suppressions file '%s'\n", |
Alexey Samsonov | 14c8bd7 | 2012-08-22 07:25:52 +0000 | [diff] [blame] | 46 | tmp.data()); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 47 | Die(); |
| 48 | } |
Peter Collingbourne | 9578a3e | 2013-05-08 14:43:49 +0000 | [diff] [blame] | 49 | fd_t fd = openrv; |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 50 | const uptr fsize = internal_filesize(fd); |
| 51 | if (fsize == (uptr)-1) { |
Alexey Samsonov | b1fe302 | 2012-11-02 12:17:51 +0000 | [diff] [blame] | 52 | Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n", |
Alexey Samsonov | 14c8bd7 | 2012-08-22 07:25:52 +0000 | [diff] [blame] | 53 | tmp.data()); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 54 | Die(); |
| 55 | } |
| 56 | char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1); |
| 57 | if (fsize != internal_read(fd, buf, fsize)) { |
Alexey Samsonov | b1fe302 | 2012-11-02 12:17:51 +0000 | [diff] [blame] | 58 | Printf("ThreadSanitizer: failed to read suppressions file '%s'\n", |
Alexey Samsonov | 14c8bd7 | 2012-08-22 07:25:52 +0000 | [diff] [blame] | 59 | tmp.data()); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 60 | Die(); |
| 61 | } |
| 62 | internal_close(fd); |
| 63 | buf[fsize] = 0; |
| 64 | return buf; |
| 65 | } |
| 66 | |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 67 | void InitializeSuppressions() { |
Sergey Matveev | a52e5c6 | 2013-06-26 15:37:14 +0000 | [diff] [blame] | 68 | ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)]; |
| 69 | g_ctx = new(placeholder_) SuppressionContext; |
Dmitry Vyukov | c2b9f1c | 2013-01-24 13:50:10 +0000 | [diff] [blame] | 70 | const char *supp = ReadFile(flags()->suppressions); |
Sergey Matveev | a52e5c6 | 2013-06-26 15:37:14 +0000 | [diff] [blame] | 71 | g_ctx->Parse(supp); |
Dmitry Vyukov | c2b9f1c | 2013-01-24 13:50:10 +0000 | [diff] [blame] | 72 | #ifndef TSAN_GO |
| 73 | supp = __tsan_default_suppressions(); |
Sergey Matveev | a52e5c6 | 2013-06-26 15:37:14 +0000 | [diff] [blame] | 74 | g_ctx->Parse(supp); |
Dmitry Vyukov | c2b9f1c | 2013-01-24 13:50:10 +0000 | [diff] [blame] | 75 | #endif |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 76 | } |
| 77 | |
Dmitry Vyukov | 3996833 | 2013-06-10 15:38:44 +0000 | [diff] [blame] | 78 | SuppressionType conv(ReportType typ) { |
| 79 | if (typ == ReportTypeRace) |
| 80 | return SuppressionRace; |
| 81 | else if (typ == ReportTypeVptrRace) |
| 82 | return SuppressionRace; |
| 83 | else if (typ == ReportTypeUseAfterFree) |
| 84 | return SuppressionNone; |
| 85 | else if (typ == ReportTypeThreadLeak) |
| 86 | return SuppressionThread; |
| 87 | else if (typ == ReportTypeMutexDestroyLocked) |
| 88 | return SuppressionMutex; |
| 89 | else if (typ == ReportTypeSignalUnsafe) |
| 90 | return SuppressionSignal; |
| 91 | else if (typ == ReportTypeErrnoInSignal) |
| 92 | return SuppressionNone; |
| 93 | Printf("ThreadSanitizer: unknown report type %d\n", typ), |
| 94 | Die(); |
| 95 | } |
| 96 | |
Dmitry Vyukov | f754eb5 | 2013-03-27 17:59:57 +0000 | [diff] [blame] | 97 | uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) { |
Sergey Matveev | a52e5c6 | 2013-06-26 15:37:14 +0000 | [diff] [blame] | 98 | CHECK(g_ctx); |
| 99 | if (!g_ctx->SuppressionCount() || stack == 0) return 0; |
Dmitry Vyukov | 3996833 | 2013-06-10 15:38:44 +0000 | [diff] [blame] | 100 | SuppressionType stype = conv(typ); |
| 101 | if (stype == SuppressionNone) |
Dmitry Vyukov | 24cdfee | 2013-05-29 11:23:54 +0000 | [diff] [blame] | 102 | return 0; |
Sergey Matveev | a52e5c6 | 2013-06-26 15:37:14 +0000 | [diff] [blame] | 103 | Suppression *s; |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 104 | for (const ReportStack *frame = stack; frame; frame = frame->next) { |
Sergey Matveev | a52e5c6 | 2013-06-26 15:37:14 +0000 | [diff] [blame] | 105 | if (g_ctx->Match(frame->func, stype, &s) || |
| 106 | g_ctx->Match(frame->file, stype, &s) || |
| 107 | g_ctx->Match(frame->module, stype, &s)) { |
| 108 | DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ); |
| 109 | s->hit_count++; |
| 110 | *sp = s; |
| 111 | return frame->pc; |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 112 | } |
| 113 | } |
Dmitry Vyukov | 158c6ac | 2012-10-05 15:51:32 +0000 | [diff] [blame] | 114 | return 0; |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 115 | } |
Dmitry Vyukov | f754eb5 | 2013-03-27 17:59:57 +0000 | [diff] [blame] | 116 | |
Dmitry Vyukov | 3996833 | 2013-06-10 15:38:44 +0000 | [diff] [blame] | 117 | uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) { |
Sergey Matveev | a52e5c6 | 2013-06-26 15:37:14 +0000 | [diff] [blame] | 118 | CHECK(g_ctx); |
| 119 | if (!g_ctx->SuppressionCount() || loc == 0 || |
| 120 | loc->type != ReportLocationGlobal) |
Dmitry Vyukov | 3996833 | 2013-06-10 15:38:44 +0000 | [diff] [blame] | 121 | return 0; |
| 122 | SuppressionType stype = conv(typ); |
| 123 | if (stype == SuppressionNone) |
| 124 | return 0; |
Sergey Matveev | a52e5c6 | 2013-06-26 15:37:14 +0000 | [diff] [blame] | 125 | Suppression *s; |
| 126 | if (g_ctx->Match(loc->name, stype, &s) || |
| 127 | g_ctx->Match(loc->file, stype, &s) || |
| 128 | g_ctx->Match(loc->module, stype, &s)) { |
Sergey Matveev | f2c8445 | 2013-06-26 16:49:34 +0000 | [diff] [blame] | 129 | DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ); |
Sergey Matveev | a52e5c6 | 2013-06-26 15:37:14 +0000 | [diff] [blame] | 130 | s->hit_count++; |
| 131 | *sp = s; |
Dmitry Vyukov | 3996833 | 2013-06-10 15:38:44 +0000 | [diff] [blame] | 132 | return loc->addr; |
Dmitry Vyukov | 3996833 | 2013-06-10 15:38:44 +0000 | [diff] [blame] | 133 | } |
| 134 | return 0; |
| 135 | } |
| 136 | |
Dmitry Vyukov | f754eb5 | 2013-03-27 17:59:57 +0000 | [diff] [blame] | 137 | void PrintMatchedSuppressions() { |
Sergey Matveev | a52e5c6 | 2013-06-26 15:37:14 +0000 | [diff] [blame] | 138 | CHECK(g_ctx); |
| 139 | InternalMmapVector<Suppression *> matched(1); |
| 140 | g_ctx->GetMatched(&matched); |
| 141 | if (!matched.size()) |
Dmitry Vyukov | f754eb5 | 2013-03-27 17:59:57 +0000 | [diff] [blame] | 142 | return; |
Sergey Matveev | a52e5c6 | 2013-06-26 15:37:14 +0000 | [diff] [blame] | 143 | int hit_count = 0; |
| 144 | for (uptr i = 0; i < matched.size(); i++) |
| 145 | hit_count += matched[i]->hit_count; |
| 146 | Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count, |
| 147 | (int)internal_getpid()); |
| 148 | for (uptr i = 0; i < matched.size(); i++) { |
| 149 | Printf("%d %s:%s\n", matched[i]->hit_count, |
| 150 | SuppressionTypeString(matched[i]->type), matched[i]->templ); |
Dmitry Vyukov | f754eb5 | 2013-03-27 17:59:57 +0000 | [diff] [blame] | 151 | } |
| 152 | } |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 153 | } // namespace __tsan |