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