|
|
|||
File indexing completed on 2026-05-10 08:37:07
0001 //===- CallDescription.h - function/method call matching --*- C++ -*-===// 0002 // 0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 0004 // See https://llvm.org/LICENSE.txt for license information. 0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 0006 // 0007 //===----------------------------------------------------------------------===// 0008 // 0009 /// \file This file defines a generic mechanism for matching for function and 0010 /// method calls of C, C++, and Objective-C languages. Instances of these 0011 /// classes are frequently used together with the CallEvent classes. 0012 // 0013 //===----------------------------------------------------------------------===// 0014 0015 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLDESCRIPTION_H 0016 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLDESCRIPTION_H 0017 0018 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 0019 #include "llvm/ADT/ArrayRef.h" 0020 #include "llvm/Support/Compiler.h" 0021 #include <optional> 0022 #include <vector> 0023 0024 namespace clang { 0025 class IdentifierInfo; 0026 } // namespace clang 0027 0028 namespace clang { 0029 namespace ento { 0030 /// A `CallDescription` is a pattern that can be used to _match_ calls 0031 /// based on the qualified name and the argument/parameter counts. 0032 class CallDescription { 0033 public: 0034 enum class Mode { 0035 /// Match calls to functions from the C standard library. This also 0036 /// recognizes builtin variants whose name is derived by adding 0037 /// "__builtin", "__inline" or similar prefixes or suffixes; but only 0038 /// matches functions than are externally visible and are declared either 0039 /// directly within a TU or in the namespace 'std'. 0040 /// For the exact heuristics, see CheckerContext::isCLibraryFunction(). 0041 CLibrary, 0042 0043 /// An extended version of the `CLibrary` mode that also matches the 0044 /// hardened variants like __FOO_chk() and __builtin__FOO_chk() that take 0045 /// additional arguments compared to the "regular" function FOO(). 0046 /// This is not the default behavior of `CLibrary` because in this case the 0047 /// checker code must be prepared to handle the different parametrization. 0048 /// For the exact heuristics, see CheckerContext::isHardenedVariantOf(). 0049 CLibraryMaybeHardened, 0050 0051 /// Matches "simple" functions that are not methods. (Static methods are 0052 /// methods.) 0053 SimpleFunc, 0054 0055 /// Matches a C++ method (may be static, may be virtual, may be an 0056 /// overloaded operator, a constructor or a destructor). 0057 CXXMethod, 0058 0059 /// Match any CallEvent that is not an ObjCMethodCall. This should not be 0060 /// used when the checker looks for a concrete function (and knows whether 0061 /// it is a method); but GenericTaintChecker uses this mode to match 0062 /// functions whose name was configured by the user. 0063 Unspecified, 0064 0065 /// FIXME: Add support for ObjCMethodCall events (I'm not adding it because 0066 /// I'm not familiar with Objective-C). Note that currently an early return 0067 /// in `bool matches(const CallEvent &Call) const;` discards all 0068 /// Objective-C method calls. 0069 }; 0070 0071 private: 0072 friend class CallEvent; 0073 using MaybeCount = std::optional<unsigned>; 0074 0075 mutable std::optional<const IdentifierInfo *> II; 0076 // The list of the qualified names used to identify the specified CallEvent, 0077 // e.g. "{a, b}" represent the qualified names, like "a::b". 0078 std::vector<std::string> QualifiedName; 0079 MaybeCount RequiredArgs; 0080 MaybeCount RequiredParams; 0081 Mode MatchAs; 0082 0083 public: 0084 /// Constructs a CallDescription object. 0085 /// 0086 /// @param MatchAs Specifies the kind of the call that should be matched. 0087 /// 0088 /// @param QualifiedName The list of the name qualifiers of the function that 0089 /// will be matched. The user is allowed to skip any of the qualifiers. 0090 /// For example, {"std", "basic_string", "c_str"} would match both 0091 /// std::basic_string<...>::c_str() and std::__1::basic_string<...>::c_str(). 0092 /// 0093 /// @param RequiredArgs The expected number of arguments that are passed to 0094 /// the function. Omit this parameter (or pass std::nullopt) to match every 0095 /// occurrence without checking the argument count in the call. 0096 /// 0097 /// @param RequiredParams The expected number of parameters in the function 0098 /// definition that is called. Omit this parameter to match every occurrence 0099 /// without checking the parameter count in the definition. 0100 CallDescription(Mode MatchAs, ArrayRef<StringRef> QualifiedName, 0101 MaybeCount RequiredArgs = std::nullopt, 0102 MaybeCount RequiredParams = std::nullopt); 0103 0104 /// Get the name of the function that this object matches. 0105 StringRef getFunctionName() const { return QualifiedName.back(); } 0106 0107 /// Get the qualified name parts in reversed order. 0108 /// E.g. { "std", "vector", "data" } -> "vector", "std" 0109 auto begin_qualified_name_parts() const { 0110 return std::next(QualifiedName.rbegin()); 0111 } 0112 auto end_qualified_name_parts() const { return QualifiedName.rend(); } 0113 0114 /// It's false, if and only if we expect a single identifier, such as 0115 /// `getenv`. It's true for `std::swap`, or `my::detail::container::data`. 0116 bool hasQualifiedNameParts() const { return QualifiedName.size() > 1; } 0117 0118 /// @name Matching CallDescriptions against a CallEvent 0119 /// @{ 0120 0121 /// Returns true if the CallEvent is a call to a function that matches 0122 /// the CallDescription. 0123 /// 0124 /// \note This function is not intended to be used to match Obj-C method 0125 /// calls. 0126 bool matches(const CallEvent &Call) const; 0127 0128 /// Returns true whether the CallEvent matches on any of the CallDescriptions 0129 /// supplied. 0130 /// 0131 /// \note This function is not intended to be used to match Obj-C method 0132 /// calls. 0133 friend bool matchesAny(const CallEvent &Call, const CallDescription &CD1) { 0134 return CD1.matches(Call); 0135 } 0136 0137 /// \copydoc clang::ento::CallDescription::matchesAny(const CallEvent &, const CallDescription &) 0138 template <typename... Ts> 0139 friend bool matchesAny(const CallEvent &Call, const CallDescription &CD1, 0140 const Ts &...CDs) { 0141 return CD1.matches(Call) || matchesAny(Call, CDs...); 0142 } 0143 /// @} 0144 0145 /// @name Matching CallDescriptions against a CallExpr 0146 /// @{ 0147 0148 /// Returns true if the CallExpr is a call to a function that matches the 0149 /// CallDescription. 0150 /// 0151 /// When available, always prefer matching with a CallEvent! This function 0152 /// exists only when that is not available, for example, when _only_ 0153 /// syntactic check is done on a piece of code. 0154 /// 0155 /// Also, StdLibraryFunctionsChecker::Signature is likely a better candicade 0156 /// for syntactic only matching if you are writing a new checker. This is 0157 /// handy if a CallDescriptionMap is already there. 0158 /// 0159 /// The function is imprecise because CallEvent may know path sensitive 0160 /// information, such as the precise argument count (see comments for 0161 /// CallEvent::getNumArgs), the called function if it was called through a 0162 /// function pointer, and other information not available syntactically. 0163 bool matchesAsWritten(const CallExpr &CE) const; 0164 0165 /// Returns true whether the CallExpr matches on any of the CallDescriptions 0166 /// supplied. 0167 /// 0168 /// \note This function is not intended to be used to match Obj-C method 0169 /// calls. 0170 friend bool matchesAnyAsWritten(const CallExpr &CE, 0171 const CallDescription &CD1) { 0172 return CD1.matchesAsWritten(CE); 0173 } 0174 0175 /// \copydoc clang::ento::CallDescription::matchesAnyAsWritten(const CallExpr &, const CallDescription &) 0176 template <typename... Ts> 0177 friend bool matchesAnyAsWritten(const CallExpr &CE, 0178 const CallDescription &CD1, 0179 const Ts &...CDs) { 0180 return CD1.matchesAsWritten(CE) || matchesAnyAsWritten(CE, CDs...); 0181 } 0182 /// @} 0183 0184 private: 0185 bool matchesImpl(const FunctionDecl *Callee, size_t ArgCount, 0186 size_t ParamCount) const; 0187 0188 bool matchNameOnly(const NamedDecl *ND) const; 0189 bool matchQualifiedNameParts(const Decl *D) const; 0190 }; 0191 0192 /// An immutable map from CallDescriptions to arbitrary data. Provides a unified 0193 /// way for checkers to react on function calls. 0194 template <typename T> class CallDescriptionMap { 0195 friend class CallDescriptionSet; 0196 0197 // Some call descriptions aren't easily hashable (eg., the ones with qualified 0198 // names in which some sections are omitted), so let's put them 0199 // in a simple vector and use linear lookup. 0200 // TODO: Implement an actual map for fast lookup for "hashable" call 0201 // descriptions (eg., the ones for C functions that just match the name). 0202 std::vector<std::pair<CallDescription, T>> LinearMap; 0203 0204 public: 0205 CallDescriptionMap( 0206 std::initializer_list<std::pair<CallDescription, T>> &&List) 0207 : LinearMap(List) {} 0208 0209 template <typename InputIt> 0210 CallDescriptionMap(InputIt First, InputIt Last) : LinearMap(First, Last) {} 0211 0212 ~CallDescriptionMap() = default; 0213 0214 // These maps are usually stored once per checker, so let's make sure 0215 // we don't do redundant copies. 0216 CallDescriptionMap(const CallDescriptionMap &) = delete; 0217 CallDescriptionMap &operator=(const CallDescription &) = delete; 0218 0219 CallDescriptionMap(CallDescriptionMap &&) = default; 0220 CallDescriptionMap &operator=(CallDescriptionMap &&) = default; 0221 0222 [[nodiscard]] const T *lookup(const CallEvent &Call) const { 0223 // Slow path: linear lookup. 0224 // TODO: Implement some sort of fast path. 0225 for (const std::pair<CallDescription, T> &I : LinearMap) 0226 if (I.first.matches(Call)) 0227 return &I.second; 0228 0229 return nullptr; 0230 } 0231 0232 /// When available, always prefer lookup with a CallEvent! This function 0233 /// exists only when that is not available, for example, when _only_ 0234 /// syntactic check is done on a piece of code. 0235 /// 0236 /// Also, StdLibraryFunctionsChecker::Signature is likely a better candicade 0237 /// for syntactic only matching if you are writing a new checker. This is 0238 /// handy if a CallDescriptionMap is already there. 0239 /// 0240 /// The function is imprecise because CallEvent may know path sensitive 0241 /// information, such as the precise argument count (see comments for 0242 /// CallEvent::getNumArgs), the called function if it was called through a 0243 /// function pointer, and other information not available syntactically. 0244 [[nodiscard]] const T *lookupAsWritten(const CallExpr &Call) const { 0245 // Slow path: linear lookup. 0246 // TODO: Implement some sort of fast path. 0247 for (const std::pair<CallDescription, T> &I : LinearMap) 0248 if (I.first.matchesAsWritten(Call)) 0249 return &I.second; 0250 0251 return nullptr; 0252 } 0253 }; 0254 0255 /// Enumerators of this enum class are used to construct CallDescription 0256 /// objects; in that context the fully qualified name is needlessly verbose. 0257 using CDM = CallDescription::Mode; 0258 0259 /// An immutable set of CallDescriptions. 0260 /// Checkers can efficiently decide if a given CallEvent matches any 0261 /// CallDescription in the set. 0262 class CallDescriptionSet { 0263 CallDescriptionMap<bool /*unused*/> Impl = {}; 0264 0265 public: 0266 CallDescriptionSet(std::initializer_list<CallDescription> &&List); 0267 0268 CallDescriptionSet(const CallDescriptionSet &) = delete; 0269 CallDescriptionSet &operator=(const CallDescription &) = delete; 0270 0271 [[nodiscard]] bool contains(const CallEvent &Call) const; 0272 0273 /// When available, always prefer lookup with a CallEvent! This function 0274 /// exists only when that is not available, for example, when _only_ 0275 /// syntactic check is done on a piece of code. 0276 /// 0277 /// Also, StdLibraryFunctionsChecker::Signature is likely a better candicade 0278 /// for syntactic only matching if you are writing a new checker. This is 0279 /// handy if a CallDescriptionMap is already there. 0280 /// 0281 /// The function is imprecise because CallEvent may know path sensitive 0282 /// information, such as the precise argument count (see comments for 0283 /// CallEvent::getNumArgs), the called function if it was called through a 0284 /// function pointer, and other information not available syntactically. 0285 [[nodiscard]] bool containsAsWritten(const CallExpr &CE) const; 0286 }; 0287 0288 } // namespace ento 0289 } // namespace clang 0290 0291 #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLDESCRIPTION_H
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|