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
11#include "clang/AST/Decl.h"
15
16using namespace clang;
17using namespace ssaf;
18
19static bool hasPointerType(const Expr *E) {
20 auto Ty = E->getType();
21 return !Ty.isNull() && !Ty->isFunctionPointerType() &&
22 (Ty->isPointerType() || Ty->isArrayType());
23}
24
25static llvm::Error makeUnsupportedStmtKindError(const Stmt *Unsupported) {
26 return llvm::createStringError(
27 "unsupported expression kind for translation to "
28 "EntityPointerLevel: %s",
29 Unsupported->getStmtClassName());
30}
31
32static llvm::Error makeCreateEntityNameError(const NamedDecl *FailedDecl,
33 ASTContext &Ctx) {
34 std::string LocStr = FailedDecl->getSourceRange().getBegin().printToString(
35 Ctx.getSourceManager());
36 return llvm::createStringError(
37 "failed to create entity name for %s declared at %s",
38 FailedDecl->getNameAsString().c_str(), LocStr.c_str());
39}
40
41namespace clang::ssaf {
42// Translate a pointer type expression 'E' to a (set of) EntityPointerLevel(s)
43// associated with the declared type of the base address of `E`. If the base
44// address of `E` is not associated with an entity, the translation result is an
45// empty set.
46//
47// The translation is a process of traversing into the pointer 'E' until its
48// base address can be represented by an entity, with the number of dereferences
49// tracked by incrementing the pointer level. Naturally, taking address of, as
50// the inverse operation of dereference, is tracked by decrementing the pointer
51// level.
52//
53// For example, suppose there are pointers and arrays declared as
54// int *ptr, **p1, **p2;
55// int arr[10][10];
56// , the translation of expressions involving these base addresses will be:
57// Translate(ptr + 5) -> {(ptr, 1)}
58// Translate(arr[5]) -> {(arr, 2)}
59// Translate(cond ? p1[5] : p2) -> {(p1, 2), (p2, 1)}
60// Translate(&arr[5]) -> {(arr, 1)}
62 : ConstStmtVisitor<EntityPointerLevelTranslator,
63 Expected<EntityPointerLevelSet>> {
64 friend class StmtVisitorBase;
65
66 // Fallback method for all unsupported expression kind:
67 llvm::Error fallback(const Stmt *E) {
69 }
70
71 static EntityPointerLevel incrementPointerLevel(const EntityPointerLevel &E) {
72 return EntityPointerLevel(E.getEntity(), E.getPointerLevel() + 1);
73 }
74
75 static EntityPointerLevel decrementPointerLevel(const EntityPointerLevel &E) {
76 assert(E.getPointerLevel() > 0);
77 return EntityPointerLevel(E.getEntity(), E.getPointerLevel() - 1);
78 }
79
80 EntityPointerLevel createEntityPointerLevelFor(const EntityName &Name) {
81 return EntityPointerLevel(AddEntity(Name), 1);
82 }
83
84 // The common helper function for Translate(*base):
85 // Translate(*base) -> Translate(base) with .pointerLevel + 1
86 Expected<EntityPointerLevelSet> translateDereferencePointer(const Expr *Ptr) {
87 assert(hasPointerType(Ptr));
88
89 Expected<EntityPointerLevelSet> SubResult = Visit(Ptr);
90 if (!SubResult)
91 return SubResult.takeError();
92
93 auto Incremented = llvm::map_range(*SubResult, incrementPointerLevel);
94 return EntityPointerLevelSet{Incremented.begin(), Incremented.end()};
95 }
96
97 std::function<EntityId(EntityName EN)> AddEntity;
98 ASTContext &Ctx;
99
100public:
102 ASTContext &Ctx)
103 : AddEntity(AddEntity), Ctx(Ctx) {}
104
106
107private:
108 Expected<EntityPointerLevelSet> VisitStmt(const Stmt *E) {
109 return fallback(E);
110 }
111
112 // Translate(base + x) -> Translate(base)
113 // Translate(x + base) -> Translate(base)
114 // Translate(base - x) -> Translate(base)
115 // Translate(base {+=, -=, =} x) -> Translate(base)
116 // Translate(x, base) -> Translate(base)
117 Expected<EntityPointerLevelSet> VisitBinaryOperator(const BinaryOperator *E) {
118 switch (E->getOpcode()) {
119 case clang::BO_Add:
120 if (hasPointerType(E->getLHS()))
121 return Visit(E->getLHS());
122 return Visit(E->getRHS());
123 case clang::BO_Sub:
124 case clang::BO_AddAssign:
125 case clang::BO_SubAssign:
126 case clang::BO_Assign:
127 return Visit(E->getLHS());
128 case clang::BO_Comma:
129 return Visit(E->getRHS());
130 default:
131 return fallback(E);
132 }
133 }
134
135 // Translate({++, --}base) -> Translate(base)
136 // Translate(base{++, --}) -> Translate(base)
137 // Translate(*base) -> Translate(base) with .pointerLevel += 1
138 // Translate(&base) -> {}, if Translate(base) is {}
139 // -> Translate(base) with .pointerLevel -= 1
140 Expected<EntityPointerLevelSet> VisitUnaryOperator(const UnaryOperator *E) {
141 switch (E->getOpcode()) {
142 case clang::UO_PostInc:
143 case clang::UO_PostDec:
144 case clang::UO_PreInc:
145 case clang::UO_PreDec:
146 return Visit(E->getSubExpr());
147 case clang::UO_AddrOf: {
148 Expected<EntityPointerLevelSet> SubResult = Visit(E->getSubExpr());
149 if (!SubResult)
150 return SubResult.takeError();
151
152 auto Decremented = llvm::map_range(*SubResult, decrementPointerLevel);
153 return EntityPointerLevelSet{Decremented.begin(), Decremented.end()};
154 }
155 case clang::UO_Deref:
156 return translateDereferencePointer(E->getSubExpr());
157 default:
158 return fallback(E);
159 }
160 }
161
162 // Translate((T*)base) -> Translate(p) if p has pointer type
163 // -> {} otherwise
164 Expected<EntityPointerLevelSet> VisitCastExpr(const CastExpr *E) {
165 if (hasPointerType(E->getSubExpr()))
166 return Visit(E->getSubExpr());
167 return EntityPointerLevelSet{};
168 }
169
170 // Translate(f(...)) -> {} if it is an indirect call
171 // -> {(f_return, 1)}, otherwise
172 Expected<EntityPointerLevelSet> VisitCallExpr(const CallExpr *E) {
173 if (auto *FD = E->getDirectCallee())
174 if (auto FDEntityName = getEntityNameForReturn(FD))
175 return EntityPointerLevelSet{
176 createEntityPointerLevelFor(*FDEntityName)};
177 return EntityPointerLevelSet{};
178 }
179
180 // Translate(base[x]) -> Translate(*base)
181 Expected<EntityPointerLevelSet>
182 VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
183 return translateDereferencePointer(E->getBase());
184 }
185
186 // Translate(cond ? base1 : base2) := Translate(base1) U Translate(base2)
187 Expected<EntityPointerLevelSet>
188 VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
189 Expected<EntityPointerLevelSet> ReT = Visit(E->getTrueExpr());
190 Expected<EntityPointerLevelSet> ReF = Visit(E->getFalseExpr());
191
192 if (ReT && ReF) {
193 ReT->insert(ReF->begin(), ReF->end());
194 return ReT;
195 }
196 if (!ReF && !ReT)
197 return llvm::joinErrors(ReT.takeError(), ReF.takeError());
198 if (!ReF)
199 return ReF.takeError();
200 return ReT.takeError();
201 }
202
203 Expected<EntityPointerLevelSet> VisitParenExpr(const ParenExpr *E) {
204 return Visit(E->getSubExpr());
205 }
206
207 // Translate("string-literal") -> {}
208 // Buffer accesses on string literals are unsafe, but string literals are not
209 // entities so there is no EntityPointerLevel associated with it.
210 Expected<EntityPointerLevelSet> VisitStringLiteral(const StringLiteral *E) {
211 return EntityPointerLevelSet{};
212 }
213
214 // Translate(DRE) -> {(Decl, 1)}
215 Expected<EntityPointerLevelSet> VisitDeclRefExpr(const DeclRefExpr *E) {
216 if (auto EntityName = getEntityName(E->getDecl()))
217 return EntityPointerLevelSet{createEntityPointerLevelFor(*EntityName)};
218 return makeCreateEntityNameError(E->getDecl(), Ctx);
219 }
220
221 // Translate({., ->}f) -> {(MemberDecl, 1)}
222 Expected<EntityPointerLevelSet> VisitMemberExpr(const MemberExpr *E) {
223 if (auto EntityName = getEntityName(E->getMemberDecl()))
224 return EntityPointerLevelSet{createEntityPointerLevelFor(*EntityName)};
226 }
227
228 Expected<EntityPointerLevelSet>
229 VisitOpaqueValueExpr(const OpaqueValueExpr *S) {
230 return Visit(S->getSourceExpr());
231 }
232};
233} // namespace clang::ssaf
234
236 const Expr *E, ASTContext &Ctx,
237 std::function<EntityId(EntityName EN)> AddEntity) {
238 EntityPointerLevelTranslator Translator(AddEntity, Ctx);
239
240 return Translator.translate(E);
241}
242
244 unsigned PtrLv) {
245 return EntityPointerLevel({Id, PtrLv});
246}
Defines the clang::ASTContext interface.
static bool hasPointerType(const Expr &E)
static llvm::Error makeUnsupportedStmtKindError(const Stmt *Unsupported)
static bool hasPointerType(const Expr *E)
static llvm::Error makeCreateEntityNameError(const NamedDecl *FailedDecl, ASTContext &Ctx)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:226
SourceManager & getSourceManager()
Definition ASTContext.h:859
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
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
Definition DeclBase.h:435
This represents one expression.
Definition Expr.h:112
QualType getType() const
Definition Expr.h:144
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
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
Definition Decl.h:317
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
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
std::string printToString(const SourceManager &SM) const
SourceLocation getBegin() const
Stmt - This represents one statement.
Definition Stmt.h: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
Expected< EntityPointerLevelSet > translate(const Expr *E)
EntityPointerLevelTranslator(std::function< EntityId(EntityName EN)> AddEntity, ASTContext &Ctx)
EntityPointerLevel buildEntityPointerLevel(EntityId, unsigned)
std::optional< EntityName > getEntityNameForReturn(const FunctionDecl *FD)
Maps return entity of a function to an EntityName.
llvm::Expected< EntityPointerLevelSet > translateEntityPointerLevel(const Expr *E, ASTContext &Ctx, std::function< EntityId(EntityName EN)> AddEntity)
An EntityPointerLevel represents a level of the declared pointer/array type of an entity.
std::optional< EntityName > getEntityName(const Decl *D)
Maps a declaration to an EntityName.
The JSON file list parser is used to communicate input to InstallAPI.
int const char * function
Definition c++config.h:31