clang: lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
23#include "llvm/ADT/SetOperations.h"
24#include "llvm/ADT/SetVector.h"
25#include "llvm/Support/CommandLine.h"
26#include "llvm/Support/Debug.h"
27#include "llvm/Support/FileSystem.h"
28#include "llvm/Support/Path.h"
29#include "llvm/Support/raw_ostream.h"
30#include
31#include
32#include
33#include
34#include
35
37 "dataflow-log", llvm:🆑:Hidden, llvm:🆑:ValueOptional,
38 llvm:🆑:desc("Emit log of dataflow analysis. With no arg, writes textual "
39 "log to stderr. With an arg, writes HTML logs under the "
40 "specified directory (one per analyzed function)."));
41
43namespace dataflow {
44
46
47
48
49
50
51
52
55
57}
58
59void DataflowAnalysisContext::addModeledFields(const FieldSet &Fields) {
60 ModeledFields.set_union(Fields);
61}
62
65 llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
67 if (Field->getType()->isReferenceType())
68 FieldLocs.insert({Field, nullptr});
69 else
71 Field->getType().getNonReferenceType())});
72
75 SyntheticFields.insert(
76 {Entry.getKey(),
78
80 std::move(SyntheticFields));
81 }
83}
84
85
86
87template
88static llvm::DenseSetllvm::StringRef getKeys(const llvm::StringMap &Map) {
89 return llvm::DenseSetllvm::StringRef(Map.keys().begin(), Map.keys().end());
90}
91
97 assert(getKeys(getSyntheticFields(Type)) == getKeys(SyntheticFields));
98
99 RecordStorageLocationCreated = true;
101 std::move(SyntheticFields));
102}
103
105DataflowAnalysisContext::getStableStorageLocation(const ValueDecl &D) {
106 if (auto *Loc = DeclToLoc.lookup(&D))
107 return *Loc;
108 auto &Loc = createStorageLocation(D.getType().getNonReferenceType());
110 return Loc;
111}
112
114DataflowAnalysisContext::getStableStorageLocation(const Expr &E) {
116
117 if (auto *Loc = ExprToLoc.lookup(&CanonE))
118 return *Loc;
119 auto &Loc = createStorageLocation(CanonE.getType());
120 ExprToLoc[&CanonE] = &Loc;
121 return Loc;
122}
123
125DataflowAnalysisContext::getOrCreateNullPointerValue(QualType PointeeType) {
126 auto CanonicalPointeeType =
128 auto Res = NullPointerVals.try_emplace(CanonicalPointeeType, nullptr);
129 if (Res.second) {
130 auto &PointeeLoc = createStorageLocation(CanonicalPointeeType);
131 Res.first->second = &arena().create<PointerValue>(PointeeLoc);
132 }
133 return *Res.first->second;
134}
135
136void DataflowAnalysisContext::addInvariant(const Formula &Constraint) {
139 else
141}
142
143void DataflowAnalysisContext::addFlowConditionConstraint(
145 auto Res = FlowConditionConstraints.try_emplace(Token, &Constraint);
146 if (!Res.second) {
147 Res.first->second =
148 &arena().makeAnd(*Res.first->second, Constraint);
149 }
150}
151
153 Atom ForkToken = arena().makeFlowConditionToken();
154 FlowConditionDeps[ForkToken].insert(Token);
155 addFlowConditionConstraint(ForkToken, arena().makeAtomRef(Token));
156 return ForkToken;
157}
158
160DataflowAnalysisContext::joinFlowConditions(Atom FirstToken,
161 Atom SecondToken) {
162 Atom Token = arena().makeFlowConditionToken();
163 FlowConditionDeps[Token].insert(FirstToken);
164 FlowConditionDeps[Token].insert(SecondToken);
165 addFlowConditionConstraint(Token,
166 arena().makeOr(arena().makeAtomRef(FirstToken),
167 arena().makeAtomRef(SecondToken)));
169}
170
172 llvm::SetVector<const Formula *> Constraints) {
173 return S.solve(Constraints.getArrayRef());
174}
175
176bool DataflowAnalysisContext::flowConditionImplies(Atom Token,
179 return true;
180
181
182
183
184
185
186 llvm::SetVector<const Formula *> Constraints;
187 Constraints.insert(&arena().makeAtomRef(Token));
188 Constraints.insert(&arena().makeNot(F));
189 addTransitiveFlowConditionConstraints(Token, Constraints);
190 return isUnsatisfiable(std::move(Constraints));
191}
192
193bool DataflowAnalysisContext::flowConditionAllows(Atom Token,
196 return false;
197
198 llvm::SetVector<const Formula *> Constraints;
199 Constraints.insert(&arena().makeAtomRef(Token));
200 Constraints.insert(&F);
201 addTransitiveFlowConditionConstraints(Token, Constraints);
202 return isSatisfiable(std::move(Constraints));
203}
204
205bool DataflowAnalysisContext::equivalentFormulas(const Formula &Val1,
207 llvm::SetVector<const Formula *> Constraints;
208 Constraints.insert(&arena().makeNot(arena().makeEquals(Val1, Val2)));
209 return isUnsatisfiable(std::move(Constraints));
210}
211
212void DataflowAnalysisContext::addTransitiveFlowConditionConstraints(
213 Atom Token, llvm::SetVector<const Formula *> &Constraints) {
214 llvm::DenseSet AddedTokens;
215 std::vector Remaining = {Token};
216
219
220 while (!Remaining.empty()) {
221 auto Token = Remaining.back();
222 Remaining.pop_back();
223 if (!AddedTokens.insert(Token).second)
224 continue;
225
226 auto ConstraintsIt = FlowConditionConstraints.find(Token);
227 if (ConstraintsIt == FlowConditionConstraints.end()) {
228 Constraints.insert(&arena().makeAtomRef(Token));
229 } else {
230
231
232 Constraints.insert(&arena().makeEquals(arena().makeAtomRef(Token),
233 *ConstraintsIt->second));
234 }
235
236 if (auto DepsIt = FlowConditionDeps.find(Token);
237 DepsIt != FlowConditionDeps.end())
238 for (Atom A : DepsIt->second)
239 Remaining.push_back(A);
240 }
241}
242
244 llvm::raw_ostream &OS) {
245 OS << "(";
246 for (size_t i = 0; i < Atoms.size(); ++i) {
247 OS << Atoms[i];
248 if (i + 1 < Atoms.size())
249 OS << ", ";
250 }
251 OS << ")\n";
252}
253
254void DataflowAnalysisContext::dumpFlowCondition(Atom Token,
255 llvm::raw_ostream &OS) {
256 llvm::SetVector<const Formula *> Constraints;
257 Constraints.insert(&arena().makeAtomRef(Token));
258 addTransitiveFlowConditionConstraints(Token, Constraints);
259
260 OS << "Flow condition token: " << Token << "\n";
262 llvm::SetVector<const Formula *> OriginalConstraints = Constraints;
264 if (!Constraints.empty()) {
265 OS << "Constraints:\n";
266 for (const auto *Constraint : Constraints) {
267 Constraint->print(OS);
268 OS << "\n";
269 }
270 }
272 OS << "True atoms: ";
274 }
276 OS << "False atoms: ";
278 }
280 OS << "Equivalent atoms:\n";
283 }
284
285 OS << "\nFlow condition constraints before simplification:\n";
286 for (const auto *Constraint : OriginalConstraints) {
287 Constraint->print(OS);
288 OS << "\n";
289 }
290}
291
293DataflowAnalysisContext::getAdornedCFG(const FunctionDecl *F) {
294
296 if (F == nullptr)
297 return nullptr;
298 auto It = FunctionContexts.find(F);
299 if (It != FunctionContexts.end())
300 return &It->second;
301
303 auto ACFG = AdornedCFG::build(*F);
304
305 assert(ACFG);
306 auto Result = FunctionContexts.insert({F, std::move(*ACFG)});
307 return &Result.first->second;
308 }
309
310 return nullptr;
311}
312
315 return Logger::textual(llvm::errs());
316
318 if (auto EC = llvm::sys::fs::create_directories(Dir))
319 llvm::errs() << "Failed to create log dir: " << EC.message() << "\n";
320
321
322
323 static std::atomic Counter = {0};
324 auto StreamFactory =
325 [Dir(Dir.str())]() mutable -> std::unique_ptrllvm::raw\_ostream {
327 llvm::sys::path::append(File,
328 std::to_string(Counter.fetch_add(1)) + ".html");
329 std::error_code EC;
330 auto OS = std::make_uniquellvm::raw\_fd\_ostream(File, EC);
331 if (EC) {
332 llvm::errs() << "Failed to create log " << File << ": " << EC.message()
333 << "\n";
334 return std::make_uniquellvm::raw\_null\_ostream();
335 }
336 return OS;
337 };
338 return Logger::html(std::move(StreamFactory));
339}
340
341DataflowAnalysisContext::DataflowAnalysisContext(
342 Solver &S, std::unique_ptr &&OwnedSolver, Options Opts)
343 : S(S), OwnedSolver(std::move(OwnedSolver)), A(std::make_unique()),
344 Opts(Opts) {
345
346
347
348 if (Opts.Log == nullptr) {
349 if (DataflowLog.getNumOccurrences() > 0) {
351 this->Opts.Log = LogOwner.get();
352
353 } else {
355 }
356 }
357}
358
359DataflowAnalysisContext::~DataflowAnalysisContext() = default;
360
361}
362}
static llvm:🆑:opt< std::string > DataflowLog("dataflow-log", llvm:🆑:Hidden, llvm:🆑:ValueOptional, llvm:🆑:desc("Emit log of dataflow analysis. With no arg, writes textual " "log to stderr. With an arg, writes HTML logs under the " "specified directory (one per analyzed function)."))
Defines the clang::Expr interface and subclasses for C++ expressions.
This represents one expression.
Represents a member of a struct/union/class.
Represents a function declaration or definition.
bool doesThisDeclarationHaveABody() const
Returns whether this specific declaration of the function has a body.
FunctionDecl * getDefinition()
Get the definition for this declaration.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
QualType getCanonicalType() const
Token - This structure provides full information about a lexed token.
The base class of the type hierarchy.
bool isRecordType() const
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Holds CFG with additional information derived from it that is needed to perform dataflow analysis.
llvm::StringMap< QualType > getSyntheticFields(QualType Type)
Returns the names and types of the synthetic fields for the given record type.
StorageLocation & createStorageLocation(QualType Type)
Returns a new storage location appropriate for Type.
FieldSet getModeledFields(QualType Type)
Returns the fields of Type, limited to the set of fields modeled by this context.
RecordStorageLocation & createRecordStorageLocation(QualType Type, RecordStorageLocation::FieldToLoc FieldLocs, RecordStorageLocation::SyntheticFieldMap SyntheticFields)
Creates a RecordStorageLocation for the given type and with the given fields.
bool isLiteral(bool b) const
static Logger & null()
Returns a dummy logger that does nothing.
Models a symbolic pointer. Specifically, any value of type T*.
A storage location for a record (struct, class, or union).
llvm::DenseMap< const ValueDecl *, StorageLocation * > FieldToLoc
llvm::StringMap< StorageLocation * > SyntheticFieldMap
A storage location that is not subdivided further for the purposes of abstract interpretation.
Base class for elements of the local variable store and of the heap.
Atom
Identifies an atomic boolean variable such as "V1".
static void printAtomList(const llvm::SmallVector< Atom > &Atoms, llvm::raw_ostream &OS)
void simplifyConstraints(llvm::SetVector< const Formula * > &Constraints, Arena &arena, SimplifyConstraintsInfo *Info=nullptr)
Simplifies a set of constraints (implicitly connected by "and") in a way that does not change satisfi...
const Expr & ignoreCFGOmittedNodes(const Expr &E)
Skip past nodes that the CFG does not emit.
FieldSet getObjectFields(QualType Type)
Returns the set of all fields in the type.
static std::unique_ptr< Logger > makeLoggerFromCommandLine()
static llvm::DenseSet< llvm::StringRef > getKeys(const llvm::StringMap< T > &Map)
bool containsSameFields(const FieldSet &Fields, const RecordStorageLocation::FieldToLoc &FieldLocs)
Returns whether Fields and FieldLocs contain the same fields.
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
@ Invariant
The parameter is invariant: must match exactly.
@ Class
The "class" keyword introduces the elaborated-type-specifier.
std::optional< ContextSensitiveOptions > ContextSensitiveOpts
Options for analyzing function bodies when present in the translation unit, or empty to disable conte...
Information on the way a set of constraints was simplified.
llvm::SmallVector< Atom > TrueAtoms
Atoms that the original constraints imply must be true.
llvm::SmallVector< llvm::SmallVector< Atom > > EquivalentAtoms
List of equivalence classes of atoms.
llvm::SmallVector< Atom > FalseAtoms
Atoms that the original constraints imply must be false.