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