clang 23.0.0git
EntityPointerLevel.cpp
Go to the documentation of this file.
1//===- EntityPointerLevel.cpp -----------------------------------*- 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
10#include "SSAFAnalysesCommon.h"
12#include "clang/AST/Decl.h"
15#include <optional>
16
17using namespace clang;
18using namespace ssaf;
19
20namespace clang::ssaf {
21// Translate a pointer type expression 'E' to a (set of) EntityPointerLevel(s)
22// associated with the declared type of the base address of `E`. If the base
23// address of `E` is not associated with an entity, the translation result is an
24// empty set.
25//
26// The translation is a process of traversing into the pointer 'E' until its
27// base address can be represented by an entity, with the number of dereferences
28// tracked by incrementing the pointer level. Naturally, taking address of, as
29// the inverse operation of dereference, is tracked by decrementing the pointer
30// level.
31//
32// For example, suppose there are pointers and arrays declared as
33// int *ptr, **p1, **p2;
34// int arr[10][10];
35// , the translation of expressions involving these base addresses will be:
36// Translate(ptr + 5) -> {(ptr, 1)}
37// Translate(arr[5]) -> {(arr, 2)}
38// Translate(cond ? p1[5] : p2) -> {(p1, 2), (p2, 1)}
39// Translate(&arr[5]) -> {(arr, 1)}
41 : ConstStmtVisitor<EntityPointerLevelTranslator,
42 Expected<EntityPointerLevelSet>> {
43 friend class StmtVisitorBase;
44
45 // Fallback method for all unsupported expression kind:
46 llvm::Error fallback(const Stmt *E) {
47 return makeErrAtNode(Ctx, E,
48 "attempt to translate %s to EntityPointerLevels",
49 E->getStmtClassName());
50 }
51
53 createEntityPointerLevelFor(const NamedDecl *ND) {
54 std::optional<EntityId> Id = Extractor.addEntity(ND);
55 if (!Id)
56 return makeErrAtNode(Ctx, ND, "failed to create EntityId for %s",
57 ND->getDeclKindName());
58 return EntityPointerLevel{buildEntityPointerLevel(*Id, 1)};
59 }
60
62 createEntityPointerLevelForReturn(const FunctionDecl *FD) {
63 std::optional<EntityId> Id = Extractor.addEntityForReturn(FD);
64 if (!Id) {
65 return makeErrAtNode(Ctx, FD, "failed to create EntityId for function %s",
66 cast<NamedDecl>(FD)->getNameAsString().c_str());
67 }
68 return EntityPointerLevel{buildEntityPointerLevel(*Id, 1)};
69 }
70
71 // The common helper function for Translate(*base):
72 // Translate(*base) -> Translate(base) with .pointerLevel + 1
73 Expected<EntityPointerLevelSet> translateDereferencePointer(const Expr *Ptr) {
74 assert(hasPtrOrArrType(Ptr));
75
76 Expected<EntityPointerLevelSet> SubResult = Visit(Ptr);
77 if (!SubResult)
78 return SubResult.takeError();
79
80 auto Incremented = llvm::map_range(*SubResult, incrementPointerLevel);
81 return EntityPointerLevelSet{Incremented.begin(), Incremented.end()};
82 }
83
84 TUSummaryExtractor &Extractor;
85 ASTContext &Ctx;
86
87public:
89 : Extractor(Extractor), Ctx(Ctx) {}
90
93 if (!IsRet)
94 return createEntityPointerLevelFor(D);
95
96 if (const auto *FD = dyn_cast<FunctionDecl>(D))
97 return createEntityPointerLevelForReturn(FD);
98
99 return makeErrAtNode(Ctx, D, "attempt to get entity for return of %s",
100 D->getDeclKindName());
101 }
102
103 static EntityPointerLevel incrementPointerLevel(const EntityPointerLevel &E) {
104 return EntityPointerLevel({E.getEntity(), E.getPointerLevel() + 1});
105 }
106
107 static EntityPointerLevel decrementPointerLevel(const EntityPointerLevel &E) {
108 assert(E.getPointerLevel() > 0);
109 return EntityPointerLevel({E.getEntity(), E.getPointerLevel() - 1});
110 }
111
112private:
113 Expected<EntityPointerLevelSet> VisitStmt(const Stmt *E) {
114 return fallback(E);
115 }
116
117 // Translate(base + x) -> Translate(base)
118 // Translate(x + base) -> Translate(base)
119 // Translate(base - x) -> Translate(base)
120 // Translate(base {+=, -=, =} x) -> Translate(base)
121 // Translate(x, base) -> Translate(base)
122 Expected<EntityPointerLevelSet> VisitBinaryOperator(const BinaryOperator *E) {
123 switch (E->getOpcode()) {
124 case clang::BO_Add:
125 if (hasPtrOrArrType(E->getLHS()))
126 return Visit(E->getLHS());
127 return Visit(E->getRHS());
128 case clang::BO_Sub:
129 case clang::BO_AddAssign:
130 case clang::BO_SubAssign:
131 case clang::BO_Assign:
132 return Visit(E->getLHS());
133 case clang::BO_Comma:
134 return Visit(E->getRHS());
135 default:
136 return fallback(E);
137 }
138 }
139
140 // Translate({++, --}base) -> Translate(base)
141 // Translate(base{++, --}) -> Translate(base)
142 // Translate(*base) -> Translate(base) with .pointerLevel += 1
143 // Translate(&base) -> {}, if Translate(base) is {}
144 // -> Translate(base) with .pointerLevel -= 1
145 Expected<EntityPointerLevelSet> VisitUnaryOperator(const UnaryOperator *E) {
146 switch (E->getOpcode()) {
147 case clang::UO_PostInc:
148 case clang::UO_PostDec:
149 case clang::UO_PreInc:
150 case clang::UO_PreDec:
151 return Visit(E->getSubExpr());
152 case clang::UO_AddrOf: {
153 Expected<EntityPointerLevelSet> SubResult = Visit(E->getSubExpr());
154 if (!SubResult)
155 return SubResult.takeError();
156
157 auto Decremented = llvm::map_range(*SubResult, decrementPointerLevel);
158 return EntityPointerLevelSet{Decremented.begin(), Decremented.end()};
159 }
160 case clang::UO_Deref:
161 return translateDereferencePointer(E->getSubExpr());
162 default:
163 return fallback(E);
164 }
165 }
166
167 // Translate((T*)base) -> Translate(base) if base has pointer type
168 // -> {} otherwise
169 Expected<EntityPointerLevelSet> VisitCastExpr(const CastExpr *E) {
170 if (hasPtrOrArrType(E->getSubExpr()))
171 return Visit(E->getSubExpr());
172 return EntityPointerLevelSet{};
173 }
174
175 // Translate(f(...)) -> {} if it is an indirect call
176 // -> {(f_return, 1)}, otherwise
177 Expected<EntityPointerLevelSet> VisitCallExpr(const CallExpr *E) {
178 if (auto *FD = E->getDirectCallee()) {
179 if (auto ReturnId = Extractor.addEntityForReturn(FD))
180 return EntityPointerLevelSet{buildEntityPointerLevel(*ReturnId, 1)};
181 }
182 return EntityPointerLevelSet{};
183 }
184
185 // Translate(base[x]) -> Translate(*base)
186 Expected<EntityPointerLevelSet>
187 VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
188 return translateDereferencePointer(E->getBase());
189 }
190
191 // Translate(cond ? base1 : base2) := Translate(base1) U Translate(base2)
192 Expected<EntityPointerLevelSet>
193 VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
194 Expected<EntityPointerLevelSet> ReT = Visit(E->getTrueExpr());
195 Expected<EntityPointerLevelSet> ReF = Visit(E->getFalseExpr());
196
197 if (ReT && ReF) {
198 ReT->insert(ReF->begin(), ReF->end());
199 return ReT;
200 }
201 if (!ReF && !ReT)
202 return llvm::joinErrors(ReT.takeError(), ReF.takeError());
203 if (!ReF)
204 return ReF.takeError();
205 return ReT.takeError();
206 }
207
208 Expected<EntityPointerLevelSet> VisitParenExpr(const ParenExpr *E) {
209 return Visit(E->getSubExpr());
210 }
211
212 // Translate("string-literal") -> {}
213 // Buffer accesses on string literals are unsafe, but string literals are not
214 // entities so there is no EntityPointerLevel associated with it.
215 Expected<EntityPointerLevelSet> VisitStringLiteral(const StringLiteral *E) {
216 return EntityPointerLevelSet{};
217 }
218
219 // Translate(DRE) -> {(Decl, 1)}
220 Expected<EntityPointerLevelSet> VisitDeclRefExpr(const DeclRefExpr *E) {
221 auto Res = createEntityPointerLevelFor(E->getDecl());
222 if (!Res)
223 return Res.takeError();
224 return EntityPointerLevelSet{*Res};
225 }
226
227 // Translate({., ->}f) -> {(MemberDecl, 1)}
228 Expected<EntityPointerLevelSet> VisitMemberExpr(const MemberExpr *E) {
229 auto Res = createEntityPointerLevelFor(E->getMemberDecl());
230 if (!Res)
231 return Res.takeError();
232 return EntityPointerLevelSet{*Res};
233 }
234
235 // Translate(`DefaultArg`) -> Translate(`DefaultArg->getExpr()`)
236 Expected<EntityPointerLevelSet>
237 VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
238 return Visit(E->getExpr());
239 }
240
241 Expected<EntityPointerLevelSet>
242 VisitOpaqueValueExpr(const OpaqueValueExpr *S) {
243 return Visit(S->getSourceExpr());
244 }
245};
246} // namespace clang::ssaf
247
249clang::ssaf::translateEntityPointerLevel(const Expr *E, ASTContext &Ctx,
250 TUSummaryExtractor &Extractor) {
251 EntityPointerLevelTranslator Translator(Extractor, Ctx);
252
253 return Translator.translate(E);
254}
255
256/// Create an EntityPointerLevel from a ValueDecl of a pointer type.
257Expected<EntityPointerLevel> clang::ssaf::createEntityPointerLevel(
258 const NamedDecl *ND, TUSummaryExtractor &Extractor, bool IsFunRet) {
259 EntityPointerLevelTranslator Translator(Extractor, ND->getASTContext());
260
261 return Translator.translate(ND, IsFunRet);
262}
263
264EntityPointerLevel
268
269EntityPointerLevel clang::ssaf::buildEntityPointerLevel(EntityId Id,
270 unsigned PtrLv) {
271 return EntityPointerLevel({Id, PtrLv});
272}
Defines the clang::ASTContext interface.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:228
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
Definition Expr.h:4540
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
Definition Expr.h:4546
A builtin binary operation expression such as "x + y" or "x <= y".
Definition Expr.h:4041
Expr * getLHS() const
Definition Expr.h:4091
Expr * getRHS() const
Definition Expr.h:4093
Opcode getOpcode() const
Definition Expr.h:4086
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3129
Expr * getSubExpr()
Definition Expr.h:3729
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
ValueDecl * getDecl()
Definition Expr.h:1341
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:547
const char * getDeclKindName() const
Definition DeclBase.cpp:169
This represents one expression.
Definition Expr.h:112
Represents a function declaration or definition.
Definition Decl.h:2018
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3450
This represents a decl that may have a name.
Definition Decl.h:274
Expr * getSourceExpr() const
The source expression of an opaque value expression is the expression which originally generated the ...
Definition Expr.h:1231
const Expr * getSubExpr() const
Definition Expr.h:2202
Stmt - This represents one statement.
Definition Stmt.h:86
const char * getStmtClassName() const
Definition Stmt.cpp:86
Expr * getSubExpr() const
Definition Expr.h:2288
Opcode getOpcode() const
Definition Expr.h:2283
Lightweight opaque handle representing an entity in an EntityIdTable.
Definition EntityId.h:31
static EntityPointerLevel incrementPointerLevel(const EntityPointerLevel &E)
EntityPointerLevelTranslator(TUSummaryExtractor &Extractor, ASTContext &Ctx)
Expected< EntityPointerLevelSet > translate(const Expr *E)
static EntityPointerLevel decrementPointerLevel(const EntityPointerLevel &E)
Expected< EntityPointerLevel > translate(const NamedDecl *D, bool IsRet)
std::optional< EntityId > addEntityForReturn(const FunctionDecl *FD)
Creates EntityName for the return value of FD, registers the entity, and sets its linkage atomically.
std::optional< EntityId > addEntity(const NamedDecl *D)
Creates EntityName from the Decl, registers the entity, and sets its linkage atomically.
llvm::Error makeErrAtNode(clang::ASTContext &Ctx, const NodeTy *N, llvm::StringRef Fmt, const Ts &...Args)
EntityPointerLevel incrementPointerLevel(const EntityPointerLevel &E)
An EntityPointerLevel is associated with a level of the declared pointer/array type of an entity.
bool hasPtrOrArrType(const DeclOrExpr *E)
The JSON file list parser is used to communicate input to InstallAPI.
U cast(CodeGen::Address addr)
Definition Address.h:327