1353944Sdim//===-- sanitizer_suppressions.cpp ----------------------------------------===// 2353944Sdim// 3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353944Sdim// See https://llvm.org/LICENSE.txt for license information. 5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353944Sdim// 7353944Sdim//===----------------------------------------------------------------------===// 8353944Sdim// 9353944Sdim// Suppression parsing/matching code. 10353944Sdim// 11353944Sdim//===----------------------------------------------------------------------===// 12353944Sdim 13353944Sdim#include "sanitizer_suppressions.h" 14353944Sdim 15353944Sdim#include "sanitizer_allocator_internal.h" 16353944Sdim#include "sanitizer_common.h" 17353944Sdim#include "sanitizer_flags.h" 18353944Sdim#include "sanitizer_file.h" 19353944Sdim#include "sanitizer_libc.h" 20353944Sdim#include "sanitizer_placement_new.h" 21353944Sdim 22353944Sdimnamespace __sanitizer { 23353944Sdim 24353944SdimSuppressionContext::SuppressionContext(const char *suppression_types[], 25353944Sdim int suppression_types_num) 26353944Sdim : suppression_types_(suppression_types), 27353944Sdim suppression_types_num_(suppression_types_num), 28353944Sdim can_parse_(true) { 29353944Sdim CHECK_LE(suppression_types_num_, kMaxSuppressionTypes); 30353944Sdim internal_memset(has_suppression_type_, 0, suppression_types_num_); 31353944Sdim} 32353944Sdim 33353944Sdim#if !SANITIZER_FUCHSIA 34353944Sdimstatic bool GetPathAssumingFileIsRelativeToExec(const char *file_path, 35353944Sdim /*out*/char *new_file_path, 36353944Sdim uptr new_file_path_size) { 37353944Sdim InternalScopedString exec(kMaxPathLength); 38353944Sdim if (ReadBinaryNameCached(exec.data(), exec.size())) { 39353944Sdim const char *file_name_pos = StripModuleName(exec.data()); 40353944Sdim uptr path_to_exec_len = file_name_pos - exec.data(); 41353944Sdim internal_strncat(new_file_path, exec.data(), 42353944Sdim Min(path_to_exec_len, new_file_path_size - 1)); 43353944Sdim internal_strncat(new_file_path, file_path, 44353944Sdim new_file_path_size - internal_strlen(new_file_path) - 1); 45353944Sdim return true; 46353944Sdim } 47353944Sdim return false; 48353944Sdim} 49353944Sdim 50353944Sdimstatic const char *FindFile(const char *file_path, 51353944Sdim /*out*/char *new_file_path, 52353944Sdim uptr new_file_path_size) { 53353944Sdim // If we cannot find the file, check if its location is relative to 54353944Sdim // the location of the executable. 55353944Sdim if (!FileExists(file_path) && !IsAbsolutePath(file_path) && 56353944Sdim GetPathAssumingFileIsRelativeToExec(file_path, new_file_path, 57353944Sdim new_file_path_size)) { 58353944Sdim return new_file_path; 59353944Sdim } 60353944Sdim return file_path; 61353944Sdim} 62353944Sdim#else 63353944Sdimstatic const char *FindFile(const char *file_path, char *, uptr) { 64353944Sdim return file_path; 65353944Sdim} 66353944Sdim#endif 67353944Sdim 68353944Sdimvoid SuppressionContext::ParseFromFile(const char *filename) { 69353944Sdim if (filename[0] == '\0') 70353944Sdim return; 71353944Sdim 72353944Sdim InternalScopedString new_file_path(kMaxPathLength); 73353944Sdim filename = FindFile(filename, new_file_path.data(), new_file_path.size()); 74353944Sdim 75353944Sdim // Read the file. 76353944Sdim VPrintf(1, "%s: reading suppressions file at %s\n", 77353944Sdim SanitizerToolName, filename); 78353944Sdim char *file_contents; 79353944Sdim uptr buffer_size; 80353944Sdim uptr contents_size; 81353944Sdim if (!ReadFileToBuffer(filename, &file_contents, &buffer_size, 82353944Sdim &contents_size)) { 83353944Sdim Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName, 84353944Sdim filename); 85353944Sdim Die(); 86353944Sdim } 87353944Sdim 88353944Sdim Parse(file_contents); 89353944Sdim} 90353944Sdim 91353944Sdimbool SuppressionContext::Match(const char *str, const char *type, 92353944Sdim Suppression **s) { 93353944Sdim can_parse_ = false; 94353944Sdim if (!HasSuppressionType(type)) 95353944Sdim return false; 96353944Sdim for (uptr i = 0; i < suppressions_.size(); i++) { 97353944Sdim Suppression &cur = suppressions_[i]; 98353944Sdim if (0 == internal_strcmp(cur.type, type) && TemplateMatch(cur.templ, str)) { 99353944Sdim *s = &cur; 100353944Sdim return true; 101353944Sdim } 102353944Sdim } 103353944Sdim return false; 104353944Sdim} 105353944Sdim 106353944Sdimstatic const char *StripPrefix(const char *str, const char *prefix) { 107353944Sdim while (*str && *str == *prefix) { 108353944Sdim str++; 109353944Sdim prefix++; 110353944Sdim } 111353944Sdim if (!*prefix) 112353944Sdim return str; 113353944Sdim return 0; 114353944Sdim} 115353944Sdim 116353944Sdimvoid SuppressionContext::Parse(const char *str) { 117353944Sdim // Context must not mutate once Match has been called. 118353944Sdim CHECK(can_parse_); 119353944Sdim const char *line = str; 120353944Sdim while (line) { 121353944Sdim while (line[0] == ' ' || line[0] == '\t') 122353944Sdim line++; 123353944Sdim const char *end = internal_strchr(line, '\n'); 124353944Sdim if (end == 0) 125353944Sdim end = line + internal_strlen(line); 126353944Sdim if (line != end && line[0] != '#') { 127353944Sdim const char *end2 = end; 128353944Sdim while (line != end2 && 129353944Sdim (end2[-1] == ' ' || end2[-1] == '\t' || end2[-1] == '\r')) 130353944Sdim end2--; 131353944Sdim int type; 132353944Sdim for (type = 0; type < suppression_types_num_; type++) { 133353944Sdim const char *next_char = StripPrefix(line, suppression_types_[type]); 134353944Sdim if (next_char && *next_char == ':') { 135353944Sdim line = ++next_char; 136353944Sdim break; 137353944Sdim } 138353944Sdim } 139353944Sdim if (type == suppression_types_num_) { 140353944Sdim Printf("%s: failed to parse suppressions\n", SanitizerToolName); 141353944Sdim Die(); 142353944Sdim } 143353944Sdim Suppression s; 144353944Sdim s.type = suppression_types_[type]; 145353944Sdim s.templ = (char*)InternalAlloc(end2 - line + 1); 146353944Sdim internal_memcpy(s.templ, line, end2 - line); 147353944Sdim s.templ[end2 - line] = 0; 148353944Sdim suppressions_.push_back(s); 149353944Sdim has_suppression_type_[type] = true; 150353944Sdim } 151353944Sdim if (end[0] == 0) 152353944Sdim break; 153353944Sdim line = end + 1; 154353944Sdim } 155353944Sdim} 156353944Sdim 157353944Sdimuptr SuppressionContext::SuppressionCount() const { 158353944Sdim return suppressions_.size(); 159353944Sdim} 160353944Sdim 161353944Sdimbool SuppressionContext::HasSuppressionType(const char *type) const { 162353944Sdim for (int i = 0; i < suppression_types_num_; i++) { 163353944Sdim if (0 == internal_strcmp(type, suppression_types_[i])) 164353944Sdim return has_suppression_type_[i]; 165353944Sdim } 166353944Sdim return false; 167353944Sdim} 168353944Sdim 169353944Sdimconst Suppression *SuppressionContext::SuppressionAt(uptr i) const { 170353944Sdim CHECK_LT(i, suppressions_.size()); 171353944Sdim return &suppressions_[i]; 172353944Sdim} 173353944Sdim 174353944Sdimvoid SuppressionContext::GetMatched( 175353944Sdim InternalMmapVector<Suppression *> *matched) { 176353944Sdim for (uptr i = 0; i < suppressions_.size(); i++) 177353944Sdim if (atomic_load_relaxed(&suppressions_[i].hit_count)) 178353944Sdim matched->push_back(&suppressions_[i]); 179353944Sdim} 180353944Sdim 181353944Sdim} // namespace __sanitizer 182