25#include "llvm/ADT/STLExtras.h"
26#include "llvm/ADT/STLFunctionalExtras.h"
27#include "llvm/ADT/Sequence.h"
28#include "llvm/Support/Debug.h"
29#include "llvm/Support/Error.h"
41class PointerFlowMatcher {
45 TUSummaryExtractor &Extractor;
47 PointerFlowMatcher(ASTContext &Ctx, TUSummaryExtractor &Extractor)
48 : Ctx(Ctx), Extractor(Extractor) {}
50 llvm::Error
matches(
const DynTypedNode &DynNode,
const NamedDecl *RootDecl);
52 llvm::Error matchesInitializerList(
const ValueDecl *Base,
54 unsigned ArrayElementIndirectLevel = 0);
56 llvm::Error matchesStmt(
const Stmt *S,
const NamedDecl *RootDecl);
58 llvm::Error matchesDecl(
const Decl *D,
const NamedDecl *RootDecl);
63 Expected<EntityPointerLevelSet> toEPL(
const NamedDecl *N,
64 bool IsRet =
false)
const;
66 Expected<EntityPointerLevelSet> toEPL(
const Expr *N)
const;
68 llvm::Error addEdges(Expected<EntityPointerLevelSet> &&LHS,
69 Expected<EntityPointerLevelSet> &&RHS);
71 template <
typename ParmsProv
ider,
typename ArgsProv
ider>
72 llvm::Error matchesArgsWithParams(
unsigned ArgIdxStart, ParmsProvider *PP,
74 unsigned ArgIdx = ArgIdxStart;
76 for (
unsigned ParmIdx = 0;
77 ParmIdx < PP->getNumParams() && ArgIdx < AP->getNumArgs();
78 ++ArgIdx, ++ParmIdx) {
79 if (
const ParmVarDecl *PD = PP->getParamDecl(ParmIdx);
81 if (
auto Err = addEdges(toEPL(PD), toEPL(AP->getArg(ArgIdx))))
85 return llvm::Error::success();
91 auto Ret = createEntityPointerLevel(N, Extractor, IsRet);
94 return EntityPointerLevelSet{*
Ret};
95 return Ret.takeError();
98Expected<EntityPointerLevelSet> PointerFlowMatcher::toEPL(
const Expr *N)
const {
99 return translateEntityPointerLevel(N, Ctx, Extractor);
103PointerFlowMatcher::addEdges(Expected<EntityPointerLevelSet> &&LHS,
104 Expected<EntityPointerLevelSet> &&RHS) {
106 return llvm::joinErrors(LHS.takeError(), RHS.takeError());
108 return LHS.takeError();
110 return RHS.takeError();
112 return llvm::Error::success();
114 Results[L].insert(RHS->begin(), RHS->end());
115 return llvm::Error::success();
133llvm::Error PointerFlowMatcher::matches(
const DynTypedNode &DynNode,
134 const NamedDecl *RootDecl) {
135 if (
const Stmt *S = DynNode.
get<Stmt>())
136 return matchesStmt(S, RootDecl);
137 if (
const Decl *D = DynNode.
get<Decl>())
138 return matchesDecl(D, RootDecl);
139 return llvm::Error::success();
142llvm::Error PointerFlowMatcher::matchesStmt(
const Stmt *S,
143 const NamedDecl *RootDecl) {
145 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
147 return addEdges(toEPL(BO->getLHS()), toEPL(BO->getRHS()));
151 if (
const auto *CE = dyn_cast<CallExpr>(S)) {
152 const FunctionDecl *FD = CE->getDirectCallee();
155 return llvm::Error::success();
160 if (
auto *MD = dyn_cast<CXXMethodDecl>(FD);
161 MD && !MD->isExplicitObjectMemberFunction())
163 return matchesArgsWithParams(ArgIdx, FD, CE);
167 if (
const auto *CCE = dyn_cast<CXXConstructExpr>(S)) {
168 return matchesArgsWithParams(0, CCE->getConstructor(), CCE);
170 if (
const auto *RS = dyn_cast<ReturnStmt>(S)) {
171 const Expr *RetExpr = RS->getRetValue();
173 return llvm::Error::success();
174 return addEdges(toEPL(RootDecl,
true), toEPL(RetExpr));
176 return llvm::Error::success();
179llvm::Error PointerFlowMatcher::matchesDecl(
const Decl *D,
180 const NamedDecl *RootDecl) {
181 const Expr *InitExpr =
nullptr;
183 if (
const auto *VD = dyn_cast<ValueDecl>(D)) {
184 if (
const auto *Var = dyn_cast<VarDecl>(VD))
185 InitExpr = Var->getInit();
186 if (
const auto *Fd = dyn_cast<FieldDecl>(VD))
187 InitExpr = Fd->getInClassInitializer();
190 if (
auto *InitLst = dyn_cast_or_null<InitListExpr>(InitExpr))
191 return matchesInitializerList(VD, InitLst);
195 return addEdges(toEPL(VD), toEPL(InitExpr));
199 if (
const auto *CtorD = dyn_cast<CXXConstructorDecl>(D)) {
200 for (
auto *E : CtorD->inits()) {
201 if (E->isDelegatingInitializer())
202 return matches(DynTypedNode::create(*E->getInit()), RootDecl);
204 if (
auto Err = addEdges(toEPL(E->getMember()), toEPL(E->getInit())))
209 return llvm::Error::success();
213llvm::Error matchInitializerListForRecordDecl(PointerFlowMatcher &Matcher,
214 const RecordDecl *RecordTy,
215 const InitListExpr *ILE) {
216 if (
auto *CXXRD = dyn_cast<CXXRecordDecl>(RecordTy))
217 if (CXXRD->getNumBases() != 0) {
221 "attempt to create pointer assignment edges between "
222 "CXXRecordDecls with base classes and initializer-lists");
228 if (!InitField || ILE->
inits().empty())
229 return llvm::Error::success();
230 return Matcher.matchesInitializerList(InitField, ILE->
getInit(0));
239 if (
auto Err = Matcher.matchesInitializerList(*(FieldIter++),
Init))
241 return llvm::Error::success();
245llvm::Error matchInitializerListForArray(PointerFlowMatcher &Matcher,
246 const ValueDecl *
Array,
247 const InitListExpr *ILE,
248 unsigned ArrayIndirectLevel = 0) {
249 for (
auto *E : ILE->
inits())
251 Matcher.matchesInitializerList(
Array, E, ArrayIndirectLevel + 1))
253 return llvm::Error::success();
271PointerFlowMatcher::matchesInitializerList(
const ValueDecl *Base,
272 const Expr *InitExpr,
273 unsigned ArrayElementIndirectLevel) {
274 const InitListExpr *ILE = dyn_cast<InitListExpr>(InitExpr);
278 return llvm::Error::success();
280 auto BaseEPL = toEPL(Base);
283 return BaseEPL.takeError();
286 auto R = llvm::map_range(*BaseEPL, [&ArrayElementIndirectLevel](
287 const EntityPointerLevel &EPL) {
288 EntityPointerLevel
Result = EPL;
289 for ([[maybe_unused]]
auto Ignored : llvm::seq(ArrayElementIndirectLevel))
293 return addEdges(EntityPointerLevelSet{
R.begin(),
R.end()}, toEPL(InitExpr));
299 if (
auto *RD =
Type->getAsRecordDecl())
300 return matchInitializerListForRecordDecl(*
this, RD, ILE);
301 if (
Type->isArrayType())
302 return matchInitializerListForArray(*
this, Base, ILE,
303 ArrayElementIndirectLevel);
308 return llvm::Error::success();
309 return matchesInitializerList(Base, ILE->
getInit(0));
312class PointerFlowTUSummaryExtractor :
public TUSummaryExtractor {
314 PointerFlowTUSummaryExtractor(TUSummaryBuilder &Builder)
315 : TUSummaryExtractor(Builder) {}
318 std::unique_ptr<PointerFlowEntitySummary>
319 extractEntitySummary(
const NamedDecl *Contributor, ASTContext &Ctx,
320 TUSummaryExtractor &Extractor) {
321 PointerFlowMatcher Matcher(Ctx, Extractor);
322 auto MatchAction = [&Matcher, &Contributor](
const DynTypedNode &Node) {
323 auto Err = Matcher.matches(Node, Contributor);
330 return std::make_unique<PointerFlowEntitySummary>(
334 void HandleTranslationUnit(ASTContext &Ctx)
override {
335 std::vector<const NamedDecl *> Contributors;
338 for (
auto *CD : Contributors) {
339 auto EntitySummary = extractEntitySummary(CD, Ctx, *
this);
341 assert(EntitySummary);
342 if (EntitySummary->empty())
345 std::optional<EntityId> ContributorId = addEntity(CD);
346 if (!ContributorId) {
351 [[maybe_unused]]
auto [_, InsertionSucceeded] =
352 SummaryBuilder.addSummary(*ContributorId, std::move(EntitySummary));
354 assert(InsertionSucceeded &&
"duplicated contributor extraction");
360namespace clang::ssaf {
365static TUSummaryExtractorRegistry::Add<PointerFlowTUSummaryExtractor>
367 "Extract pointer flow information");
Defines the clang::ASTContext interface.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
Result
Implement __builtin_bit_cast and related operations.
C Language Family Type Representation.
const T * get() const
Retrieve the stored node as type T.
FieldDecl * getInitializedFieldInUnion()
If this initializes a union, specifies which field in the union to initialize.
unsigned getNumInits() const
bool isSemanticForm() const
InitListExpr * getSemanticForm() const
const Expr * getInit(unsigned Init) const
ArrayRef< Expr * > inits() const
This represents a decl that may have a name.
unsigned getNumFields() const
Returns the number of fields (non-static data members) in this record.
field_iterator field_begin() const
static constexpr llvm::StringLiteral Name
DynTypedNode DynTypedNode
bool InitField(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack 2) Peeks a pointer from the stack 3) Pushes the value to field I of ...
PRESERVE_NONE bool Ret(InterpState &S, CodePtr &PC)
void logWarningFromError(llvm::Error Err)
Log a warning from an llvm::Error.
llvm::Error makeErrAtNode(clang::ASTContext &Ctx, const NodeTy *N, llvm::StringRef Fmt, const Ts &...Args)
std::map< EntityPointerLevel, EntityPointerLevelSet > EdgeSet
Maps each LHS pointer (source / assignee) to the set of RHS pointers (destinations / assigned values)...
EntityPointerLevel incrementPointerLevel(const EntityPointerLevel &E)
An EntityPointerLevel is associated with a level of the declared pointer/array type of an entity.
void findContributors(ASTContext &Ctx, std::vector< const NamedDecl * > &Contributors)
Find all contributors in an AST.
llvm::Error makeEntityNameErr(clang::ASTContext &Ctx, const clang::NamedDecl *D)
void findMatchesIn(const NamedDecl *Contributor, llvm::function_ref< void(const DynTypedNode &)> MatchActionRef)
Perform "MatchAction" on each Stmt and Decl belonging to the Contributor.
PointerFlowEntitySummary buildPointerFlowEntitySummary(EdgeSet Edges)
volatile int PointerFlowExtractorAnchorSource
bool hasPtrOrArrType(const DeclOrExpr *E)
bool matches(const til::SExpr *E1, const til::SExpr *E2)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
@ Type
The name was classified as a type.
int const char * function