xref: /freebsd/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
168d75effSDimitry Andric //===-- sanitizer_suppressions.cpp ----------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // Suppression parsing/matching code.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric //===----------------------------------------------------------------------===//
1268d75effSDimitry Andric 
1368d75effSDimitry Andric #include "sanitizer_suppressions.h"
1468d75effSDimitry Andric 
1568d75effSDimitry Andric #include "sanitizer_allocator_internal.h"
1668d75effSDimitry Andric #include "sanitizer_common.h"
1768d75effSDimitry Andric #include "sanitizer_flags.h"
1868d75effSDimitry Andric #include "sanitizer_file.h"
1968d75effSDimitry Andric #include "sanitizer_libc.h"
2068d75effSDimitry Andric #include "sanitizer_placement_new.h"
2168d75effSDimitry Andric 
2268d75effSDimitry Andric namespace __sanitizer {
2368d75effSDimitry Andric 
SuppressionContext(const char * suppression_types[],int suppression_types_num)2468d75effSDimitry Andric SuppressionContext::SuppressionContext(const char *suppression_types[],
2568d75effSDimitry Andric                                        int suppression_types_num)
2668d75effSDimitry Andric     : suppression_types_(suppression_types),
2768d75effSDimitry Andric       suppression_types_num_(suppression_types_num),
2868d75effSDimitry Andric       can_parse_(true) {
2968d75effSDimitry Andric   CHECK_LE(suppression_types_num_, kMaxSuppressionTypes);
3068d75effSDimitry Andric   internal_memset(has_suppression_type_, 0, suppression_types_num_);
3168d75effSDimitry Andric }
3268d75effSDimitry Andric 
3368d75effSDimitry Andric #if !SANITIZER_FUCHSIA
GetPathAssumingFileIsRelativeToExec(const char * file_path,char * new_file_path,uptr new_file_path_size)3468d75effSDimitry Andric static bool GetPathAssumingFileIsRelativeToExec(const char *file_path,
3568d75effSDimitry Andric                                                 /*out*/char *new_file_path,
3668d75effSDimitry Andric                                                 uptr new_file_path_size) {
37fe6060f1SDimitry Andric   InternalMmapVector<char> exec(kMaxPathLength);
3868d75effSDimitry Andric   if (ReadBinaryNameCached(exec.data(), exec.size())) {
3968d75effSDimitry Andric     const char *file_name_pos = StripModuleName(exec.data());
4068d75effSDimitry Andric     uptr path_to_exec_len = file_name_pos - exec.data();
4168d75effSDimitry Andric     internal_strncat(new_file_path, exec.data(),
4268d75effSDimitry Andric                      Min(path_to_exec_len, new_file_path_size - 1));
4368d75effSDimitry Andric     internal_strncat(new_file_path, file_path,
4468d75effSDimitry Andric                      new_file_path_size - internal_strlen(new_file_path) - 1);
4568d75effSDimitry Andric     return true;
4668d75effSDimitry Andric   }
4768d75effSDimitry Andric   return false;
4868d75effSDimitry Andric }
4968d75effSDimitry Andric 
FindFile(const char * file_path,char * new_file_path,uptr new_file_path_size)5068d75effSDimitry Andric static const char *FindFile(const char *file_path,
5168d75effSDimitry Andric                             /*out*/char *new_file_path,
5268d75effSDimitry Andric                             uptr new_file_path_size) {
5368d75effSDimitry Andric   // If we cannot find the file, check if its location is relative to
5468d75effSDimitry Andric   // the location of the executable.
5568d75effSDimitry Andric   if (!FileExists(file_path) && !IsAbsolutePath(file_path) &&
5668d75effSDimitry Andric       GetPathAssumingFileIsRelativeToExec(file_path, new_file_path,
5768d75effSDimitry Andric                                           new_file_path_size)) {
5868d75effSDimitry Andric     return new_file_path;
5968d75effSDimitry Andric   }
6068d75effSDimitry Andric   return file_path;
6168d75effSDimitry Andric }
6268d75effSDimitry Andric #else
FindFile(const char * file_path,char *,uptr)6368d75effSDimitry Andric static const char *FindFile(const char *file_path, char *, uptr) {
6468d75effSDimitry Andric   return file_path;
6568d75effSDimitry Andric }
6668d75effSDimitry Andric #endif
6768d75effSDimitry Andric 
ParseFromFile(const char * filename)6868d75effSDimitry Andric void SuppressionContext::ParseFromFile(const char *filename) {
6968d75effSDimitry Andric   if (filename[0] == '\0')
7068d75effSDimitry Andric     return;
7168d75effSDimitry Andric 
72fe6060f1SDimitry Andric   InternalMmapVector<char> new_file_path(kMaxPathLength);
7368d75effSDimitry Andric   filename = FindFile(filename, new_file_path.data(), new_file_path.size());
7468d75effSDimitry Andric 
7568d75effSDimitry Andric   // Read the file.
7668d75effSDimitry Andric   VPrintf(1, "%s: reading suppressions file at %s\n",
7768d75effSDimitry Andric           SanitizerToolName, filename);
7868d75effSDimitry Andric   char *file_contents;
7968d75effSDimitry Andric   uptr buffer_size;
8068d75effSDimitry Andric   uptr contents_size;
8168d75effSDimitry Andric   if (!ReadFileToBuffer(filename, &file_contents, &buffer_size,
8268d75effSDimitry Andric                         &contents_size)) {
8368d75effSDimitry Andric     Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
8468d75effSDimitry Andric            filename);
8568d75effSDimitry Andric     Die();
8668d75effSDimitry Andric   }
8768d75effSDimitry Andric 
8868d75effSDimitry Andric   Parse(file_contents);
89*0fca6ea1SDimitry Andric   UnmapOrDie(file_contents, buffer_size);
9068d75effSDimitry Andric }
9168d75effSDimitry Andric 
Match(const char * str,const char * type,Suppression ** s)9268d75effSDimitry Andric bool SuppressionContext::Match(const char *str, const char *type,
9368d75effSDimitry Andric                                Suppression **s) {
9468d75effSDimitry Andric   can_parse_ = false;
9568d75effSDimitry Andric   if (!HasSuppressionType(type))
9668d75effSDimitry Andric     return false;
9768d75effSDimitry Andric   for (uptr i = 0; i < suppressions_.size(); i++) {
9868d75effSDimitry Andric     Suppression &cur = suppressions_[i];
9968d75effSDimitry Andric     if (0 == internal_strcmp(cur.type, type) && TemplateMatch(cur.templ, str)) {
10068d75effSDimitry Andric       *s = &cur;
10168d75effSDimitry Andric       return true;
10268d75effSDimitry Andric     }
10368d75effSDimitry Andric   }
10468d75effSDimitry Andric   return false;
10568d75effSDimitry Andric }
10668d75effSDimitry Andric 
StripPrefix(const char * str,const char * prefix)10768d75effSDimitry Andric static const char *StripPrefix(const char *str, const char *prefix) {
10868d75effSDimitry Andric   while (*str && *str == *prefix) {
10968d75effSDimitry Andric     str++;
11068d75effSDimitry Andric     prefix++;
11168d75effSDimitry Andric   }
11268d75effSDimitry Andric   if (!*prefix)
11368d75effSDimitry Andric     return str;
11468d75effSDimitry Andric   return 0;
11568d75effSDimitry Andric }
11668d75effSDimitry Andric 
Parse(const char * str)11768d75effSDimitry Andric void SuppressionContext::Parse(const char *str) {
11868d75effSDimitry Andric   // Context must not mutate once Match has been called.
11968d75effSDimitry Andric   CHECK(can_parse_);
12068d75effSDimitry Andric   const char *line = str;
12168d75effSDimitry Andric   while (line) {
12268d75effSDimitry Andric     while (line[0] == ' ' || line[0] == '\t')
12368d75effSDimitry Andric       line++;
12468d75effSDimitry Andric     const char *end = internal_strchr(line, '\n');
12568d75effSDimitry Andric     if (end == 0)
12668d75effSDimitry Andric       end = line + internal_strlen(line);
12768d75effSDimitry Andric     if (line != end && line[0] != '#') {
12868d75effSDimitry Andric       const char *end2 = end;
12968d75effSDimitry Andric       while (line != end2 &&
13068d75effSDimitry Andric              (end2[-1] == ' ' || end2[-1] == '\t' || end2[-1] == '\r'))
13168d75effSDimitry Andric         end2--;
13268d75effSDimitry Andric       int type;
13368d75effSDimitry Andric       for (type = 0; type < suppression_types_num_; type++) {
13468d75effSDimitry Andric         const char *next_char = StripPrefix(line, suppression_types_[type]);
13568d75effSDimitry Andric         if (next_char && *next_char == ':') {
13668d75effSDimitry Andric           line = ++next_char;
13768d75effSDimitry Andric           break;
13868d75effSDimitry Andric         }
13968d75effSDimitry Andric       }
14068d75effSDimitry Andric       if (type == suppression_types_num_) {
141cb14a3feSDimitry Andric         Printf("%s: failed to parse suppressions.\n", SanitizerToolName);
142cb14a3feSDimitry Andric         Printf("Supported suppression types are:\n");
143cb14a3feSDimitry Andric         for (type = 0; type < suppression_types_num_; type++)
144cb14a3feSDimitry Andric           Printf("- %s\n", suppression_types_[type]);
14568d75effSDimitry Andric         Die();
14668d75effSDimitry Andric       }
14768d75effSDimitry Andric       Suppression s;
14868d75effSDimitry Andric       s.type = suppression_types_[type];
14968d75effSDimitry Andric       s.templ = (char*)InternalAlloc(end2 - line + 1);
15068d75effSDimitry Andric       internal_memcpy(s.templ, line, end2 - line);
15168d75effSDimitry Andric       s.templ[end2 - line] = 0;
15268d75effSDimitry Andric       suppressions_.push_back(s);
15368d75effSDimitry Andric       has_suppression_type_[type] = true;
15468d75effSDimitry Andric     }
15568d75effSDimitry Andric     if (end[0] == 0)
15668d75effSDimitry Andric       break;
15768d75effSDimitry Andric     line = end + 1;
15868d75effSDimitry Andric   }
15968d75effSDimitry Andric }
16068d75effSDimitry Andric 
SuppressionCount() const16168d75effSDimitry Andric uptr SuppressionContext::SuppressionCount() const {
16268d75effSDimitry Andric   return suppressions_.size();
16368d75effSDimitry Andric }
16468d75effSDimitry Andric 
HasSuppressionType(const char * type) const16568d75effSDimitry Andric bool SuppressionContext::HasSuppressionType(const char *type) const {
16668d75effSDimitry Andric   for (int i = 0; i < suppression_types_num_; i++) {
16768d75effSDimitry Andric     if (0 == internal_strcmp(type, suppression_types_[i]))
16868d75effSDimitry Andric       return has_suppression_type_[i];
16968d75effSDimitry Andric   }
17068d75effSDimitry Andric   return false;
17168d75effSDimitry Andric }
17268d75effSDimitry Andric 
SuppressionAt(uptr i) const17368d75effSDimitry Andric const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
17468d75effSDimitry Andric   CHECK_LT(i, suppressions_.size());
17568d75effSDimitry Andric   return &suppressions_[i];
17668d75effSDimitry Andric }
17768d75effSDimitry Andric 
GetMatched(InternalMmapVector<Suppression * > * matched)17868d75effSDimitry Andric void SuppressionContext::GetMatched(
17968d75effSDimitry Andric     InternalMmapVector<Suppression *> *matched) {
18068d75effSDimitry Andric   for (uptr i = 0; i < suppressions_.size(); i++)
18168d75effSDimitry Andric     if (atomic_load_relaxed(&suppressions_[i].hit_count))
18268d75effSDimitry Andric       matched->push_back(&suppressions_[i]);
18368d75effSDimitry Andric }
18468d75effSDimitry Andric 
18568d75effSDimitry Andric }  // namespace __sanitizer
186