1603c4be006d8c53905d736bf1f19a49f5ce98276Alexey Samsonov//===-- tsan_suppressions.cc ----------------------------------------------===//
27ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
37ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//                     The LLVM Compiler Infrastructure
47ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
57ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is distributed under the University of Illinois Open Source
67ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// License. See LICENSE.TXT for details.
77ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
87ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===//
97ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is a part of ThreadSanitizer (TSan), a race detector.
117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===//
137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
140969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov#include "sanitizer_common/sanitizer_common.h"
157f9c5a220b2768a450696bbd157a0e6f2e9ceea3Alexey Samsonov#include "sanitizer_common/sanitizer_libc.h"
167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_suppressions.h"
177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_rtl.h"
187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_flags.h"
197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_mman.h"
207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_platform.h"
217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
22c2b9f1c1d54e857e56462e65155381faddf398dfDmitry Vyukov// Can be overriden in frontend.
23c2b9f1c1d54e857e56462e65155381faddf398dfDmitry Vyukov#ifndef TSAN_GO
24c2b9f1c1d54e857e56462e65155381faddf398dfDmitry Vyukovextern "C" const char *WEAK __tsan_default_suppressions() {
25c2b9f1c1d54e857e56462e65155381faddf398dfDmitry Vyukov  return 0;
26c2b9f1c1d54e857e56462e65155381faddf398dfDmitry Vyukov}
27c2b9f1c1d54e857e56462e65155381faddf398dfDmitry Vyukov#endif
28c2b9f1c1d54e857e56462e65155381faddf398dfDmitry Vyukov
297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanynamespace __tsan {
307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic Suppression *g_suppressions;
327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic char *ReadFile(const char *filename) {
347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (filename == 0 || filename[0] == 0)
357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return 0;
3614c8bd7250742749e44e306c02a56cf47ad1db82Alexey Samsonov  InternalScopedBuffer<char> tmp(4*1024);
376422c32996ec2d65b2ebc77dda36b613dbd1571aDmitry Vyukov  if (filename[0] == '/' || GetPwd() == 0)
381dc4cf7e253aefa3ce3bd4a1d349a13647e8b2eaAlexey Samsonov    internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  else
401dc4cf7e253aefa3ce3bd4a1d349a13647e8b2eaAlexey Samsonov    internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
41ee7cc4454421a176d23442382afd9a01d36e7ad4Alexey Samsonov  fd_t fd = OpenFile(tmp.data(), false);
427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (fd == kInvalidFd) {
43b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
4414c8bd7250742749e44e306c02a56cf47ad1db82Alexey Samsonov               tmp.data());
457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    Die();
467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  const uptr fsize = internal_filesize(fd);
487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (fsize == (uptr)-1) {
49b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
5014c8bd7250742749e44e306c02a56cf47ad1db82Alexey Samsonov               tmp.data());
517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    Die();
527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (fsize != internal_read(fd, buf, fsize)) {
55b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
5614c8bd7250742749e44e306c02a56cf47ad1db82Alexey Samsonov               tmp.data());
577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    Die();
587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  internal_close(fd);
607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  buf[fsize] = 0;
617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return buf;
627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanybool SuppressionMatch(char *templ, const char *str) {
6520f60c53c446f42af2b4ebc3b85f6a5042be6904Dmitry Vyukov  if (str == 0 || str[0] == 0)
6620f60c53c446f42af2b4ebc3b85f6a5042be6904Dmitry Vyukov    return false;
677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  char *tpos;
687ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  const char *spos;
697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  while (templ && templ[0]) {
707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (templ[0] == '*') {
717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      templ++;
727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      continue;
737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (str[0] == 0)
757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      return false;
767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    tpos = (char*)internal_strchr(templ, '*');
777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (tpos != 0)
787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      tpos[0] = 0;
79d51a1a10cba87be50e9ada9fa21337c387edb237Dmitry Vyukov    spos = internal_strstr(str, templ);
807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    str = spos + internal_strlen(templ);
817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    templ = tpos;
827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (tpos)
837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      tpos[0] = '*';
847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (spos == 0)
857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      return false;
867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return true;
887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
90c2b9f1c1d54e857e56462e65155381faddf398dfDmitry VyukovSuppression *SuppressionParse(Suppression *head, const char* supp) {
917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  const char *line = supp;
927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  while (line) {
937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    while (line[0] == ' ' || line[0] == '\t')
947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      line++;
957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    const char *end = internal_strchr(line, '\n');
967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (end == 0)
977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      end = line + internal_strlen(line);
987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (line != end && line[0] != '#') {
997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      const char *end2 = end;
1007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
1017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        end2--;
1027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      SuppressionType stype;
103d51a1a10cba87be50e9ada9fa21337c387edb237Dmitry Vyukov      if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) {
1047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        stype = SuppressionRace;
1057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        line += sizeof("race:") - 1;
106d51a1a10cba87be50e9ada9fa21337c387edb237Dmitry Vyukov      } else if (0 == internal_strncmp(line, "thread:",
1077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany          sizeof("thread:") - 1)) {
1087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        stype = SuppressionThread;
1097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        line += sizeof("thread:") - 1;
110d51a1a10cba87be50e9ada9fa21337c387edb237Dmitry Vyukov      } else if (0 == internal_strncmp(line, "mutex:",
1117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany          sizeof("mutex:") - 1)) {
1127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        stype = SuppressionMutex;
1137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        line += sizeof("mutex:") - 1;
114d51a1a10cba87be50e9ada9fa21337c387edb237Dmitry Vyukov      } else if (0 == internal_strncmp(line, "signal:",
1157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany          sizeof("signal:") - 1)) {
1167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        stype = SuppressionSignal;
1177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        line += sizeof("signal:") - 1;
1187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      } else {
119b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov        Printf("ThreadSanitizer: failed to parse suppressions file\n");
1207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        Die();
1217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      }
1227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
1237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany          sizeof(Suppression));
1247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      s->next = head;
1257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      head = s;
1267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      s->type = stype;
12720f60c53c446f42af2b4ebc3b85f6a5042be6904Dmitry Vyukov      s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
128d51a1a10cba87be50e9ada9fa21337c387edb237Dmitry Vyukov      internal_memcpy(s->templ, line, end2 - line);
12920f60c53c446f42af2b4ebc3b85f6a5042be6904Dmitry Vyukov      s->templ[end2 - line] = 0;
1307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
1317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (end[0] == 0)
1327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      break;
1337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    line = end + 1;
1347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
1357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return head;
1367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid InitializeSuppressions() {
139c2b9f1c1d54e857e56462e65155381faddf398dfDmitry Vyukov  const char *supp = ReadFile(flags()->suppressions);
140c2b9f1c1d54e857e56462e65155381faddf398dfDmitry Vyukov  g_suppressions = SuppressionParse(0, supp);
141c2b9f1c1d54e857e56462e65155381faddf398dfDmitry Vyukov#ifndef TSAN_GO
142c2b9f1c1d54e857e56462e65155381faddf398dfDmitry Vyukov  supp = __tsan_default_suppressions();
14315190a6f0f086737f2fcffe16a58ed42939ef081Dmitry Vyukov  g_suppressions = SuppressionParse(g_suppressions, supp);
144c2b9f1c1d54e857e56462e65155381faddf398dfDmitry Vyukov#endif
1457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
147158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukovuptr IsSuppressed(ReportType typ, const ReportStack *stack) {
1487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (g_suppressions == 0 || stack == 0)
149158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    return 0;
1507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  SuppressionType stype;
1517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (typ == ReportTypeRace)
1527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    stype = SuppressionRace;
1537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  else if (typ == ReportTypeThreadLeak)
1547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    stype = SuppressionThread;
1557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  else if (typ == ReportTypeMutexDestroyLocked)
1567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    stype = SuppressionMutex;
1577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  else if (typ == ReportTypeSignalUnsafe)
1587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    stype = SuppressionSignal;
1597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  else
160158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    return 0;
1617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (const ReportStack *frame = stack; frame; frame = frame->next) {
1627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
163a13749bd7b3629a3498e765960729a8ade5db7cfDmitry Vyukov      if (stype == supp->type &&
164a13749bd7b3629a3498e765960729a8ade5db7cfDmitry Vyukov          (SuppressionMatch(supp->templ, frame->func) ||
165c2b9f1c1d54e857e56462e65155381faddf398dfDmitry Vyukov           SuppressionMatch(supp->templ, frame->file) ||
166c2b9f1c1d54e857e56462e65155381faddf398dfDmitry Vyukov           SuppressionMatch(supp->templ, frame->module))) {
16720f60c53c446f42af2b4ebc3b85f6a5042be6904Dmitry Vyukov        DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
168158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov        return frame->pc;
1697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      }
1707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
1717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
172158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  return 0;
1737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}  // namespace __tsan
175