tsan_suppressions.cc revision ee7cc4454421a176d23442382afd9a01d36e7ad4
1793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//===-- tsan_suppressions.cc ----------------------------------------------===// 2793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// 3793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// The LLVM Compiler Infrastructure 4793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// 5793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// This file is distributed under the University of Illinois Open Source 6793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// License. See LICENSE.TXT for details. 7793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// 8793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//===----------------------------------------------------------------------===// 9793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// 10793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// This file is a part of ThreadSanitizer (TSan), a race detector. 11793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// 12793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//===----------------------------------------------------------------------===// 13793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 14793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "sanitizer_common/sanitizer_common.h" 15793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "sanitizer_common/sanitizer_libc.h" 16793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "tsan_suppressions.h" 17793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "tsan_rtl.h" 18793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "tsan_flags.h" 19793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "tsan_mman.h" 20793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "tsan_platform.h" 21793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 22793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Can be overriden in frontend. 23793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifndef TSAN_GO 24793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerextern "C" const char *WEAK __tsan_default_suppressions() { 25793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; 26793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 27793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif 28793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 29793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslernamespace __tsan { 30793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 31793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic Suppression *g_suppressions; 32793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 33793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic char *ReadFile(const char *filename) { 34793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (filename == 0 || filename[0] == 0) 35793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; 36793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler InternalScopedBuffer<char> tmp(4*1024); 37793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (filename[0] == '/' || GetPwd() == 0) 38793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler internal_snprintf(tmp.data(), tmp.size(), "%s", filename); 39793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler else 40793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename); 41793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler fd_t fd = OpenFile(tmp.data(), false); 42793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (fd == kInvalidFd) { 43793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler Printf("ThreadSanitizer: failed to open suppressions file '%s'\n", 44793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tmp.data()); 45793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler Die(); 46793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 47793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const uptr fsize = internal_filesize(fd); 48793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (fsize == (uptr)-1) { 49793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n", 50793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tmp.data()); 51793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler Die(); 52793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 53793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1); 54793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (fsize != internal_read(fd, buf, fsize)) { 55793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler Printf("ThreadSanitizer: failed to read suppressions file '%s'\n", 56793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tmp.data()); 57793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler Die(); 58793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 59793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler internal_close(fd); 60793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler buf[fsize] = 0; 61793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return buf; 62793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 63793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 64793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerbool SuppressionMatch(char *templ, const char *str) { 65793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (str == 0 || str[0] == 0) 66793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return false; 67793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler char *tpos; 68793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const char *spos; 69793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler while (templ && templ[0]) { 70793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (templ[0] == '*') { 71793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler templ++; 72793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler continue; 73793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 74793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (str[0] == 0) 75793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return false; 76793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tpos = (char*)internal_strchr(templ, '*'); 77793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (tpos != 0) 78793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tpos[0] = 0; 79793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler spos = internal_strstr(str, templ); 80793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler str = spos + internal_strlen(templ); 81793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler templ = tpos; 82793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (tpos) 83793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler tpos[0] = '*'; 84793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (spos == 0) 85793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return false; 86793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 87793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return true; 88793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 89793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 90793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerSuppression *SuppressionParse(Suppression *head, const char* supp) { 91793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const char *line = supp; 92793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler while (line) { 93793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler while (line[0] == ' ' || line[0] == '\t') 94793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler line++; 95793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const char *end = internal_strchr(line, '\n'); 96793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (end == 0) 97793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler end = line + internal_strlen(line); 98793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (line != end && line[0] != '#') { 99793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const char *end2 = end; 100793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t')) 101793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler end2--; 102793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler SuppressionType stype; 103793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) { 104793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler stype = SuppressionRace; 105793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler line += sizeof("race:") - 1; 106793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } else if (0 == internal_strncmp(line, "thread:", 107793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler sizeof("thread:") - 1)) { 108793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler stype = SuppressionThread; 109793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler line += sizeof("thread:") - 1; 110793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } else if (0 == internal_strncmp(line, "mutex:", 111793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler sizeof("mutex:") - 1)) { 112793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler stype = SuppressionMutex; 113793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler line += sizeof("mutex:") - 1; 114793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } else if (0 == internal_strncmp(line, "signal:", 115793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler sizeof("signal:") - 1)) { 116793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler stype = SuppressionSignal; 117793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler line += sizeof("signal:") - 1; 118793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } else { 119793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler Printf("ThreadSanitizer: failed to parse suppressions file\n"); 120793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler Die(); 121793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 122793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler Suppression *s = (Suppression*)internal_alloc(MBlockSuppression, 123793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler sizeof(Suppression)); 124793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler s->next = head; 125793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler head = s; 126793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler s->type = stype; 127793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1); 128793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler internal_memcpy(s->templ, line, end2 - line); 129793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler s->templ[end2 - line] = 0; 130793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 131793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (end[0] == 0) 132793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler break; 133793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler line = end + 1; 134793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 135793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return head; 136793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 137793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 138793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslervoid InitializeSuppressions() { 139793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const char *supp = ReadFile(flags()->suppressions); 140793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler g_suppressions = SuppressionParse(0, supp); 141793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifndef TSAN_GO 142793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler supp = __tsan_default_suppressions(); 143793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler g_suppressions = SuppressionParse(0, supp); 144793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif 145793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 146793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 147793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presleruptr IsSuppressed(ReportType typ, const ReportStack *stack) { 148793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (g_suppressions == 0 || stack == 0) 149793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; 150793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler SuppressionType stype; 151793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (typ == ReportTypeRace) 152793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler stype = SuppressionRace; 153793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler else if (typ == ReportTypeThreadLeak) 154793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler stype = SuppressionThread; 155793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler else if (typ == ReportTypeMutexDestroyLocked) 156793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler stype = SuppressionMutex; 157793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler else if (typ == ReportTypeSignalUnsafe) 158793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler stype = SuppressionSignal; 159793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler else 160793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; 161793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (const ReportStack *frame = stack; frame; frame = frame->next) { 162793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (Suppression *supp = g_suppressions; supp; supp = supp->next) { 163793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (stype == supp->type && 164793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler (SuppressionMatch(supp->templ, frame->func) || 165793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler SuppressionMatch(supp->templ, frame->file) || 166793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler SuppressionMatch(supp->templ, frame->module))) { 167793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ); 168793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return frame->pc; 169793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 170793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 171793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 172793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return 0; 173793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 174793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} // namespace __tsan 175793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler