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"
13#include "clang/AST/Expr.h"
14#include "clang/AST/ExprCXX.h"
17#include <optional>
18
19using namespace clang;
20using namespace ssaf;
21
22namespace clang::ssaf {
23// Translate a pointer type expression 'E' to a (set of) EntityPointerLevel(s)
24// associated with the declared type of the base address of `E`. If the base
25// address of `E` is not associated with an entity, the translation result is an
26// empty set.
27//
28// The translation is a process of traversing into the pointer 'E' until its
29// base address can be represented by an entity, with the number of dereferences
30// tracked by incrementing the pointer level. Naturally, taking address of, as
31// the inverse operation of dereference, is tracked by decrementing the pointer
32// level.
33//
34// For example, suppose there are pointers and arrays declared as
35// int *ptr, **p1, **p2;
36// int arr[10][10];
37// , the translation of expressions involving these base addresses will be:
38// Translate(ptr + 5) -> {(ptr, 1)}
39// Translate(arr[5]) -> {(arr, 2)}
40// Translate(cond ? p1[5] : p2) -> {(p1, 2), (p2, 1)}
41// Translate(&arr[5]) -> {(arr, 1)}
43 : ConstStmtVisitor<EntityPointerLevelTranslator,
44 Expected<EntityPointerLevelSet>> {
45 friend class StmtVisitorBase;
46
47 // Fallback method for all unsupported expression kind:
48 Expected<EntityPointerLevelSet> fallback(const Stmt *S) {
49 // Report an error/warning (at least in debug mode) for any unsupported kind
50 // of pointer/array typed expression, because we want to understand every
51 // pointer/array expression. But for non-pointer/array typed expressions, we
52 // could silently ignore unsupported kinds. This translator visits
53 // non-pointer/array typed expressions because of address-of expressions.
54 if (const Expr *E = dyn_cast<Expr>(S); E && hasPtrOrArrType(E))
55 return makeErrAtNode(Ctx, E,
56 "attempt to translate %s to EntityPointerLevels",
57 E->getStmtClassName());
58 return EntityPointerLevelSet{};
59 }
60
62 createEntityPointerLevelFor(const NamedDecl *ND) {
63 std::optional<EntityId> Id = Extractor.addEntity(ND);
64 if (!Id)
65 return makeErrAtNode(Ctx, ND, "failed to create EntityId for %s",
66 ND->getDeclKindName());
67 return EntityPointerLevel{buildEntityPointerLevel(*Id, 1)};
68 }
69
70 Expected<EntityPointerLevel>
71 createEntityPointerLevelForReturn(const FunctionDecl *FD) {
72 std::optional<EntityId> Id = Extractor.addEntityForReturn(FD);
73 if (!Id) {
74 return makeErrAtNode(Ctx, FD, "failed to create EntityId for function %s",
75 cast<NamedDecl>(FD)->getNameAsString().c_str());
76 }
77 return EntityPointerLevel{buildEntityPointerLevel(*Id, 1)};
78 }
79
80 // The common helper function for Translate(*base):
81 // Translate(*base) -> Translate(base) with .pointerLevel + 1
82 Expected<EntityPointerLevelSet> translateDereferencePointer(const Expr *Ptr) {
83 assert(hasPtrOrArrType(Ptr));
84
85 Expected<EntityPointerLevelSet> SubResult = Visit(Ptr);
86 if (!SubResult)
87 return SubResult.takeError();
88
89 auto Incremented = llvm::map_range(*SubResult, incrementPointerLevel);
90 return EntityPointerLevelSet{Incremented.begin(), Incremented.end()};
91 }
92
93 TUSummaryExtractor &Extractor;
94 ASTContext &Ctx;
95
96public:
98 : Extractor(Extractor), Ctx(Ctx) {}
99
102 if (!IsRet)
103 return createEntityPointerLevelFor(D);
104
105 if (const auto *FD = dyn_cast<FunctionDecl>(D))
106 return createEntityPointerLevelForReturn(FD);
107
108 return makeErrAtNode(Ctx, D, "attempt to get entity for return of %s",
109 D->getDeclKindName());
110 }
111
112 static EntityPointerLevel incrementPointerLevel(const EntityPointerLevel &E) {
113 return EntityPointerLevel({E.getEntity(), E.getPointerLevel() + 1});
114 }
115
116 static EntityPointerLevel decrementPointerLevel(const EntityPointerLevel &E) {
117 assert(E.getPointerLevel() > 0);
118 return EntityPointerLevel({E.getEntity(), E.getPointerLevel() - 1});
119 }
120
121private:
122 Expected<EntityPointerLevelSet> VisitStmt(const Stmt *E) {
123 return fallback(E);
124 }
125
126 // Translate(base + x) -> Translate(base)
127 // Translate(x + base) -> Translate(base)
128 // Translate(base - x) -> Translate(base)
129 // Translate(base {+=, -=, =} x) -> Translate(base)
130 // Translate(x, base) -> Translate(base)
131 Expected<EntityPointerLevelSet> VisitBinaryOperator(const BinaryOperator *E) {
132 switch (E->getOpcode()) {
133 case clang::BO_Add:
134 if (hasPtrOrArrType(E->getLHS()))
135 return Visit(E->getLHS());
136 return Visit(E->getRHS());
137 case clang::BO_Sub:
138 case clang::BO_AddAssign:
139 case clang::BO_SubAssign:
140 case clang::BO_Assign:
141 return Visit(E->getLHS());
142 case clang::BO_Comma:
143 return Visit(E->getRHS());
144 default:
145 return fallback(E);
146 }
147 }
148
149 // Translate({++, --}base) -> Translate(base)
150 // Translate(base{++, --}) -> Translate(base)
151 // Translate(*base) -> Translate(base) with .pointerLevel += 1
152 // Translate(&base) -> {}, if Translate(base) is {}
153 // -> Translate(base) with .pointerLevel -= 1
154 // Translate(+base) -> Translate(base)
155 Expected<EntityPointerLevelSet> VisitUnaryOperator(const UnaryOperator *E) {
156 switch (E->getOpcode()) {
157 case clang::UO_PostInc:
158 case clang::UO_PostDec:
159 case clang::UO_PreInc:
160 case clang::UO_PreDec:
161 return Visit(E->getSubExpr());
162 case clang::UO_AddrOf: {
163 Expected<EntityPointerLevelSet> SubResult = Visit(E->getSubExpr());
164 if (!SubResult)
165 return SubResult.takeError();
166
167 auto Decremented = llvm::map_range(*SubResult, decrementPointerLevel);
168 return EntityPointerLevelSet{Decremented.begin(), Decremented.end()};
169 }
170 case clang::UO_Deref:
171 return translateDereferencePointer(E->getSubExpr());
172 case clang::UO_Plus:
173 return Visit(E->getSubExpr());
174 default:
175 return fallback(E);
176 }
177 }
178
179 // Translate((T*)base) -> Translate(base) if base has pointer type
180 // -> {} otherwise
181 Expected<EntityPointerLevelSet> VisitCastExpr(const CastExpr *E) {
182 if (hasPtrOrArrType(E->getSubExpr()))
183 return Visit(E->getSubExpr());
184 return EntityPointerLevelSet{};
185 }
186
187 // Translate(f(...)) -> {} if it is an indirect call
188 // -> {(f_return, 1)}, otherwise
189 Expected<EntityPointerLevelSet> VisitCallExpr(const CallExpr *E) {
190 if (auto *FD = E->getDirectCallee()) {
191 if (auto ReturnId = Extractor.addEntityForReturn(FD))
192 return EntityPointerLevelSet{buildEntityPointerLevel(*ReturnId, 1)};
193 }
194 return EntityPointerLevelSet{};
195 }
196
197 // Translate(base[x]) -> Translate(*base)
198 Expected<EntityPointerLevelSet>
199 VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
200 return translateDereferencePointer(E->getBase());
201 }
202
203 // Translate(cond ? base1 : base2) := Translate(base1) U Translate(base2)
204 Expected<EntityPointerLevelSet>
205 VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
206 Expected<EntityPointerLevelSet> ReT = Visit(E->getTrueExpr());
207 Expected<EntityPointerLevelSet> ReF = Visit(E->getFalseExpr());
208
209 if (ReT && ReF) {
210 ReT->insert(ReF->begin(), ReF->end());
211 return ReT;
212 }
213 if (!ReF && !ReT)
214 return llvm::joinErrors(ReT.takeError(), ReF.takeError());
215 if (!ReF)
216 return ReF.takeError();
217 return ReT.takeError();
218 }
219
220 Expected<EntityPointerLevelSet> VisitParenExpr(const ParenExpr *E) {
221 return Visit(E->getSubExpr());
222 }
223
224 // Translate("string-literal") -> {} // no entity involved
225 Expected<EntityPointerLevelSet> VisitStringLiteral(const StringLiteral *E) {
226 return EntityPointerLevelSet{};
227 }
228
229 // Translate(predefined-expr) -> {} // treated the same as string literals
230 Expected<EntityPointerLevelSet> VisitPredefinedExpr(const PredefinedExpr *E) {
231 return EntityPointerLevelSet{};
232 }
233
234 // Translate(integer-literal) -> {} // no entity involved
235 Expected<EntityPointerLevelSet> VisitIntegerLiteral(const IntegerLiteral *E) {
236 return EntityPointerLevelSet{};
237 }
238
239 // Translate(DRE) -> {(Decl, 1)}
240 Expected<EntityPointerLevelSet> VisitDeclRefExpr(const DeclRefExpr *E) {
241 auto Res = createEntityPointerLevelFor(E->getDecl());
242 if (!Res)
243 return Res.takeError();
244 return EntityPointerLevelSet{*Res};
245 }
246
247 // Translate({., ->}f) -> {(MemberDecl, 1)}
248 Expected<EntityPointerLevelSet> VisitMemberExpr(const MemberExpr *E) {
249 auto Res = createEntityPointerLevelFor(E->getMemberDecl());
250 if (!Res)
251 return Res.takeError();
252 return EntityPointerLevelSet{*Res};
253 }
254
255 // Unwrap CXXDefaultArgExpr
256 Expected<EntityPointerLevelSet>
257 VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
258 return Visit(E->getExpr());
259 }
260
261 // Unwrap OpaqueValueExpr
262 Expected<EntityPointerLevelSet>
263 VisitOpaqueValueExpr(const OpaqueValueExpr *S) {
264 return Visit(S->getSourceExpr());
265 }
266
267 // Unwrap ExprWithCleanups
268 Expected<EntityPointerLevelSet>
269 VisitExprWithCleanups(const ExprWithCleanups *S) {
270 return Visit(S->getSubExpr());
271 }
272
273 // Unwrap MaterializeTemporaryExpr
274 Expected<EntityPointerLevelSet>
275 VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
276 return Visit(S->getSubExpr());
277 }
278
279 // Unwrap CXXDefaultInitExpr
280 Expected<EntityPointerLevelSet>
281 VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) {
282 return Visit(E->getExpr());
283 }
284
285 // Translate(`nullptr`) -> {}
286 Expected<EntityPointerLevelSet>
287 VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *S) {
288 return EntityPointerLevelSet{};
289 }
290
291 // Translate(`this`) -> {}
292 Expected<EntityPointerLevelSet> VisitCXXThisExpr(const CXXThisExpr *S) {
293 return EntityPointerLevelSet{};
294 }
295
296 // Translate(`new`/`new [*]`) -> {}
297 Expected<EntityPointerLevelSet> VisitCXXNewExpr(const CXXNewExpr *S) {
298 return EntityPointerLevelSet{};
299 }
300
301 // ImplicitValueInitExpr, for raw pointer type,
302 // evaluates to a compile-time constant zero (or null). So no EPL in the
303 // result.
304 Expected<EntityPointerLevelSet>
305 VisitImplicitValueInitExpr(const ImplicitValueInitExpr *S) {
306 return EntityPointerLevelSet{};
307 }
308
309 // The InitListExpr must be an empty or singleton list that
310 // initializes a pointer scalar. Other cases are unexpected thus an error.
311 Expected<EntityPointerLevelSet> VisitInitListExpr(const InitListExpr *E) {
312 if (E->getNumInits() < 1)
313 return EntityPointerLevelSet{};
314 if (E->getType()->isPointerType())
315 return Visit(E->getInit(0));
316 return llvm::createStringError(
317 "Cannot translate an InitListExpr to EntityPointerLevels if it is not "
318 "an empty or singleton list that initializes a pointer scalar");
319 }
320
321 // Clang may default initializes an array with a CXXConstructExpr. Fallback on
322 // other cases, if they exist.
323 // When a CXXConstructExpr has an array type, clang is initializing an array
324 // of class-type objects with default values. In this case, no entity is
325 // associated with the initializer.
326 Expected<EntityPointerLevelSet>
327 VisitCXXConstructExpr(const CXXConstructExpr *E) {
328 if (E->getType()->isArrayType()) {
329 return EntityPointerLevelSet{};
330 }
331 return fallback(E);
332 }
333
334 // No entity is associated with a CXXScalarValueInitExpr:
335 Expected<EntityPointerLevelSet>
336 VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) {
337 return EntityPointerLevelSet{};
338 }
339};
340} // namespace clang::ssaf
341
343clang::ssaf::translateEntityPointerLevel(const Expr *E, ASTContext &Ctx,
344 TUSummaryExtractor &Extractor) {
345 EntityPointerLevelTranslator Translator(Extractor, Ctx);
346
347 return Translator.translate(E);
348}
349
350/// Create an EntityPointerLevel from a ValueDecl of a pointer type.
351Expected<EntityPointerLevel> clang::ssaf::createEntityPointerLevel(
352 const NamedDecl *ND, TUSummaryExtractor &Extractor, bool IsFunRet) {
353 EntityPointerLevelTranslator Translator(Extractor, ND->getASTContext());
354
355 return Translator.translate(ND, IsFunRet);
356}
357
358EntityPointerLevel
362
363EntityPointerLevel clang::ssaf::buildEntityPointerLevel(EntityId Id,
364 unsigned PtrLv) {
365 return EntityPointerLevel({Id, PtrLv});
366}
Defines the clang::ASTContext interface.
Defines the clang::Expr interface and subclasses for C++ expressions.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
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
Expr * getExpr()
Get the initialization expression that will be used.
Definition ExprCXX.cpp:1112
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
QualType getType() const
Definition Expr.h:144
const Expr * getSubExpr() const
Definition Expr.h:1065
unsigned getNumInits() const
Definition Expr.h:5335
const Expr * getInit(unsigned Init) const
Definition Expr.h:5357
Expr * getSubExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue.
Definition ExprCXX.h:4937
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
bool isArrayType() const
Definition TypeBase.h:8781
bool isPointerType() const
Definition TypeBase.h:8682
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 > 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