tsan_suppressions.cpp revision 360784
1178825Sdfr//===-- tsan_suppressions.cpp ---------------------------------------------===//
2233294Sstas//
3233294Sstas// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4233294Sstas// See https://llvm.org/LICENSE.txt for license information.
5178825Sdfr// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6233294Sstas//
7233294Sstas//===----------------------------------------------------------------------===//
8233294Sstas//
9178825Sdfr// This file is a part of ThreadSanitizer (TSan), a race detector.
10233294Sstas//
11233294Sstas//===----------------------------------------------------------------------===//
12178825Sdfr
13233294Sstas#include "sanitizer_common/sanitizer_common.h"
14233294Sstas#include "sanitizer_common/sanitizer_libc.h"
15233294Sstas#include "sanitizer_common/sanitizer_placement_new.h"
16178825Sdfr#include "sanitizer_common/sanitizer_suppressions.h"
17233294Sstas#include "tsan_suppressions.h"
18233294Sstas#include "tsan_rtl.h"
19233294Sstas#include "tsan_flags.h"
20178825Sdfr#include "tsan_mman.h"
21233294Sstas#include "tsan_platform.h"
22233294Sstas
23233294Sstas#if !SANITIZER_GO
24233294Sstas// Suppressions for true/false positives in standard libraries.
25233294Sstasstatic const char *const std_suppressions =
26233294Sstas// Libstdc++ 4.4 has data races in std::string.
27233294Sstas// See http://crbug.com/181502 for an example.
28233294Sstas"race:^_M_rep$\n"
29233294Sstas"race:^_M_is_leaked$\n"
30233294Sstas// False positive when using std <thread>.
31233294Sstas// Happens because we miss atomic synchronization in libstdc++.
32178825Sdfr// See http://llvm.org/bugs/show_bug.cgi?id=17066 for details.
33178825Sdfr"race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n";
34233294Sstas
35178825Sdfr// Can be overriden in frontend.
36178825SdfrSANITIZER_WEAK_DEFAULT_IMPL
37178825Sdfrconst char *__tsan_default_suppressions() {
38178825Sdfr  return 0;
39178825Sdfr}
40178825Sdfr#endif
41178825Sdfr
42178825Sdfrnamespace __tsan {
43178825Sdfr
44178825SdfrALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
45178825Sdfrstatic SuppressionContext *suppression_ctx = nullptr;
46178825Sdfrstatic const char *kSuppressionTypes[] = {
47233294Sstas    kSuppressionRace,   kSuppressionRaceTop, kSuppressionMutex,
48178825Sdfr    kSuppressionThread, kSuppressionSignal, kSuppressionLib,
49178825Sdfr    kSuppressionDeadlock};
50178825Sdfr
51178825Sdfrvoid InitializeSuppressions() {
52178825Sdfr  CHECK_EQ(nullptr, suppression_ctx);
53178825Sdfr  suppression_ctx = new (suppression_placeholder)
54178825Sdfr      SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
55178825Sdfr  suppression_ctx->ParseFromFile(flags()->suppressions);
56178825Sdfr#if !SANITIZER_GO
57178825Sdfr  suppression_ctx->Parse(__tsan_default_suppressions());
58178825Sdfr  suppression_ctx->Parse(std_suppressions);
59178825Sdfr#endif
60178825Sdfr}
61178825Sdfr
62178825SdfrSuppressionContext *Suppressions() {
63178825Sdfr  CHECK(suppression_ctx);
64178825Sdfr  return suppression_ctx;
65178825Sdfr}
66178825Sdfr
67178825Sdfrstatic const char *conv(ReportType typ) {
68178825Sdfr  switch (typ) {
69178825Sdfr    case ReportTypeRace:
70178825Sdfr    case ReportTypeVptrRace:
71178825Sdfr    case ReportTypeUseAfterFree:
72178825Sdfr    case ReportTypeVptrUseAfterFree:
73178825Sdfr    case ReportTypeExternalRace:
74      return kSuppressionRace;
75    case ReportTypeThreadLeak:
76      return kSuppressionThread;
77    case ReportTypeMutexDestroyLocked:
78    case ReportTypeMutexDoubleLock:
79    case ReportTypeMutexInvalidAccess:
80    case ReportTypeMutexBadUnlock:
81    case ReportTypeMutexBadReadLock:
82    case ReportTypeMutexBadReadUnlock:
83      return kSuppressionMutex;
84    case ReportTypeSignalUnsafe:
85    case ReportTypeErrnoInSignal:
86      return kSuppressionSignal;
87    case ReportTypeDeadlock:
88      return kSuppressionDeadlock;
89    // No default case so compiler warns us if we miss one
90  }
91  UNREACHABLE("missing case");
92}
93
94static uptr IsSuppressed(const char *stype, const AddressInfo &info,
95    Suppression **sp) {
96  if (suppression_ctx->Match(info.function, stype, sp) ||
97      suppression_ctx->Match(info.file, stype, sp) ||
98      suppression_ctx->Match(info.module, stype, sp)) {
99    VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", (*sp)->templ);
100    atomic_fetch_add(&(*sp)->hit_count, 1, memory_order_relaxed);
101    return info.address;
102  }
103  return 0;
104}
105
106uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
107  CHECK(suppression_ctx);
108  if (!suppression_ctx->SuppressionCount() || stack == 0 ||
109      !stack->suppressable)
110    return 0;
111  const char *stype = conv(typ);
112  if (0 == internal_strcmp(stype, kSuppressionNone))
113    return 0;
114  for (const SymbolizedStack *frame = stack->frames; frame;
115      frame = frame->next) {
116    uptr pc = IsSuppressed(stype, frame->info, sp);
117    if (pc != 0)
118      return pc;
119  }
120  if (0 == internal_strcmp(stype, kSuppressionRace) && stack->frames != nullptr)
121    return IsSuppressed(kSuppressionRaceTop, stack->frames->info, sp);
122  return 0;
123}
124
125uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
126  CHECK(suppression_ctx);
127  if (!suppression_ctx->SuppressionCount() || loc == 0 ||
128      loc->type != ReportLocationGlobal || !loc->suppressable)
129    return 0;
130  const char *stype = conv(typ);
131  if (0 == internal_strcmp(stype, kSuppressionNone))
132    return 0;
133  Suppression *s;
134  const DataInfo &global = loc->global;
135  if (suppression_ctx->Match(global.name, stype, &s) ||
136      suppression_ctx->Match(global.module, stype, &s)) {
137      VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", s->templ);
138      atomic_fetch_add(&s->hit_count, 1, memory_order_relaxed);
139      *sp = s;
140      return global.start;
141  }
142  return 0;
143}
144
145void PrintMatchedSuppressions() {
146  InternalMmapVector<Suppression *> matched;
147  CHECK(suppression_ctx);
148  suppression_ctx->GetMatched(&matched);
149  if (!matched.size())
150    return;
151  int hit_count = 0;
152  for (uptr i = 0; i < matched.size(); i++)
153    hit_count += atomic_load_relaxed(&matched[i]->hit_count);
154  Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count,
155         (int)internal_getpid());
156  for (uptr i = 0; i < matched.size(); i++) {
157    Printf("%d %s:%s\n", atomic_load_relaxed(&matched[i]->hit_count),
158           matched[i]->type, matched[i]->templ);
159  }
160}
161}  // namespace __tsan
162