aboutsummaryrefslogtreecommitdiff
path: root/lib/tsan/rtl/tsan_suppressions.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tsan/rtl/tsan_suppressions.cc')
-rw-r--r--lib/tsan/rtl/tsan_suppressions.cc163
1 files changed, 163 insertions, 0 deletions
diff --git a/lib/tsan/rtl/tsan_suppressions.cc b/lib/tsan/rtl/tsan_suppressions.cc
new file mode 100644
index 000000000000..7549a4f8ba83
--- /dev/null
+++ b/lib/tsan/rtl/tsan_suppressions.cc
@@ -0,0 +1,163 @@
+//===-- tsan_suppressions.cc ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "tsan_suppressions.h"
+#include "tsan_rtl.h"
+#include "tsan_flags.h"
+#include "tsan_mman.h"
+#include "tsan_platform.h"
+
+namespace __tsan {
+
+static Suppression *g_suppressions;
+
+static char *ReadFile(const char *filename) {
+ if (filename == 0 || filename[0] == 0)
+ return 0;
+ InternalScopedBuf<char> tmp(4*1024);
+ if (filename[0] == '/')
+ internal_snprintf(tmp, tmp.Size(), "%s", filename);
+ else
+ internal_snprintf(tmp, tmp.Size(), "%s/%s", GetPwd(), filename);
+ fd_t fd = internal_open(tmp, false);
+ if (fd == kInvalidFd) {
+ TsanPrintf("ThreadSanitizer: failed to open suppressions file '%s'\n",
+ tmp.Ptr());
+ Die();
+ }
+ const uptr fsize = internal_filesize(fd);
+ if (fsize == (uptr)-1) {
+ TsanPrintf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
+ tmp.Ptr());
+ Die();
+ }
+ char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
+ if (fsize != internal_read(fd, buf, fsize)) {
+ TsanPrintf("ThreadSanitizer: failed to read suppressions file '%s'\n",
+ tmp.Ptr());
+ Die();
+ }
+ internal_close(fd);
+ buf[fsize] = 0;
+ return buf;
+}
+
+bool SuppressionMatch(char *templ, const char *str) {
+ if (str == 0 || str[0] == 0)
+ return false;
+ char *tpos;
+ const char *spos;
+ while (templ && templ[0]) {
+ if (templ[0] == '*') {
+ templ++;
+ continue;
+ }
+ if (str[0] == 0)
+ return false;
+ tpos = (char*)internal_strchr(templ, '*');
+ if (tpos != 0)
+ tpos[0] = 0;
+ spos = internal_strstr(str, templ);
+ str = spos + internal_strlen(templ);
+ templ = tpos;
+ if (tpos)
+ tpos[0] = '*';
+ if (spos == 0)
+ return false;
+ }
+ return true;
+}
+
+Suppression *SuppressionParse(const char* supp) {
+ Suppression *head = 0;
+ const char *line = supp;
+ while (line) {
+ while (line[0] == ' ' || line[0] == '\t')
+ line++;
+ const char *end = internal_strchr(line, '\n');
+ if (end == 0)
+ end = line + internal_strlen(line);
+ if (line != end && line[0] != '#') {
+ const char *end2 = end;
+ while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
+ end2--;
+ SuppressionType stype;
+ if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) {
+ stype = SuppressionRace;
+ line += sizeof("race:") - 1;
+ } else if (0 == internal_strncmp(line, "thread:",
+ sizeof("thread:") - 1)) {
+ stype = SuppressionThread;
+ line += sizeof("thread:") - 1;
+ } else if (0 == internal_strncmp(line, "mutex:",
+ sizeof("mutex:") - 1)) {
+ stype = SuppressionMutex;
+ line += sizeof("mutex:") - 1;
+ } else if (0 == internal_strncmp(line, "signal:",
+ sizeof("signal:") - 1)) {
+ stype = SuppressionSignal;
+ line += sizeof("signal:") - 1;
+ } else {
+ TsanPrintf("ThreadSanitizer: failed to parse suppressions file\n");
+ Die();
+ }
+ Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
+ sizeof(Suppression));
+ s->next = head;
+ head = s;
+ s->type = stype;
+ s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
+ internal_memcpy(s->templ, line, end2 - line);
+ s->templ[end2 - line] = 0;
+ }
+ if (end[0] == 0)
+ break;
+ line = end + 1;
+ }
+ return head;
+}
+
+void InitializeSuppressions() {
+ char *supp = ReadFile(flags()->suppressions);
+ g_suppressions = SuppressionParse(supp);
+}
+
+bool IsSuppressed(ReportType typ, const ReportStack *stack) {
+ if (g_suppressions == 0 || stack == 0)
+ return false;
+ SuppressionType stype;
+ if (typ == ReportTypeRace)
+ stype = SuppressionRace;
+ else if (typ == ReportTypeThreadLeak)
+ stype = SuppressionThread;
+ else if (typ == ReportTypeMutexDestroyLocked)
+ stype = SuppressionMutex;
+ else if (typ == ReportTypeSignalUnsafe)
+ stype = SuppressionSignal;
+ else
+ return false;
+ for (const ReportStack *frame = stack; frame; frame = frame->next) {
+ for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
+ if (stype == supp->type &&
+ (SuppressionMatch(supp->templ, frame->func) ||
+ SuppressionMatch(supp->templ, frame->file))) {
+ DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+} // namespace __tsan