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