clang  19.0.0git
CallDescription.cpp
Go to the documentation of this file.
1 //===- CallDescription.cpp - function/method call matching --*- 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 //
9 /// \file This file defines a generic mechanism for matching for function and
10 /// method calls of C, C++, and Objective-C languages. Instances of these
11 /// classes are frequently used together with the CallEvent classes.
12 //
13 //===----------------------------------------------------------------------===//
14 
16 #include "clang/AST/Decl.h"
19 #include "llvm/ADT/ArrayRef.h"
20 #include <iterator>
21 #include <optional>
22 
23 using namespace llvm;
24 using namespace clang;
25 
26 using MaybeCount = std::optional<unsigned>;
27 
28 // A constructor helper.
30  MaybeCount RequiredParams) {
31  if (RequiredParams)
32  return RequiredParams;
33  if (RequiredArgs)
34  return RequiredArgs;
35  return std::nullopt;
36 }
37 
38 ento::CallDescription::CallDescription(Mode MatchAs,
39  ArrayRef<StringRef> QualifiedName,
40  MaybeCount RequiredArgs /*= None*/,
41  MaybeCount RequiredParams /*= None*/)
42  : RequiredArgs(RequiredArgs),
43  RequiredParams(readRequiredParams(RequiredArgs, RequiredParams)),
44  MatchAs(MatchAs) {
45  assert(!QualifiedName.empty());
46  this->QualifiedName.reserve(QualifiedName.size());
47  llvm::transform(QualifiedName, std::back_inserter(this->QualifiedName),
48  [](StringRef From) { return From.str(); });
49 }
50 
51 bool ento::CallDescription::matches(const CallEvent &Call) const {
52  // FIXME: Add ObjC Message support.
53  if (Call.getKind() == CE_ObjCMessage)
54  return false;
55 
56  const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
57  if (!FD)
58  return false;
59 
60  return matchesImpl(FD, Call.getNumArgs(), Call.parameters().size());
61 }
62 
64  const auto *FD = dyn_cast_or_null<FunctionDecl>(CE.getCalleeDecl());
65  if (!FD)
66  return false;
67 
68  return matchesImpl(FD, CE.getNumArgs(), FD->param_size());
69 }
70 
71 bool ento::CallDescription::matchNameOnly(const NamedDecl *ND) const {
72  DeclarationName Name = ND->getDeclName();
73  if (const auto *NameII = Name.getAsIdentifierInfo()) {
74  if (!II)
75  II = &ND->getASTContext().Idents.get(getFunctionName());
76 
77  return NameII == *II; // Fast case.
78  }
79 
80  // Fallback to the slow stringification and comparison for:
81  // C++ overloaded operators, constructors, destructors, etc.
82  // FIXME This comparison is way SLOWER than comparing pointers.
83  // At some point in the future, we should compare FunctionDecl pointers.
84  return Name.getAsString() == getFunctionName();
85 }
86 
87 bool ento::CallDescription::matchQualifiedNameParts(const Decl *D) const {
88  const auto FindNextNamespaceOrRecord =
89  [](const DeclContext *Ctx) -> const DeclContext * {
90  while (Ctx && !isa<NamespaceDecl, RecordDecl>(Ctx))
91  Ctx = Ctx->getParent();
92  return Ctx;
93  };
94 
95  auto QualifierPartsIt = begin_qualified_name_parts();
96  const auto QualifierPartsEndIt = end_qualified_name_parts();
97 
98  // Match namespace and record names. Skip unrelated names if they don't
99  // match.
100  const DeclContext *Ctx = FindNextNamespaceOrRecord(D->getDeclContext());
101  for (; Ctx && QualifierPartsIt != QualifierPartsEndIt;
102  Ctx = FindNextNamespaceOrRecord(Ctx->getParent())) {
103  // If not matched just continue and try matching for the next one.
104  if (cast<NamedDecl>(Ctx)->getName() != *QualifierPartsIt)
105  continue;
106  ++QualifierPartsIt;
107  }
108 
109  // We matched if we consumed all expected qualifier segments.
110  return QualifierPartsIt == QualifierPartsEndIt;
111 }
112 
113 bool ento::CallDescription::matchesImpl(const FunctionDecl *FD, size_t ArgCount,
114  size_t ParamCount) const {
115  if (!FD)
116  return false;
117 
118  const bool isMethod = isa<CXXMethodDecl>(FD);
119 
120  if (MatchAs == Mode::SimpleFunc && isMethod)
121  return false;
122 
123  if (MatchAs == Mode::CXXMethod && !isMethod)
124  return false;
125 
126  if (MatchAs == Mode::CLibraryMaybeHardened) {
127  // In addition to accepting FOO() with CLibrary rules, we also want to
128  // accept calls to __FOO_chk() and __builtin___FOO_chk().
131  // Check that the actual argument/parameter counts are greater or equal
132  // to the required counts. (Setting a requirement to std::nullopt matches
133  // anything, so in that case value_or ensures that the value is compared
134  // with itself.)
135  return (RequiredArgs.value_or(ArgCount) <= ArgCount &&
136  RequiredParams.value_or(ParamCount) <= ParamCount);
137  }
138  }
139 
140  if (RequiredArgs.value_or(ArgCount) != ArgCount ||
141  RequiredParams.value_or(ParamCount) != ParamCount)
142  return false;
143 
144  if (MatchAs == Mode::CLibrary || MatchAs == Mode::CLibraryMaybeHardened)
146 
147  if (!matchNameOnly(FD))
148  return false;
149 
150  if (!hasQualifiedNameParts())
151  return true;
152 
153  return matchQualifiedNameParts(FD);
154 }
155 
157  std::initializer_list<CallDescription> &&List) {
158  Impl.LinearMap.reserve(List.size());
159  for (const CallDescription &CD : List)
160  Impl.LinearMap.push_back({CD, /*unused*/ true});
161 }
162 
164  return static_cast<bool>(Impl.lookup(Call));
165 }
166 
168  return static_cast<bool>(Impl.lookupAsWritten(CE));
169 }
static MaybeCount readRequiredParams(MaybeCount RequiredArgs, MaybeCount RequiredParams)
std::optional< unsigned > MaybeCount
IdentifierTable & Idents
Definition: ASTContext.h:647
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2872
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:3050
Decl * getCalleeDecl()
Definition: Expr.h:3036
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1436
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition: DeclBase.h:2066
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:501
DeclContext * getDeclContext()
Definition: DeclBase.h:454
The name of a declaration.
Represents a function declaration or definition.
Definition: Decl.h:1972
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
This represents a decl that may have a name.
Definition: Decl.h:249
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition: Decl.h:315
CallDescriptionSet(std::initializer_list< CallDescription > &&List)
bool containsAsWritten(const CallExpr &CE) const
When available, always prefer lookup with a CallEvent! This function exists only when that is not ava...
bool contains(const CallEvent &Call) const
A CallDescription is a pattern that can be used to match calls based on the qualified name and the ar...
bool matches(const CallEvent &Call) const
Returns true if the CallEvent is a call to a function that matches the CallDescription.
bool matchesAsWritten(const CallExpr &CE) const
Returns true if the CallExpr is a call to a function that matches the CallDescription.
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:153
static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name=StringRef())
Returns true if the given function is an externally-visible function in the top-level namespace,...
static bool isHardenedVariantOf(const FunctionDecl *FD, StringRef Name)
In builds that use source hardening (-D_FORTIFY_SOURCE), many standard functions are implemented as m...
@ CE_ObjCMessage
Definition: CallEvent.h:77
static FormatToken * getFunctionName(const AnnotatedLine &Line)
The JSON file list parser is used to communicate input to InstallAPI.
Diagnostic wrappers for TextAPI types for error reporting.
Definition: Dominators.h:30