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"
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 llvm::Error fallback(const Stmt *E) {
49 return makeErrAtNode(Ctx, E,
50 "attempt to translate %s to EntityPointerLevels",
51 E->getStmtClassName());
52 }
53
54 EntityPointerLevel createEntityPointerLevelFor(const EntityName &Name) {
55 return EntityPointerLevel({AddEntity(Name), 1});
56 }
57
58 // The common helper function for Translate(*base):
59 // Translate(*base) -> Translate(base) with .pointerLevel + 1
60 Expected<EntityPointerLevelSet> translateDereferencePointer(const Expr *Ptr) {
61 assert(hasPtrOrArrType(Ptr));
62
64 if (!SubResult)
65 return SubResult.takeError();
66
67 auto Incremented = llvm::map_range(*SubResult, incrementPointerLevel);
68 return EntityPointerLevelSet{Incremented.begin(), Incremented.end()};
69 }
70
71 std::function<EntityId(EntityName EN)> AddEntity;
72 ASTContext &Ctx;
73
74public:
76 ASTContext &Ctx)
77 : AddEntity(AddEntity), Ctx(Ctx) {}
78
81 if (IsRet && !isa<FunctionDecl>(D))
82 return makeErrAtNode(
83 Ctx, D,
84 "attempt to call getEntityNameForReturn on a NamedDecl of %s kind",
85 D->getDeclKindName());
86
87 std::optional<EntityName> EN =
89 : getEntityName(D);
90 if (EN)
91 return createEntityPointerLevelFor(*EN);
92 return makeEntityNameErr(Ctx, D);
93 }
94
95 static EntityPointerLevel incrementPointerLevel(const EntityPointerLevel &E) {
96 return EntityPointerLevel({E.getEntity(), E.getPointerLevel() + 1});
97 }
98
99 static EntityPointerLevel decrementPointerLevel(const EntityPointerLevel &E) {
100 assert(E.getPointerLevel() > 0);
101 return EntityPointerLevel({E.getEntity(), E.getPointerLevel() - 1});
102 }
103
104private:
105 Expected<EntityPointerLevelSet> VisitStmt(const Stmt *E) {
106 return fallback(E);
107 }
108
109 // Translate(base + x) -> Translate(base)
110 // Translate(x + base) -> Translate(base)
111 // Translate(base - x) -> Translate(base)
112 // Translate(base {+=, -=, =} x) -> Translate(base)
113 // Translate(x, base) -> Translate(base)
114 Expected<EntityPointerLevelSet> VisitBinaryOperator(const BinaryOperator *E) {
115 switch (E->getOpcode()) {
116 case clang::BO_Add:
117 if (hasPtrOrArrType(E->getLHS()))
118 return Visit(E->getLHS());
119 return Visit(E->getRHS());
120 case clang::BO_Sub:
121 case clang::BO_AddAssign:
122 case clang::BO_SubAssign:
123 case clang::BO_Assign:
124 return Visit(E->getLHS());
125 case clang::BO_Comma:
126 return Visit(E->getRHS());
127 default:
128 return fallback(E);
129 }
130 }
131
132 // Translate({++, --}base) -> Translate(base)
133 // Translate(base{++, --}) -> Translate(base)
134 // Translate(*base) -> Translate(base) with .pointerLevel += 1
135 // Translate(&base) -> {}, if Translate(base) is {}
136 // -> Translate(base) with .pointerLevel -= 1
137 Expected<EntityPointerLevelSet> VisitUnaryOperator(const UnaryOperator *E) {
138 switch (E->getOpcode()) {
139 case clang::UO_PostInc:
140 case clang::UO_PostDec:
141 case clang::UO_PreInc:
142 case clang::UO_PreDec:
143 return Visit(E->getSubExpr());
144 case clang::UO_AddrOf: {
145 Expected<EntityPointerLevelSet> SubResult = Visit(E->getSubExpr());
146 if (!SubResult)
147 return SubResult.takeError();
148
149 auto Decremented = llvm::map_range(*SubResult, decrementPointerLevel);
150 return EntityPointerLevelSet{Decremented.begin(), Decremented.end()};
151 }
152 case clang::UO_Deref:
153 return translateDereferencePointer(E->getSubExpr());
154 default:
155 return fallback(E);
156 }
157 }
158
159 // Translate((T*)base) -> Translate(base) if base has pointer type
160 // -> {} otherwise
161 Expected<EntityPointerLevelSet> VisitCastExpr(const CastExpr *E) {
162 if (hasPtrOrArrType(E->getSubExpr()))
163 return Visit(E->getSubExpr());
164 return EntityPointerLevelSet{};
165 }
166
167 // Translate(f(...)) -> {} if it is an indirect call
168 // -> {(f_return, 1)}, otherwise
169 Expected<EntityPointerLevelSet> VisitCallExpr(const CallExpr *E) {
170 if (auto *FD = E->getDirectCallee())
171 if (auto FDEntityName = getEntityNameForReturn(FD))
172 return EntityPointerLevelSet{
173 createEntityPointerLevelFor(*FDEntityName)};
174 return EntityPointerLevelSet{};
175 }
176
177 // Translate(base[x]) -> Translate(*base)
178 Expected<EntityPointerLevelSet>
179 VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
180 return translateDereferencePointer(E->getBase());
181 }
182
183 // Translate(cond ? base1 : base2) := Translate(base1) U Translate(base2)
184 Expected<EntityPointerLevelSet>
185 VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
186 Expected<EntityPointerLevelSet> ReT = Visit(E->getTrueExpr());
187 Expected<EntityPointerLevelSet> ReF = Visit(E->getFalseExpr());
188
189 if (ReT && ReF) {
190 ReT->insert(ReF->begin(), ReF->end());
191 return ReT;
192 }
193 if (!ReF && !ReT)
194 return llvm::joinErrors(ReT.takeError(), ReF.takeError());
195 if (!ReF)
196 return ReF.takeError();
197 return ReT.takeError();
198 }
199
200 Expected<EntityPointerLevelSet> VisitParenExpr(const ParenExpr *E) {
201 return Visit(E->getSubExpr());
202 }
203
204 // Translate("string-literal") -> {}
205 // Buffer accesses on string literals are unsafe, but string literals are not
206 // entities so there is no EntityPointerLevel associated with it.
207 Expected<EntityPointerLevelSet> VisitStringLiteral(const StringLiteral *E) {
208 return EntityPointerLevelSet{};
209 }
210
211 // Translate(DRE) -> {(Decl, 1)}
212 Expected<EntityPointerLevelSet> VisitDeclRefExpr(const DeclRefExpr *E) {
213 if (auto EntityName = getEntityName(E->getDecl()))
214 return EntityPointerLevelSet{createEntityPointerLevelFor(*EntityName)};
215 return makeEntityNameErr(Ctx, E->getDecl());
216 }
217
218 // Translate({., ->}f) -> {(MemberDecl, 1)}
219 Expected<EntityPointerLevelSet> VisitMemberExpr(const MemberExpr *E) {
220 if (auto EntityName = getEntityName(E->getMemberDecl()))
221 return EntityPointerLevelSet{createEntityPointerLevelFor(*EntityName)};
222 return makeEntityNameErr(Ctx, E->getMemberDecl());
223 }
224
225 Expected<EntityPointerLevelSet>
226 VisitOpaqueValueExpr(const OpaqueValueExpr *S) {
227 return Visit(S->getSourceExpr());
228 }
229};
230} // namespace clang::ssaf
231
232Expected<EntityPointerLevelSet> clang::ssaf::translateEntityPointerLevel(
233 const Expr *E, ASTContext &Ctx,
234 llvm::function_ref<EntityId(EntityName EN)> AddEntity) {
235 EntityPointerLevelTranslator Translator(AddEntity, Ctx);
236
237 return Translator.translate(E);
238}
239
240/// Create an EntityPointerLevel from a ValueDecl of a pointer type.
241Expected<EntityPointerLevel> clang::ssaf::createEntityPointerLevel(
242 const NamedDecl *ND, llvm::function_ref<EntityId(EntityName EN)> AddEntity,
243 bool IsFunRet) {
244 EntityPointerLevelTranslator Translator(AddEntity, ND->getASTContext());
245
246 return Translator.translate(ND, IsFunRet);
247}
248
249EntityPointerLevel
253
254EntityPointerLevel clang::ssaf::buildEntityPointerLevel(EntityId Id,
255 unsigned PtrLv) {
256 return EntityPointerLevel({Id, PtrLv});
257}
258
259// Writes an EntityPointerLevel as
260// Array [
261// Object { "@" : [entity-id]},
262// [pointer-level-integer]
263// ]
265 const EntityPointerLevel &EPL, JSONFormat::EntityIdToJSONFn EntityId2JSON) {
266 return llvm::json::Array{EntityId2JSON(EPL.getEntity()),
267 llvm::json::Value(EPL.getPointerLevel())};
268}
269
271 const llvm::json::Value &EPLData,
272 JSONFormat::EntityIdFromJSONFn EntityIdFromJSON) {
273 auto *AsArr = EPLData.getAsArray();
274
275 if (!AsArr || AsArr->size() != 2)
277 EPLData, "an array with exactly two elements representing "
278 "EntityId and PointerLevel, respectively");
279
280 auto *EntityIdObj = (*AsArr)[0].getAsObject();
281
282 if (!EntityIdObj)
283 return makeSawButExpectedError((*AsArr)[0],
284 "an object representing EntityId");
285
286 Expected<EntityId> Id = EntityIdFromJSON(*EntityIdObj);
287
288 if (!Id)
289 return Id.takeError();
290
291 std::optional<uint64_t> PtrLv = (*AsArr)[1].getAsInteger();
292
293 if (!PtrLv)
294 return makeSawButExpectedError((*AsArr)[1],
295 "an integer representing PointerLevel");
296
297 return buildEntityPointerLevel(*Id, *PtrLv);
298}
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:227
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
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
Uniquely identifies an entity in a program.
Definition EntityName.h:28
static EntityPointerLevel incrementPointerLevel(const EntityPointerLevel &E)
Expected< EntityPointerLevelSet > translate(const Expr *E)
EntityPointerLevelTranslator(std::function< EntityId(EntityName EN)> AddEntity, ASTContext &Ctx)
static EntityPointerLevel decrementPointerLevel(const EntityPointerLevel &E)
Expected< EntityPointerLevel > translate(const NamedDecl *D, bool IsRet)
llvm::function_ref< llvm::Expected< EntityId >(const Object &)> EntityIdFromJSONFn
Definition JSONFormat.h:71
llvm::function_ref< Object(EntityId)> EntityIdToJSONFn
Definition JSONFormat.h:70
std::optional< EntityName > getEntityNameForReturn(const FunctionDecl *FD)
Maps return entity of a function to an EntityName.
llvm::Error makeErrAtNode(clang::ASTContext &Ctx, const NodeTy *N, llvm::StringRef Fmt, const Ts &...Args)
llvm::json::Value entityPointerLevelToJSON(const EntityPointerLevel &EPL, JSONFormat::EntityIdToJSONFn EntityId2JSON)
EntityPointerLevel incrementPointerLevel(const EntityPointerLevel &E)
An EntityPointerLevel is associated with a level of the declared pointer/array type of an entity.
Expected< EntityPointerLevel > entityPointerLevelFromJSON(const llvm::json::Value &EPLData, JSONFormat::EntityIdFromJSONFn EntityIdFromJSON)
llvm::Error makeEntityNameErr(clang::ASTContext &Ctx, const clang::NamedDecl *D)
std::optional< EntityName > getEntityName(const Decl *D)
Maps a declaration to an EntityName.
llvm::Error makeSawButExpectedError(const llvm::json::Value &Saw, llvm::StringRef Expected, const Ts &...ExpectedArgs)
bool hasPtrOrArrType(const DeclOrExpr *E)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
U cast(CodeGen::Address addr)
Definition Address.h:327
int const char * function
Definition c++config.h:31