clang 23.0.0git
UnsafeBufferUsageExtractor.cpp
Go to the documentation of this file.
1//===- UnsafeBufferUsageExtractor.cpp -------------------------------------===//
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
12#include "clang/AST/Decl.h"
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/iterator_range.h"
20#include "llvm/Support/Error.h"
21#include <memory>
22
23namespace {
24using namespace clang;
25using namespace ssaf;
26
27static llvm::Error makeCreateEntityNameError(const NamedDecl *FailedDecl,
28 ASTContext &Ctx) {
29 std::string LocStr = FailedDecl->getSourceRange().getBegin().printToString(
30 Ctx.getSourceManager());
31 return llvm::createStringError(
32 "failed to create entity name for %s declared at %s",
33 FailedDecl->getNameAsString().c_str(), LocStr.c_str());
34}
35
36static llvm::Error makeAddEntitySummaryError(const NamedDecl *FailedContributor,
37 ASTContext &Ctx) {
38 std::string LocStr =
39 FailedContributor->getSourceRange().getBegin().printToString(
40 Ctx.getSourceManager());
41 return llvm::createStringError(
42 "failed to add entity summary for contributor %s declared at %s",
43 FailedContributor->getNameAsString().c_str(), LocStr.c_str());
44}
45
47buildEntityPointerLevels(std::set<const Expr *> &&UnsafePointers,
49 ASTContext &Ctx,
50 std::function<EntityId(EntityName)> AddEntity) {
51 EntityPointerLevelSet Result{};
52 llvm::Error AllErrors = llvm::ErrorSuccess();
53
54 for (const Expr *Ptr : UnsafePointers) {
56 translateEntityPointerLevel(Ptr, Ctx, AddEntity);
57
58 if (Translation) {
59 // Filter out those temporary invalid EntityPointerLevels associated with
60 // `&E` pointers:
61 auto FilteredTranslation = llvm::make_filter_range(
62 *Translation, [](const EntityPointerLevel &E) -> bool {
63 return E.getPointerLevel() > 0;
64 });
65 Result.insert(FilteredTranslation.begin(), FilteredTranslation.end());
66 continue;
67 }
68 AllErrors = llvm::joinErrors(std::move(AllErrors), Translation.takeError());
69 }
70 if (AllErrors)
71 return AllErrors;
72 return Result;
73}
74} // namespace
75
76static std::set<const Expr *> findUnsafePointersInContributor(const Decl *D) {
78 return findUnsafePointers(D);
79 if (auto *RD = dyn_cast<RecordDecl>(D)) {
80 std::set<const Expr *> Result;
81
82 for (const FieldDecl *FD : RD->fields()) {
83 Result.merge(findUnsafePointers(FD));
84 }
85 return Result;
86 }
87 return {};
88}
89
90std::unique_ptr<UnsafeBufferUsageEntitySummary>
92 const Decl *Contributor, ASTContext &Ctx, llvm::Error &Error) {
93 auto AddEntity = [this](EntityName EN) { return addEntity(EN); };
94 Expected<EntityPointerLevelSet> EPLs = buildEntityPointerLevels(
95 findUnsafePointersInContributor(Contributor), *this, Ctx, AddEntity);
96
97 if (EPLs)
98 return std::make_unique<UnsafeBufferUsageEntitySummary>(
99 UnsafeBufferUsageEntitySummary(std::move(*EPLs)));
100 Error = EPLs.takeError();
101 return nullptr;
102}
103
105 ASTContext &Ctx) {
106
107 // FIXME: I suppose finding contributor Decls is commonly needed by all/many
108 // extractors
109 class ContributorFinder : public DynamicRecursiveASTVisitor {
110 public:
111 std::vector<const NamedDecl *> Contributors;
112
113 bool VisitFunctionDecl(FunctionDecl *D) override {
114 Contributors.push_back(D);
115 return true;
116 }
117
118 bool VisitRecordDecl(RecordDecl *D) override {
119 Contributors.push_back(D);
120 return true;
121 }
122
123 bool VisitVarDecl(VarDecl *D) override {
124 DeclContext *DC = D->getDeclContext();
125
126 if (DC->isFileContext() || DC->isNamespace())
127 Contributors.push_back(D);
128 return false;
129 }
130 } ContributorFinder;
131
132 ContributorFinder.VisitTranslationUnitDecl(Ctx.getTranslationUnitDecl());
133
134 llvm::Error Errors = llvm::ErrorSuccess();
135 auto addError = [&Errors](llvm::Error Err) {
136 Errors = llvm::joinErrors(std::move(Errors), std::move(Err));
137 };
138
139 for (auto *CD : ContributorFinder.Contributors) {
140 llvm::Error Error = llvm::ErrorSuccess();
142
143 if (Error)
144 addError(std::move(Error));
145 if (EntitySummary->empty())
146 continue;
147
148 auto ContributorName = getEntityName(CD);
149
150 if (!ContributorName) {
151 addError(makeCreateEntityNameError(CD, Ctx));
152 continue;
153 }
154
155 auto [EntitySummaryPtr, Success] = SummaryBuilder.addSummary(
156 addEntity(*ContributorName), std::move(EntitySummary));
157
158 if (!Success)
159 addError(makeAddEntitySummaryError(CD, Ctx));
160 }
161 // FIXME: handle errors!
162 llvm::consumeError(std::move(Errors));
163}
Defines the clang::ASTContext interface.
static llvm::Error makeCreateEntityNameError(const NamedDecl *FailedDecl, ASTContext &Ctx)
static std::set< const Expr * > findUnsafePointersInContributor(const Decl *D)
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
TranslationUnitDecl * getTranslationUnitDecl() const
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1462
bool isFileContext() const
Definition DeclBase.h:2193
bool isNamespace() const
Definition DeclBase.h:2211
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
DeclContext * getDeclContext()
Definition DeclBase.h:456
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
Definition DeclBase.h:435
This represents one expression.
Definition Expr.h:112
Represents a member of a struct/union/class.
Definition Decl.h:3175
Represents a function declaration or definition.
Definition Decl.h:2015
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
Represents a struct/union/class.
Definition Decl.h:4342
std::string printToString(const SourceManager &SM) const
SourceLocation getBegin() const
Represents a variable declaration or definition.
Definition Decl.h:926
Lightweight opaque handle representing an entity in an EntityIdTable.
Definition EntityId.h:31
Uniquely identifies an entity in a program.
Definition EntityName.h:28
Base class for analysis-specific summary data.
An UnsafeBufferUsageEntitySummary is an immutable set of unsafe buffers, in the form of EntityPointer...
void HandleTranslationUnit(ASTContext &Ctx) override
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
std::unique_ptr< UnsafeBufferUsageEntitySummary > extractEntitySummary(const Decl *Contributor, ASTContext &Ctx, llvm::Error &Error)
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.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ Success
Annotation was successful.
Definition Parser.h:65
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
std::set< const Expr * > findUnsafePointers(const Decl *D)
Find unsafe pointers in body/initializer of D, if D is one of the followings: VarDecl FieldDecl Funct...
int const char * function
Definition c++config.h:31