1 //===-- SpecialCaseList.h - special case list for sanitizers ----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 //===----------------------------------------------------------------------===// 7 // 8 // This file implements a Special Case List for code sanitizers. 9 // 10 //===----------------------------------------------------------------------===// 11 12 #ifndef LLVM_SUPPORT_SPECIALCASELIST_H 13 #define LLVM_SUPPORT_SPECIALCASELIST_H 14 15 #include "llvm/ADT/StringMap.h" 16 #include "llvm/Support/Compiler.h" 17 #include "llvm/Support/GlobPattern.h" 18 #include "llvm/Support/Regex.h" 19 #include <memory> 20 #include <string> 21 #include <utility> 22 #include <vector> 23 24 namespace llvm { 25 class MemoryBuffer; 26 class StringRef; 27 28 namespace vfs { 29 class FileSystem; 30 } 31 32 /// This is a utility class used to parse user-provided text files with 33 /// "special case lists" for code sanitizers. Such files are used to 34 /// define an "ABI list" for DataFlowSanitizer and allow/exclusion lists for 35 /// sanitizers like AddressSanitizer or UndefinedBehaviorSanitizer. 36 /// 37 /// Empty lines and lines starting with "#" are ignored. Sections are defined 38 /// using a '[section_name]' header and can be used to specify sanitizers the 39 /// entries below it apply to. Section names are globs, and 40 /// entries without a section header match all sections (e.g. an '[*]' header 41 /// is assumed.) 42 /// The remaining lines should have the form: 43 /// prefix:glob_pattern[=category] 44 /// If category is not specified, it is assumed to be empty string. 45 /// Definitions of "prefix" and "category" are sanitizer-specific. For example, 46 /// sanitizer exclusion support prefixes "src", "mainfile", "fun" and "global". 47 /// "glob_pattern" defines source files, main files, functions or globals which 48 /// shouldn't be instrumented. 49 /// Examples of categories: 50 /// "functional": used in DFSan to list functions with pure functional 51 /// semantics. 52 /// "init": used in ASan exclusion list to disable initialization-order bugs 53 /// detection for certain globals or source files. 54 /// Full special case list file example: 55 /// --- 56 /// [address] 57 /// # Excluded items: 58 /// fun:*_ZN4base6subtle* 59 /// global:*global_with_bad_access_or_initialization* 60 /// global:*global_with_initialization_issues*=init 61 /// type:*Namespace::ClassName*=init 62 /// src:file_with_tricky_code.cc 63 /// src:ignore-global-initializers-issues.cc=init 64 /// mainfile:main_file.cc 65 /// 66 /// [dataflow] 67 /// # Functions with pure functional semantics: 68 /// fun:cos=functional 69 /// fun:sin=functional 70 /// --- 71 class SpecialCaseList { 72 public: 73 static constexpr std::pair<unsigned, unsigned> NotFound = {0, 0}; 74 /// Parses the special case list entries from files. On failure, returns 75 /// 0 and writes an error message to string. 76 LLVM_ABI static std::unique_ptr<SpecialCaseList> 77 create(const std::vector<std::string> &Paths, llvm::vfs::FileSystem &FS, 78 std::string &Error); 79 /// Parses the special case list from a memory buffer. On failure, returns 80 /// 0 and writes an error message to string. 81 LLVM_ABI static std::unique_ptr<SpecialCaseList> 82 create(const MemoryBuffer *MB, std::string &Error); 83 /// Parses the special case list entries from files. On failure, reports a 84 /// fatal error. 85 LLVM_ABI static std::unique_ptr<SpecialCaseList> 86 createOrDie(const std::vector<std::string> &Paths, llvm::vfs::FileSystem &FS); 87 88 LLVM_ABI ~SpecialCaseList(); 89 90 /// Returns true, if special case list contains a line 91 /// \code 92 /// @Prefix:<E>=@Category 93 /// \endcode 94 /// where @Query satisfies the glob <E> in a given @Section. 95 LLVM_ABI bool inSection(StringRef Section, StringRef Prefix, StringRef Query, 96 StringRef Category = StringRef()) const; 97 98 /// Returns the file index and the line number <FileIdx, LineNo> corresponding 99 /// to the special case list entry if the special case list contains a line 100 /// \code 101 /// @Prefix:<E>=@Category 102 /// \endcode 103 /// where @Query satisfies the glob <E> in a given @Section. 104 /// Returns (zero, zero) if there is no exclusion entry corresponding to this 105 /// expression. 106 LLVM_ABI std::pair<unsigned, unsigned> 107 inSectionBlame(StringRef Section, StringRef Prefix, StringRef Query, 108 StringRef Category = StringRef()) const; 109 110 protected: 111 // Implementations of the create*() functions that can also be used by derived 112 // classes. 113 LLVM_ABI bool createInternal(const std::vector<std::string> &Paths, 114 vfs::FileSystem &VFS, std::string &Error); 115 LLVM_ABI bool createInternal(const MemoryBuffer *MB, std::string &Error); 116 117 SpecialCaseList() = default; 118 SpecialCaseList(SpecialCaseList const &) = delete; 119 SpecialCaseList &operator=(SpecialCaseList const &) = delete; 120 121 /// Represents a set of globs and their line numbers 122 class Matcher { 123 public: 124 LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber, 125 bool UseRegex); 126 // Returns the line number in the source file that this query matches to. 127 // Returns zero if no match is found. 128 LLVM_ABI unsigned match(StringRef Query) const; 129 130 struct Glob { 131 std::string Name; 132 unsigned LineNo; 133 GlobPattern Pattern; 134 // neither copyable nor movable because GlobPattern contains 135 // Glob::StringRef that points to Glob::Name. 136 Glob(Glob &&) = delete; 137 Glob() = default; 138 }; 139 140 std::vector<std::unique_ptr<Matcher::Glob>> Globs; 141 std::vector<std::pair<std::unique_ptr<Regex>, unsigned>> RegExes; 142 }; 143 144 using SectionEntries = StringMap<StringMap<Matcher>>; 145 146 struct Section { SectionSection147 Section(StringRef Str, unsigned FileIdx) 148 : SectionStr(Str), FileIdx(FileIdx) {}; 149 150 std::unique_ptr<Matcher> SectionMatcher = std::make_unique<Matcher>(); 151 SectionEntries Entries; 152 std::string SectionStr; 153 unsigned FileIdx; 154 }; 155 156 std::vector<Section> Sections; 157 158 LLVM_ABI Expected<Section *> addSection(StringRef SectionStr, 159 unsigned FileIdx, unsigned LineNo, 160 bool UseGlobs = true); 161 162 /// Parses just-constructed SpecialCaseList entries from a memory buffer. 163 LLVM_ABI bool parse(unsigned FileIdx, const MemoryBuffer *MB, 164 std::string &Error); 165 166 // Helper method for derived classes to search by Prefix, Query, and Category 167 // once they have already resolved a section entry. 168 LLVM_ABI unsigned inSectionBlame(const SectionEntries &Entries, 169 StringRef Prefix, StringRef Query, 170 StringRef Category) const; 171 }; 172 173 } // namespace llvm 174 175 #endif // LLVM_SUPPORT_SPECIALCASELIST_H 176