xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Support/SpecialCaseList.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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