clang: lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
21#include "llvm/ADT/SetOperations.h"
22#include "llvm/ADT/SetVector.h"
23#include "llvm/Support/CommandLine.h"
24#include "llvm/Support/Debug.h"
25#include "llvm/Support/FileSystem.h"
26#include "llvm/Support/Path.h"
27#include "llvm/Support/raw_ostream.h"
28#include
29#include
30#include
31#include
32#include
33
35 "dataflow-log", llvm:🆑:Hidden, llvm:🆑:ValueOptional,
36 llvm:🆑:desc("Emit log of dataflow analysis. With no arg, writes textual "
37 "log to stderr. With an arg, writes HTML logs under the "
38 "specified directory (one per analyzed function)."));
39
41namespace dataflow {
42
44
45
46
47
48
49
50
51 if (Opts.ContextSensitiveOpts)
53
55}
56
57void DataflowAnalysisContext::addModeledFields(const FieldSet &Fields) {
58 ModeledFields.set_union(Fields);
59}
60
63 llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
65 if (Field->getType()->isReferenceType())
66 FieldLocs.insert({Field, nullptr});
67 else
69 Field->getType().getNonReferenceType())});
70
73 SyntheticFields.insert(
74 {Entry.getKey(),
76
78 std::move(SyntheticFields));
79 }
81}
82
83
84
85template
86static llvm::DenseSetllvm::StringRef getKeys(const llvm::StringMap &Map) {
87 return llvm::DenseSetllvm::StringRef(llvm::from_range, Map.keys());
88}
89
96
97 RecordStorageLocationCreated = true;
99 std::move(SyntheticFields));
100}
101
104 if (auto *Loc = DeclToLoc.lookup(&D))
105 return *Loc;
107 DeclToLoc[&D] = &Loc;
108 return Loc;
109}
110
114
115 if (auto *Loc = ExprToLoc.lookup(&CanonE))
116 return *Loc;
118 ExprToLoc[&CanonE] = &Loc;
119 return Loc;
120}
121
124 auto CanonicalPointeeType =
126 auto Res = NullPointerVals.try_emplace(CanonicalPointeeType, nullptr);
127 if (Res.second) {
130 }
131 return *Res.first->second;
132}
133
140
143 auto Res = FlowConditionConstraints.try_emplace(Token, &Constraint);
144 if (!Res.second) {
145 Res.first->second =
146 &arena().makeAnd(*Res.first->second, Constraint);
147 }
148}
149
152 FlowConditionDeps[ForkToken].insert(Token);
154 return ForkToken;
155}
156
159 Atom SecondToken) {
161 auto &TokenDeps = FlowConditionDeps[Token];
162 TokenDeps.insert(FirstToken);
163 TokenDeps.insert(SecondToken);
165 arena().makeOr(arena().makeAtomRef(FirstToken),
166 arena().makeAtomRef(SecondToken)));
168}
169
171 llvm::SetVector<const Formula *> Constraints) {
172 return S.solve(Constraints.getArrayRef());
173}
174
178 return true;
179
180
181
182
183
184
185 llvm::SetVector<const Formula *> Constraints;
186 Constraints.insert(&arena().makeAtomRef(Token));
187 Constraints.insert(&arena().makeNot(F));
188 addTransitiveFlowConditionConstraints(Token, Constraints);
189 return isUnsatisfiable(std::move(Constraints));
190}
191
195 return false;
196
197 llvm::SetVector<const Formula *> Constraints;
198 Constraints.insert(&arena().makeAtomRef(Token));
199 Constraints.insert(&F);
200 addTransitiveFlowConditionConstraints(Token, Constraints);
201 return isSatisfiable(std::move(Constraints));
202}
203
206 llvm::SetVector<const Formula *> Constraints;
207 Constraints.insert(&arena().makeNot(arena().makeEquals(Val1, Val2)));
208 return isUnsatisfiable(std::move(Constraints));
209}
210
211llvm::DenseSet DataflowAnalysisContext::collectDependencies(
212 llvm::DenseSet Tokens) const {
213
214
215 std::vector Remaining(Tokens.begin(), Tokens.end());
216 while (!Remaining.empty()) {
217 Atom CurrentToken = Remaining.back();
218 Remaining.pop_back();
219 if (auto DepsIt = FlowConditionDeps.find(CurrentToken);
220 DepsIt != FlowConditionDeps.end())
221 for (Atom A : DepsIt->second)
222 if (Tokens.insert(A).second)
223 Remaining.push_back(A);
224 }
225
226 return Tokens;
227}
228
229void DataflowAnalysisContext::addTransitiveFlowConditionConstraints(
230 Atom Token, llvm::SetVector<const Formula *> &Constraints) {
231 llvm::DenseSet AddedTokens;
232 std::vector Remaining = {Token};
233
236
237 while (!Remaining.empty()) {
238 auto Token = Remaining.back();
239 Remaining.pop_back();
240 if (!AddedTokens.insert(Token).second)
241 continue;
242
243 auto ConstraintsIt = FlowConditionConstraints.find(Token);
244 if (ConstraintsIt == FlowConditionConstraints.end()) {
245
246
247 Constraints.insert(&arena().makeAtomRef(Token));
248 } else {
249
250
251 Constraints.insert(&arena().makeEquals(arena().makeAtomRef(Token),
252 *ConstraintsIt->second));
253 }
254
255 if (auto DepsIt = FlowConditionDeps.find(Token);
256 DepsIt != FlowConditionDeps.end())
257 for (Atom A : DepsIt->second)
258 Remaining.push_back(A);
259 }
260}
261
263 llvm::DenseSetdataflow::Atom &Refs) {
264 switch (F.kind()) {
266 Refs.insert(F.getAtom());
267 break;
269 break;
272 break;
280 break;
281 }
282}
283
285 llvm::DenseSetdataflow::Atom TargetTokens) const {
287
288
292
293 llvm::DenseSetdataflow::Atom Dependencies =
294 collectDependencies(std::move(TargetTokens));
295
297
298
299 const Formula *Constraints = FlowConditionConstraints.lookup(Token);
300 if (Constraints == nullptr)
301 continue;
303
304 if (auto DepsIt = FlowConditionDeps.find(Token);
305 DepsIt != FlowConditionDeps.end())
307 }
308
309 return LC;
310}
311
314 FlowConditionConstraints = std::move(LC.TokenDefs);
315
316
317
318 FlowConditionDeps = std::move(LC.TokenDeps);
319}
320
322 llvm::raw_ostream &OS) {
323 OS << "(";
324 for (size_t i = 0; i < Atoms.size(); ++i) {
325 OS << Atoms[i];
326 if (i + 1 < Atoms.size())
327 OS << ", ";
328 }
329 OS << ")\n";
330}
331
333 llvm::raw_ostream &OS) {
334 llvm::SetVector<const Formula *> Constraints;
335 Constraints.insert(&arena().makeAtomRef(Token));
336 addTransitiveFlowConditionConstraints(Token, Constraints);
337
338 OS << "Flow condition token: " << Token << "\n";
340 llvm::SetVector<const Formula *> OriginalConstraints = Constraints;
342 if (!Constraints.empty()) {
343 OS << "Constraints:\n";
344 for (const auto *Constraint : Constraints) {
345 Constraint->print(OS);
346 OS << "\n";
347 }
348 }
350 OS << "True atoms: ";
352 }
354 OS << "False atoms: ";
356 }
358 OS << "Equivalent atoms:\n";
361 }
362
363 OS << "\nFlow condition constraints before simplification:\n";
364 for (const auto *Constraint : OriginalConstraints) {
365 Constraint->print(OS);
366 OS << "\n";
367 }
368}
369
372
374 if (F == nullptr)
375 return nullptr;
376 auto It = FunctionContexts.find(F);
377 if (It != FunctionContexts.end())
378 return &It->second;
379
382
383 assert(ACFG);
384 auto Result = FunctionContexts.insert({F, std::move(*ACFG)});
385 return &Result.first->second;
386 }
387
388 return nullptr;
389}
390
394
396 if (auto EC = llvm::sys::fs::create_directories(Dir))
397 llvm::errs() << "Failed to create log dir: " << EC.message() << "\n";
398
399
400
401 static std::atomic Counter = {0};
402 auto StreamFactory =
403 [Dir(Dir.str())]() mutable -> std::unique_ptrllvm::raw\_ostream {
405 llvm::sys::path::append(File,
406 std::to_string(Counter.fetch_add(1)) + ".html");
407 std::error_code EC;
408 auto OS = std::make_uniquellvm::raw\_fd\_ostream(File, EC);
409 if (EC) {
410 llvm::errs() << "Failed to create log " << File << ": " << EC.message()
411 << "\n";
412 return std::make_uniquellvm::raw\_null\_ostream();
413 }
414 return OS;
415 };
416 return Logger::html(std::move(StreamFactory));
417}
418
420 Solver &S, std::unique_ptr &&OwnedSolver, Options Opts)
421 : S(S), OwnedSolver(std::move(OwnedSolver)), A(std::make_unique()),
422 Opts(Opts) {
423
424
425
426 if (Opts.Log == nullptr) {
427 if (DataflowLog.getNumOccurrences() > 0) {
428 LogOwner = makeLoggerFromCommandLine();
429 this->Opts.Log = LogOwner.get();
430
431 } else {
432 this->Opts.Log = &Logger::null();
433 }
434 }
435}
436
437DataflowAnalysisContext::~DataflowAnalysisContext() = default;
438
439}
440}
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)."))
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 getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
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.
static llvm::Expected< AdornedCFG > build(const FunctionDecl &Func)
Builds an AdornedCFG from a FunctionDecl.
Atom makeFlowConditionToken()
Creates a fresh flow condition and returns a token that identifies it.
const Formula & makeAnd(const Formula &LHS, const Formula &RHS)
Returns a formula for the conjunction of LHS and RHS.
std::enable_if_t< std::is_base_of< StorageLocation, T >::value, T & > create(Args &&...args)
Creates a T (some subclass of StorageLocation), forwarding args to the constructor,...
const AdornedCFG * getAdornedCFG(const FunctionDecl *F)
Returns the AdornedCFG registered for F, if any.
Definition DataflowAnalysisContext.cpp:371
DataflowAnalysisContext(std::unique_ptr< Solver > S, Options Opts=Options{ std::nullopt, nullptr})
Constructs a dataflow analysis context.
Atom joinFlowConditions(Atom FirstToken, Atom SecondToken)
Creates a new flow condition that represents the disjunction of the flow conditions identified by Fir...
Definition DataflowAnalysisContext.cpp:158
void addFlowConditionConstraint(Atom Token, const Formula &Constraint)
Adds Constraint to the flow condition identified by Token.
Definition DataflowAnalysisContext.cpp:141
Atom forkFlowCondition(Atom Token)
Creates a new flow condition with the same constraints as the flow condition identified by Token and ...
Definition DataflowAnalysisContext.cpp:150
bool equivalentFormulas(const Formula &Val1, const Formula &Val2)
Returns true if Val1 is equivalent to Val2.
Definition DataflowAnalysisContext.cpp:204
StorageLocation & getStableStorageLocation(const ValueDecl &D)
Returns a stable storage location for D.
Definition DataflowAnalysisContext.cpp:103
bool flowConditionImplies(Atom Token, const Formula &F)
Returns true if the constraints of the flow condition identified by Token imply that F is true.
Definition DataflowAnalysisContext.cpp:175
Solver::Result querySolver(llvm::SetVector< const Formula * > Constraints)
Returns the outcome of satisfiability checking on Constraints.
Definition DataflowAnalysisContext.cpp:170
bool flowConditionAllows(Atom Token, const Formula &F)
Returns true if the constraints of the flow condition identified by Token still allow F to be true.
Definition DataflowAnalysisContext.cpp:192
PointerValue & getOrCreateNullPointerValue(QualType PointeeType)
Returns a pointer value that represents a null pointer.
Definition DataflowAnalysisContext.cpp:123
void addInvariant(const Formula &Constraint)
Adds Constraint to current and future flow conditions in this context.
Definition DataflowAnalysisContext.cpp:134
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.
Definition DataflowAnalysisContext.cpp:61
SimpleLogicalContext exportLogicalContext(llvm::DenseSet< dataflow::Atom > TargetTokens) const
Export the logical-context portions of AC, limited to the given target flow-condition tokens.
Definition DataflowAnalysisContext.cpp:284
FieldSet getModeledFields(QualType Type)
Returns the fields of Type, limited to the set of fields modeled by this context.
Definition DataflowAnalysisContext.cpp:43
LLVM_DUMP_METHOD void dumpFlowCondition(Atom Token, llvm::raw_ostream &OS=llvm::dbgs())
Definition DataflowAnalysisContext.cpp:332
void initLogicalContext(SimpleLogicalContext LC)
Initializes this context's "logical" components with LC.
Definition DataflowAnalysisContext.cpp:312
RecordStorageLocation & createRecordStorageLocation(QualType Type, RecordStorageLocation::FieldToLoc FieldLocs, RecordStorageLocation::SyntheticFieldMap SyntheticFields)
Creates a RecordStorageLocation for the given type and with the given fields.
Definition DataflowAnalysisContext.cpp:90
ArrayRef< const Formula * > operands() const
bool isLiteral(bool b) const
@ Equal
True if LHS is false or RHS is true.
@ Implies
True if either LHS or RHS is true.
@ AtomRef
A reference to an atomic boolean variable.
@ Literal
Constant true or false.
@ Or
True if LHS and RHS are both true.
@ And
True if its only operand is false.
static std::unique_ptr< Logger > textual(llvm::raw_ostream &)
A logger that simply writes messages to the specified ostream in real time.
static std::unique_ptr< Logger > html(std::function< std::unique_ptr< llvm::raw_ostream >()>)
A logger that builds an HTML UI to inspect the analysis results.
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.
static void getReferencedAtoms(const Formula &F, llvm::DenseSet< dataflow::Atom > &Refs)
Definition DataflowAnalysisContext.cpp:262
Atom
Identifies an atomic boolean variable such as "V1".
static void printAtomList(const llvm::SmallVector< Atom > &Atoms, llvm::raw_ostream &OS)
Definition DataflowAnalysisContext.cpp:321
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()
Definition DataflowAnalysisContext.cpp:391
static llvm::DenseSet< llvm::StringRef > getKeys(const llvm::StringMap< T > &Map)
Definition DataflowAnalysisContext.cpp:86
bool containsSameFields(const FieldSet &Fields, const RecordStorageLocation::FieldToLoc &FieldLocs)
Returns whether Fields and FieldLocs contain the same fields.
llvm::SmallSetVector< const FieldDecl *, 4 > FieldSet
A set of FieldDecl *.
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.
A simple representation of essential elements of the logical context used in environments.
llvm::DenseMap< Atom, const Formula * > TokenDefs
const Formula * Invariant
llvm::DenseMap< Atom, llvm::DenseSet< Atom > > TokenDeps
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.