• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- sanitizer_suppressions.cc -----------------------------------------===//
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 // Suppression parsing/matching code.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "sanitizer_suppressions.h"
15 
16 #include "sanitizer_allocator_internal.h"
17 #include "sanitizer_common.h"
18 #include "sanitizer_flags.h"
19 #include "sanitizer_libc.h"
20 #include "sanitizer_placement_new.h"
21 
22 namespace __sanitizer {
23 
SuppressionContext(const char * suppression_types[],int suppression_types_num)24 SuppressionContext::SuppressionContext(const char *suppression_types[],
25                                        int suppression_types_num)
26     : suppression_types_(suppression_types),
27       suppression_types_num_(suppression_types_num), suppressions_(1),
28       can_parse_(true) {
29   CHECK_LE(suppression_types_num_, kMaxSuppressionTypes);
30   internal_memset(has_suppression_type_, 0, suppression_types_num_);
31 }
32 
GetPathAssumingFileIsRelativeToExec(const char * file_path,char * new_file_path,uptr new_file_path_size)33 static bool GetPathAssumingFileIsRelativeToExec(const char *file_path,
34                                                 /*out*/char *new_file_path,
35                                                 uptr new_file_path_size) {
36   InternalScopedString exec(kMaxPathLength);
37   if (ReadBinaryNameCached(exec.data(), exec.size())) {
38     const char *file_name_pos = StripModuleName(exec.data());
39     uptr path_to_exec_len = file_name_pos - exec.data();
40     internal_strncat(new_file_path, exec.data(),
41                      Min(path_to_exec_len, new_file_path_size - 1));
42     internal_strncat(new_file_path, file_path,
43                      new_file_path_size - internal_strlen(new_file_path) - 1);
44     return true;
45   }
46   return false;
47 }
48 
ParseFromFile(const char * filename)49 void SuppressionContext::ParseFromFile(const char *filename) {
50   if (filename[0] == '\0')
51     return;
52 
53   // If we cannot find the file, check if its location is relative to
54   // the location of the executable.
55   InternalScopedString new_file_path(kMaxPathLength);
56   if (!FileExists(filename) && !IsAbsolutePath(filename) &&
57       GetPathAssumingFileIsRelativeToExec(filename, new_file_path.data(),
58                                           new_file_path.size())) {
59     filename = new_file_path.data();
60   }
61 
62   // Read the file.
63   VPrintf(1, "%s: reading suppressions file at %s\n",
64           SanitizerToolName, filename);
65   char *file_contents;
66   uptr buffer_size;
67   uptr contents_size;
68   if (!ReadFileToBuffer(filename, &file_contents, &buffer_size,
69                         &contents_size)) {
70     Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
71            filename);
72     Die();
73   }
74 
75   Parse(file_contents);
76 }
77 
Match(const char * str,const char * type,Suppression ** s)78 bool SuppressionContext::Match(const char *str, const char *type,
79                                Suppression **s) {
80   can_parse_ = false;
81   if (!HasSuppressionType(type))
82     return false;
83   for (uptr i = 0; i < suppressions_.size(); i++) {
84     Suppression &cur = suppressions_[i];
85     if (0 == internal_strcmp(cur.type, type) && TemplateMatch(cur.templ, str)) {
86       *s = &cur;
87       return true;
88     }
89   }
90   return false;
91 }
92 
StripPrefix(const char * str,const char * prefix)93 static const char *StripPrefix(const char *str, const char *prefix) {
94   while (str && *str == *prefix) {
95     str++;
96     prefix++;
97   }
98   if (!*prefix)
99     return str;
100   return 0;
101 }
102 
Parse(const char * str)103 void SuppressionContext::Parse(const char *str) {
104   // Context must not mutate once Match has been called.
105   CHECK(can_parse_);
106   const char *line = str;
107   while (line) {
108     while (line[0] == ' ' || line[0] == '\t')
109       line++;
110     const char *end = internal_strchr(line, '\n');
111     if (end == 0)
112       end = line + internal_strlen(line);
113     if (line != end && line[0] != '#') {
114       const char *end2 = end;
115       while (line != end2 &&
116              (end2[-1] == ' ' || end2[-1] == '\t' || end2[-1] == '\r'))
117         end2--;
118       int type;
119       for (type = 0; type < suppression_types_num_; type++) {
120         const char *next_char = StripPrefix(line, suppression_types_[type]);
121         if (next_char && *next_char == ':') {
122           line = ++next_char;
123           break;
124         }
125       }
126       if (type == suppression_types_num_) {
127         Printf("%s: failed to parse suppressions\n", SanitizerToolName);
128         Die();
129       }
130       Suppression s;
131       s.type = suppression_types_[type];
132       s.templ = (char*)InternalAlloc(end2 - line + 1);
133       internal_memcpy(s.templ, line, end2 - line);
134       s.templ[end2 - line] = 0;
135       suppressions_.push_back(s);
136       has_suppression_type_[type] = true;
137     }
138     if (end[0] == 0)
139       break;
140     line = end + 1;
141   }
142 }
143 
SuppressionCount() const144 uptr SuppressionContext::SuppressionCount() const {
145   return suppressions_.size();
146 }
147 
HasSuppressionType(const char * type) const148 bool SuppressionContext::HasSuppressionType(const char *type) const {
149   for (int i = 0; i < suppression_types_num_; i++) {
150     if (0 == internal_strcmp(type, suppression_types_[i]))
151       return has_suppression_type_[i];
152   }
153   return false;
154 }
155 
SuppressionAt(uptr i) const156 const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
157   CHECK_LT(i, suppressions_.size());
158   return &suppressions_[i];
159 }
160 
GetMatched(InternalMmapVector<Suppression * > * matched)161 void SuppressionContext::GetMatched(
162     InternalMmapVector<Suppression *> *matched) {
163   for (uptr i = 0; i < suppressions_.size(); i++)
164     if (atomic_load_relaxed(&suppressions_[i].hit_count))
165       matched->push_back(&suppressions_[i]);
166 }
167 
168 }  // namespace __sanitizer
169