20#include "llvm/ADT/SetOperations.h"
21#include "llvm/Support/CommandLine.h"
22#include "llvm/Support/Debug.h"
23#include "llvm/Support/FileSystem.h"
24#include "llvm/Support/Path.h"
30 "dataflow-log", llvm::cl::Hidden, llvm::cl::ValueOptional,
31 llvm::cl::desc(
"Emit log of dataflow analysis. With no arg, writes textual "
32 "log to stderr. With an arg, writes HTML logs under the "
33 "specified directory (one per analyzed function)."));
38void DataflowAnalysisContext::addModeledFields(
40 llvm::set_union(ModeledFields, Fields);
44DataflowAnalysisContext::getReferencedFields(
QualType Type) {
46 llvm::set_intersect(Fields, ModeledFields);
52 llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
61 : getReferencedFields(
Type);
89 auto CanonicalPointeeType =
91 auto Res = NullPointerVals.try_emplace(CanonicalPointeeType,
nullptr);
96 return *Res.first->second;
101 auto Res = FlowConditionConstraints.try_emplace(&
Token, &Constraint);
111 FlowConditionDeps[&ForkToken].insert(&
Token);
120 FlowConditionDeps[&
Token].insert(&FirstToken);
121 FlowConditionDeps[&
Token].insert(&SecondToken);
123 Token,
arena().makeOr(FirstToken, SecondToken));
129 Constraints.insert(&
arena().makeLiteral(
true));
131 &
arena().makeNot(
arena().makeLiteral(
false)));
132 return S->solve(std::move(Constraints));
145 addTransitiveFlowConditionConstraints(
Token, Constraints, VisitedTokens);
146 return isUnsatisfiable(std::move(Constraints));
155 addTransitiveFlowConditionConstraints(
Token, Constraints, VisitedTokens);
156 return isUnsatisfiable(std::move(Constraints));
163 return isUnsatisfiable(Constraints);
166void DataflowAnalysisContext::addTransitiveFlowConditionConstraints(
169 auto Res = VisitedTokens.insert(&
Token);
173 auto ConstraintsIt = FlowConditionConstraints.find(&
Token);
174 if (ConstraintsIt == FlowConditionConstraints.end()) {
175 Constraints.insert(&
Token);
179 Constraints.insert(&
arena().makeEquals(
Token, *ConstraintsIt->second));
182 auto DepsIt = FlowConditionDeps.find(&
Token);
183 if (DepsIt != FlowConditionDeps.end()) {
184 for (AtomicBoolValue *DepToken : DepsIt->second) {
185 addTransitiveFlowConditionConstraints(*DepToken, Constraints,
192 llvm::raw_ostream &OS) {
195 addTransitiveFlowConditionConstraints(
Token, Constraints, VisitedTokens);
197 llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {
209 auto It = FunctionContexts.find(F);
210 if (It != FunctionContexts.end())
217 auto Result = FunctionContexts.insert({F, std::move(*
CFCtx)});
218 return &
Result.first->second;
229 if (
auto EC = llvm::sys::fs::create_directories(Dir))
230 llvm::errs() <<
"Failed to create log dir: " << EC.message() <<
"\n";
234 static std::atomic<unsigned> Counter = {0};
236 [Dir(Dir.str())]()
mutable -> std::unique_ptr<llvm::raw_ostream> {
238 llvm::sys::path::append(
File,
239 std::to_string(Counter.fetch_add(1)) +
".html");
241 auto OS = std::make_unique<llvm::raw_fd_ostream>(
File, EC);
243 llvm::errs() <<
"Failed to create log " <<
File <<
": " << EC.message()
245 return std::make_unique<llvm::raw_null_ostream>();
254 : S(
std::move(S)), A(
std::make_unique<
Arena>()), Opts(Opts) {
255 assert(this->S !=
nullptr);
259 if (Opts.
Log ==
nullptr) {
262 this->Opts.
Log = LogOwner.get();
275using namespace clang;
278 const Expr *Current = &E;
279 if (
auto *EWC = dyn_cast<ExprWithCleanups>(Current)) {
280 Current = EWC->getSubExpr();
281 assert(Current !=
nullptr);
283 Current = Current->IgnoreParens();
284 assert(Current !=
nullptr);
289 if (
auto *E = dyn_cast<Expr>(&S))
304 Fields.insert(Field);
static llvm::cl::opt< std::string > DataflowLog("dataflow-log", llvm::cl::Hidden, llvm::cl::ValueOptional, llvm::cl::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)."))
static void getFieldsFromClassHierarchy(QualType Type, llvm::DenseSet< const FieldDecl * > &Fields)
Defines the clang::Expr interface and subclasses for C++ expressions.
const ControlFlowContext & CFCtx
Contains the CFG being analyzed.
Represents a base class of a C++ class.
This represents one expression.
Represents a member of a struct/union/class.
Represents a function declaration or definition.
FunctionDecl * getDefinition()
Get the definition for this declaration.
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
QualType getCanonicalType() const
field_range fields() const
Stmt - This represents one statement.
Token - This structure provides full information about a lexed token.
The base class of the type hierarchy.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isDependentType() const
Whether this type is a dependent type, meaning that its definition somehow depends on a template para...
bool isIncompleteType(NamedDecl **Def=nullptr) const
Types are partitioned into 3 broad categories (C99 6.2.5p1): object types, function types,...
bool isRecordType() const
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Represents a variable declaration or definition.
A storage location which is subdivided into smaller storage locations that can be traced independentl...
The Arena owns the objects that model data within an analysis.
AtomicBoolValue & makeFlowConditionToken()
Creates a fresh flow condition and returns a token that identifies it.
AtomicBoolValue & makeLiteral(bool Value) const
Returns a symbolic boolean value that models a boolean literal equal to Value.
BoolValue & makeNot(BoolValue &Val)
Returns a boolean value that represents the negation of Val.
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,...
BoolValue & makeAnd(BoolValue &LHS, BoolValue &RHS)
Returns a boolean value that represents the conjunction of LHS and RHS.
Models an atomic boolean.
Holds CFG and other derived context that is needed to perform dataflow analysis.
static llvm::Expected< ControlFlowContext > build(const FunctionDecl &Func)
Builds a ControlFlowContext from a FunctionDecl.
StorageLocation & getStableStorageLocation(const VarDecl &D)
Returns a stable storage location for D.
StorageLocation * getStorageLocation(const ValueDecl &D) const
Returns the storage location assigned to D or null if D has no assigned storage location.
DataflowAnalysisContext(std::unique_ptr< Solver > S, Options Opts=Options{ std::nullopt, nullptr})
Constructs a dataflow analysis context.
bool equivalentBoolValues(BoolValue &Val1, BoolValue &Val2)
Returns true if Val1 is equivalent to Val2.
bool flowConditionImplies(AtomicBoolValue &Token, BoolValue &Val)
Returns true if and only if the constraints of the flow condition identified by Token imply that Val ...
void setStorageLocation(const ValueDecl &D, StorageLocation &Loc)
Assigns Loc as the storage location of D.
bool flowConditionIsTautology(AtomicBoolValue &Token)
Returns true if and only if the constraints of the flow condition identified by Token are always true...
void addFlowConditionConstraint(AtomicBoolValue &Token, BoolValue &Constraint)
Adds Constraint to the flow condition identified by Token.
PointerValue & getOrCreateNullPointerValue(QualType PointeeType)
Returns a pointer value that represents a null pointer.
~DataflowAnalysisContext()
StorageLocation & createStorageLocation(QualType Type)
Returns a new storage location appropriate for Type.
AtomicBoolValue & joinFlowConditions(AtomicBoolValue &FirstToken, AtomicBoolValue &SecondToken)
Creates a new flow condition that represents the disjunction of the flow conditions identified by Fir...
LLVM_DUMP_METHOD void dumpFlowCondition(AtomicBoolValue &Token, llvm::raw_ostream &OS=llvm::dbgs())
AtomicBoolValue & forkFlowCondition(AtomicBoolValue &Token)
Creates a new flow condition with the same constraints as the flow condition identified by Token and ...
const ControlFlowContext * getControlFlowContext(const FunctionDecl *F)
Returns the ControlFlowContext registered for F, if any.
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.
static Logger & null()
Returns a dummy logger that does nothing.
Models a symbolic pointer. Specifically, any value of type T*.
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.
llvm::StringRef debugString(Value::Kind Kind)
Returns a string representation of a value kind.
llvm::DenseSet< const FieldDecl * > getObjectFields(QualType Type)
Returns the set of all fields in the type.
const Expr & ignoreCFGOmittedNodes(const Expr &E)
Skip past nodes that the CFG does not emit.
static std::unique_ptr< Logger > makeLoggerFromCommandLine()
@ Result
The result type of a method or function.
Logger * Log
If provided, analysis details will be recorded here.
std::optional< ContextSensitiveOptions > ContextSensitiveOpts
Options for analyzing function bodies when present in the translation unit, or empty to disable conte...