Chris Lattner has strong opinions about directory

layout.  :)

Rename the 'EntoSA' directories to 'StaticAnalyzer'.

Internally we will still use the 'ento' namespace
for the analyzer engine (unless there are further
sabre rattlings...).

llvm-svn: 122514
This commit is contained in:
Ted Kremenek 2010-12-23 19:38:26 +00:00
parent 2a0a3b43d7
commit d99bd55a5e
255 changed files with 39743 additions and 285 deletions

View File

@ -10,8 +10,8 @@ set( LLVM_USED_LIBS
clangCodeGen
clangParse
clangSema
clangEntoCheckers
clangEntoCore
clangStaticAnalyzerCheckers
clangStaticAnalyzerCore
clangAnalysis
clangIndex
clangRewrite

View File

@ -6,8 +6,8 @@ set(LLVM_USED_LIBS
clangDriver
clangCodeGen
clangSema
clangEntoCheckers
clangEntoCore
clangStaticAnalyzerCheckers
clangStaticAnalyzerCore
clangIndex
clangAnalysis
clangRewrite

View File

@ -18,7 +18,7 @@ TOOL_NO_EXPORTS = 1
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
selectiondag asmparser
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
clangSema.a clangEntoCheckers.a clangEntoCore.a clangAnalysis.a clangRewrite.a \
clangSema.a clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a clangAnalysis.a clangRewrite.a \
clangAST.a clangParse.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile

View File

@ -7,8 +7,8 @@ set(LLVM_USED_LIBS
clangSema
clangAnalysis
clangSerialization
clangEntoCheckers
clangEntoCore
clangStaticAnalyzerCheckers
clangStaticAnalyzerCore
clangRewrite
clangAST
clangParse

View File

@ -16,7 +16,7 @@ NO_INSTALL = 1
TOOL_NO_EXPORTS = 1
LINK_COMPONENTS := asmparser bitreader mc core
USEDLIBS = clangEntoCheckers.a clangEntoCore.a clangIndex.a clangFrontend.a clangDriver.a \
USEDLIBS = clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a clangIndex.a clangFrontend.a clangDriver.a \
clangSema.a clangAnalysis.a clangSerialization.a \
clangAST.a clangParse.a clangLex.a clangBasic.a

View File

@ -16,7 +16,7 @@
#define LLVM_CLANG_GR_BUGREPORTER
#include "clang/Basic/SourceLocation.h"
#include "clang/EntoSA/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableSet.h"

View File

@ -14,7 +14,7 @@
#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
#define LLVM_CLANG_ANALYSIS_BUGTYPE
#include "clang/EntoSA/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
#include "llvm/ADT/FoldingSet.h"
#include <string>

View File

@ -0,0 +1,39 @@
//===--- AnalysisConsumer.h - Front-end Analysis Engine Hooks ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This header contains the functions necessary for a front-end to run various
// analyses.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_ANALYSISCONSUMER_H
#define LLVM_CLANG_GR_ANALYSISCONSUMER_H
#include <string>
namespace clang {
class AnalyzerOptions;
class ASTConsumer;
class Preprocessor;
namespace ento {
/// CreateAnalysisConsumer - Creates an ASTConsumer to run various code
/// analysis passes. (The set of analyses run is controlled by command-line
/// options.)
ASTConsumer* CreateAnalysisConsumer(const Preprocessor &pp,
const std::string &output,
const AnalyzerOptions& Opts);
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,486 @@
//===--- BugReporter.h - Generate PathDiagnostics --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines BugReporter, a utility class for generating
// PathDiagnostics for analyses based on GRState.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_BUGREPORTER
#define LLVM_CLANG_GR_BUGREPORTER
#include "clang/Basic/SourceLocation.h"
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableSet.h"
#include "llvm/ADT/SmallSet.h"
#include <list>
namespace clang {
class ASTContext;
class Diagnostic;
class Stmt;
class ParentMap;
namespace ento {
class PathDiagnostic;
class PathDiagnosticPiece;
class PathDiagnosticClient;
class ExplodedNode;
class ExplodedGraph;
class BugReporter;
class BugReporterContext;
class ExprEngine;
class GRState;
class BugType;
//===----------------------------------------------------------------------===//
// Interface for individual bug reports.
//===----------------------------------------------------------------------===//
class BugReporterVisitor : public llvm::FoldingSetNode {
public:
virtual ~BugReporterVisitor();
virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
const ExplodedNode* PrevN,
BugReporterContext& BRC) = 0;
virtual bool isOwnedByReporterContext() { return true; }
virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
};
// FIXME: Combine this with RangedBugReport and remove RangedBugReport.
class BugReport : public BugReporterVisitor {
protected:
BugType& BT;
std::string ShortDescription;
std::string Description;
const ExplodedNode *ErrorNode;
mutable SourceRange R;
protected:
friend class BugReporter;
friend class BugReportEquivClass;
virtual void Profile(llvm::FoldingSetNodeID& hash) const {
hash.AddInteger(getLocation().getRawEncoding());
hash.AddString(Description);
}
public:
class NodeResolver {
public:
virtual ~NodeResolver() {}
virtual const ExplodedNode*
getOriginalNode(const ExplodedNode* N) = 0;
};
BugReport(BugType& bt, llvm::StringRef desc, const ExplodedNode *errornode)
: BT(bt), Description(desc), ErrorNode(errornode) {}
BugReport(BugType& bt, llvm::StringRef shortDesc, llvm::StringRef desc,
const ExplodedNode *errornode)
: BT(bt), ShortDescription(shortDesc), Description(desc),
ErrorNode(errornode) {}
virtual ~BugReport();
virtual bool isOwnedByReporterContext() { return false; }
const BugType& getBugType() const { return BT; }
BugType& getBugType() { return BT; }
// FIXME: Perhaps this should be moved into a subclass?
const ExplodedNode* getErrorNode() const { return ErrorNode; }
// FIXME: Do we need this? Maybe getLocation() should return a ProgramPoint
// object.
// FIXME: If we do need it, we can probably just make it private to
// BugReporter.
const Stmt* getStmt() const;
const llvm::StringRef getDescription() const { return Description; }
const llvm::StringRef getShortDescription() const {
return ShortDescription.empty() ? Description : ShortDescription;
}
// FIXME: Is this needed?
virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
return std::make_pair((const char**)0,(const char**)0);
}
// FIXME: Perhaps move this into a subclass.
virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
const ExplodedNode* N);
/// getLocation - Return the "definitive" location of the reported bug.
/// While a bug can span an entire path, usually there is a specific
/// location that can be used to identify where the key issue occured.
/// This location is used by clients rendering diagnostics.
virtual SourceLocation getLocation() const;
typedef const SourceRange *ranges_iterator;
/// getRanges - Returns the source ranges associated with this bug.
virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const;
virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
const ExplodedNode* PrevN,
BugReporterContext& BR);
virtual void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode* N) {}
};
//===----------------------------------------------------------------------===//
// BugTypes (collections of related reports).
//===----------------------------------------------------------------------===//
class BugReportEquivClass : public llvm::FoldingSetNode {
// List of *owned* BugReport objects.
std::list<BugReport*> Reports;
friend class BugReporter;
void AddReport(BugReport* R) { Reports.push_back(R); }
public:
BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
~BugReportEquivClass();
void Profile(llvm::FoldingSetNodeID& ID) const {
assert(!Reports.empty());
(*Reports.begin())->Profile(ID);
}
class iterator {
std::list<BugReport*>::iterator impl;
public:
iterator(std::list<BugReport*>::iterator i) : impl(i) {}
iterator& operator++() { ++impl; return *this; }
bool operator==(const iterator& I) const { return I.impl == impl; }
bool operator!=(const iterator& I) const { return I.impl != impl; }
BugReport* operator*() const { return *impl; }
BugReport* operator->() const { return *impl; }
};
class const_iterator {
std::list<BugReport*>::const_iterator impl;
public:
const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {}
const_iterator& operator++() { ++impl; return *this; }
bool operator==(const const_iterator& I) const { return I.impl == impl; }
bool operator!=(const const_iterator& I) const { return I.impl != impl; }
const BugReport* operator*() const { return *impl; }
const BugReport* operator->() const { return *impl; }
};
iterator begin() { return iterator(Reports.begin()); }
iterator end() { return iterator(Reports.end()); }
const_iterator begin() const { return const_iterator(Reports.begin()); }
const_iterator end() const { return const_iterator(Reports.end()); }
};
//===----------------------------------------------------------------------===//
// Specialized subclasses of BugReport.
//===----------------------------------------------------------------------===//
// FIXME: Collapse this with the default BugReport class.
class RangedBugReport : public BugReport {
llvm::SmallVector<SourceRange, 4> Ranges;
public:
RangedBugReport(BugType& D, llvm::StringRef description,
ExplodedNode *errornode)
: BugReport(D, description, errornode) {}
RangedBugReport(BugType& D, llvm::StringRef shortDescription,
llvm::StringRef description, ExplodedNode *errornode)
: BugReport(D, shortDescription, description, errornode) {}
~RangedBugReport();
// FIXME: Move this out of line.
void addRange(SourceRange R) {
assert(R.isValid());
Ranges.push_back(R);
}
virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const {
return std::make_pair(Ranges.begin(), Ranges.end());
}
};
class EnhancedBugReport : public RangedBugReport {
public:
typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data,
const ExplodedNode *N);
private:
typedef std::vector<std::pair<VisitorCreator, const void*> > Creators;
Creators creators;
public:
EnhancedBugReport(BugType& D, llvm::StringRef description,
ExplodedNode *errornode)
: RangedBugReport(D, description, errornode) {}
EnhancedBugReport(BugType& D, llvm::StringRef shortDescription,
llvm::StringRef description, ExplodedNode *errornode)
: RangedBugReport(D, shortDescription, description, errornode) {}
~EnhancedBugReport() {}
void registerInitialVisitors(BugReporterContext& BRC, const ExplodedNode* N) {
for (Creators::iterator I = creators.begin(), E = creators.end(); I!=E; ++I)
I->first(BRC, I->second, N);
}
void addVisitorCreator(VisitorCreator creator, const void *data) {
creators.push_back(std::make_pair(creator, data));
}
};
//===----------------------------------------------------------------------===//
// BugReporter and friends.
//===----------------------------------------------------------------------===//
class BugReporterData {
public:
virtual ~BugReporterData();
virtual Diagnostic& getDiagnostic() = 0;
virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
virtual ASTContext& getASTContext() = 0;
virtual SourceManager& getSourceManager() = 0;
};
class BugReporter {
public:
enum Kind { BaseBRKind, GRBugReporterKind };
private:
typedef llvm::ImmutableSet<BugType*> BugTypesTy;
BugTypesTy::Factory F;
BugTypesTy BugTypes;
const Kind kind;
BugReporterData& D;
void FlushReport(BugReportEquivClass& EQ);
protected:
BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
D(d) {}
public:
BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind),
D(d) {}
virtual ~BugReporter();
void FlushReports();
Kind getKind() const { return kind; }
Diagnostic& getDiagnostic() {
return D.getDiagnostic();
}
PathDiagnosticClient* getPathDiagnosticClient() {
return D.getPathDiagnosticClient();
}
typedef BugTypesTy::iterator iterator;
iterator begin() { return BugTypes.begin(); }
iterator end() { return BugTypes.end(); }
ASTContext& getContext() { return D.getASTContext(); }
SourceManager& getSourceManager() { return D.getSourceManager(); }
virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
llvm::SmallVectorImpl<BugReport *> &bugReports) {}
void Register(BugType *BT);
void EmitReport(BugReport *R);
void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
SourceLocation Loc,
SourceRange* RangeBeg, unsigned NumRanges);
void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
llvm::StringRef BugStr, SourceLocation Loc,
SourceRange* RangeBeg, unsigned NumRanges);
void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
SourceLocation Loc) {
EmitBasicReport(BugName, BugStr, Loc, 0, 0);
}
void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
llvm::StringRef BugStr, SourceLocation Loc) {
EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
}
void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
SourceLocation Loc, SourceRange R) {
EmitBasicReport(BugName, BugStr, Loc, &R, 1);
}
void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef Category,
llvm::StringRef BugStr, SourceLocation Loc,
SourceRange R) {
EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
}
static bool classof(const BugReporter* R) { return true; }
};
// FIXME: Get rid of GRBugReporter. It's the wrong abstraction.
class GRBugReporter : public BugReporter {
ExprEngine& Eng;
llvm::SmallSet<SymbolRef, 10> NotableSymbols;
public:
GRBugReporter(BugReporterData& d, ExprEngine& eng)
: BugReporter(d, GRBugReporterKind), Eng(eng) {}
virtual ~GRBugReporter();
/// getEngine - Return the analysis engine used to analyze a given
/// function or method.
ExprEngine &getEngine() { return Eng; }
/// getGraph - Get the exploded graph created by the analysis engine
/// for the analyzed method or function.
ExplodedGraph &getGraph();
/// getStateManager - Return the state manager used by the analysis
/// engine.
GRStateManager &getStateManager();
virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
llvm::SmallVectorImpl<BugReport*> &bugReports);
void addNotableSymbol(SymbolRef Sym) {
NotableSymbols.insert(Sym);
}
bool isNotable(SymbolRef Sym) const {
return (bool) NotableSymbols.count(Sym);
}
/// classof - Used by isa<>, cast<>, and dyn_cast<>.
static bool classof(const BugReporter* R) {
return R->getKind() == GRBugReporterKind;
}
};
class BugReporterContext {
GRBugReporter &BR;
// Not the most efficient data structure, but we use an ImmutableList for the
// Callbacks because it is safe to make additions to list during iteration.
llvm::ImmutableList<BugReporterVisitor*>::Factory F;
llvm::ImmutableList<BugReporterVisitor*> Callbacks;
llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
public:
BugReporterContext(GRBugReporter& br) : BR(br), Callbacks(F.getEmptyList()) {}
virtual ~BugReporterContext();
void addVisitor(BugReporterVisitor* visitor);
typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
visitor_iterator visitor_begin() { return Callbacks.begin(); }
visitor_iterator visitor_end() { return Callbacks.end(); }
GRBugReporter& getBugReporter() { return BR; }
ExplodedGraph &getGraph() { return BR.getGraph(); }
void addNotableSymbol(SymbolRef Sym) {
// FIXME: For now forward to GRBugReporter.
BR.addNotableSymbol(Sym);
}
bool isNotable(SymbolRef Sym) const {
// FIXME: For now forward to GRBugReporter.
return BR.isNotable(Sym);
}
GRStateManager& getStateManager() {
return BR.getStateManager();
}
SValBuilder& getSValBuilder() {
return getStateManager().getSValBuilder();
}
ASTContext& getASTContext() {
return BR.getContext();
}
SourceManager& getSourceManager() {
return BR.getSourceManager();
}
virtual BugReport::NodeResolver& getNodeResolver() = 0;
};
class DiagBugReport : public RangedBugReport {
std::list<std::string> Strs;
FullSourceLoc L;
public:
DiagBugReport(BugType& D, llvm::StringRef desc, FullSourceLoc l) :
RangedBugReport(D, desc, 0), L(l) {}
virtual ~DiagBugReport() {}
// FIXME: Move out-of-line (virtual function).
SourceLocation getLocation() const { return L; }
void addString(llvm::StringRef s) { Strs.push_back(s); }
typedef std::list<std::string>::const_iterator str_iterator;
str_iterator str_begin() const { return Strs.begin(); }
str_iterator str_end() const { return Strs.end(); }
};
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
namespace bugreporter {
const Stmt *GetDerefExpr(const ExplodedNode *N);
const Stmt *GetDenomExpr(const ExplodedNode *N);
const Stmt *GetCalleeExpr(const ExplodedNode *N);
const Stmt *GetRetValExpr(const ExplodedNode *N);
void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt,
const ExplodedNode* N);
void registerFindLastStore(BugReporterContext& BRC, const void *memregion,
const ExplodedNode *N);
void registerNilReceiverVisitor(BugReporterContext &BRC);
void registerVarDeclsLastStore(BugReporterContext &BRC, const void *stmt,
const ExplodedNode *N);
} // end namespace clang::bugreporter
//===----------------------------------------------------------------------===//
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,76 @@
//===--- BugType.h - Bug Information Desciption ----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines BugType, a class representing a bug type.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
#define LLVM_CLANG_ANALYSIS_BUGTYPE
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
#include "llvm/ADT/FoldingSet.h"
#include <string>
namespace clang {
namespace ento {
class ExplodedNode;
class ExprEngine;
class BugType {
private:
const std::string Name;
const std::string Category;
llvm::FoldingSet<BugReportEquivClass> EQClasses;
friend class BugReporter;
bool SuppressonSink;
public:
BugType(llvm::StringRef name, llvm::StringRef cat)
: Name(name), Category(cat), SuppressonSink(false) {}
virtual ~BugType();
// FIXME: Should these be made strings as well?
llvm::StringRef getName() const { return Name; }
llvm::StringRef getCategory() const { return Category; }
/// isSuppressOnSink - Returns true if bug reports associated with this bug
/// type should be suppressed if the end node of the report is post-dominated
/// by a sink node.
bool isSuppressOnSink() const { return SuppressonSink; }
void setSuppressOnSink(bool x) { SuppressonSink = x; }
virtual void FlushReports(BugReporter& BR);
typedef llvm::FoldingSet<BugReportEquivClass>::iterator iterator;
iterator begin() { return EQClasses.begin(); }
iterator end() { return EQClasses.end(); }
typedef llvm::FoldingSet<BugReportEquivClass>::const_iterator const_iterator;
const_iterator begin() const { return EQClasses.begin(); }
const_iterator end() const { return EQClasses.end(); }
};
class BuiltinBug : public BugType {
const std::string desc;
public:
BuiltinBug(const char *name, const char *description)
: BugType(name, "Logic error"), desc(description) {}
BuiltinBug(const char *name)
: BugType(name, "Logic error"), desc(name) {}
llvm::StringRef getDescription() const { return desc; }
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,500 @@
//===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the PathDiagnostic-related interfaces.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
#define LLVM_CLANG_PATH_DIAGNOSTIC_H
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/FoldingSet.h"
#include <deque>
#include <iterator>
#include <string>
#include <vector>
namespace clang {
class Decl;
class SourceManager;
class Stmt;
namespace ento {
//===----------------------------------------------------------------------===//
// High-level interface for handlers of path-sensitive diagnostics.
//===----------------------------------------------------------------------===//
class PathDiagnostic;
class PathDiagnosticClient : public DiagnosticClient {
public:
PathDiagnosticClient() {}
virtual ~PathDiagnosticClient() {}
virtual void
FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade = 0) = 0;
void FlushDiagnostics(llvm::SmallVectorImpl<std::string> &FilesMade) {
FlushDiagnostics(&FilesMade);
}
virtual llvm::StringRef getName() const = 0;
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
const DiagnosticInfo &Info);
virtual void HandlePathDiagnostic(const PathDiagnostic* D) = 0;
enum PathGenerationScheme { Minimal, Extensive };
virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
virtual bool supportsLogicalOpControlFlow() const { return false; }
virtual bool supportsAllBlockEdges() const { return false; }
virtual bool useVerboseDescription() const { return true; }
};
//===----------------------------------------------------------------------===//
// Path-sensitive diagnostics.
//===----------------------------------------------------------------------===//
class PathDiagnosticRange : public SourceRange {
public:
const bool isPoint;
PathDiagnosticRange(const SourceRange &R, bool isP = false)
: SourceRange(R), isPoint(isP) {}
};
class PathDiagnosticLocation {
private:
enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
SourceRange R;
const Stmt *S;
const Decl *D;
const SourceManager *SM;
public:
PathDiagnosticLocation()
: K(SingleLocK), S(0), D(0), SM(0) {}
PathDiagnosticLocation(FullSourceLoc L)
: K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()) {}
PathDiagnosticLocation(const Stmt *s, const SourceManager &sm)
: K(StmtK), S(s), D(0), SM(&sm) {}
PathDiagnosticLocation(SourceRange r, const SourceManager &sm)
: K(RangeK), R(r), S(0), D(0), SM(&sm) {}
PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
: K(DeclK), S(0), D(d), SM(&sm) {}
bool operator==(const PathDiagnosticLocation &X) const {
return K == X.K && R == X.R && S == X.S && D == X.D;
}
bool operator!=(const PathDiagnosticLocation &X) const {
return K != X.K || R != X.R || S != X.S || D != X.D;;
}
PathDiagnosticLocation& operator=(const PathDiagnosticLocation &X) {
K = X.K;
R = X.R;
S = X.S;
D = X.D;
SM = X.SM;
return *this;
}
bool isValid() const {
return SM != 0;
}
const SourceManager& getSourceManager() const { assert(isValid());return *SM;}
FullSourceLoc asLocation() const;
PathDiagnosticRange asRange() const;
const Stmt *asStmt() const { assert(isValid()); return S; }
const Decl *asDecl() const { assert(isValid()); return D; }
bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
void invalidate() {
*this = PathDiagnosticLocation();
}
void flatten();
const SourceManager& getManager() const { assert(isValid()); return *SM; }
void Profile(llvm::FoldingSetNodeID &ID) const;
};
class PathDiagnosticLocationPair {
private:
PathDiagnosticLocation Start, End;
public:
PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
const PathDiagnosticLocation &end)
: Start(start), End(end) {}
const PathDiagnosticLocation &getStart() const { return Start; }
const PathDiagnosticLocation &getEnd() const { return End; }
void flatten() {
Start.flatten();
End.flatten();
}
void Profile(llvm::FoldingSetNodeID &ID) const {
Start.Profile(ID);
End.Profile(ID);
}
};
//===----------------------------------------------------------------------===//
// Path "pieces" for path-sensitive diagnostics.
//===----------------------------------------------------------------------===//
class PathDiagnosticPiece {
public:
enum Kind { ControlFlow, Event, Macro };
enum DisplayHint { Above, Below };
private:
const std::string str;
std::vector<FixItHint> FixItHints;
const Kind kind;
const DisplayHint Hint;
std::vector<SourceRange> ranges;
// Do not implement:
PathDiagnosticPiece();
PathDiagnosticPiece(const PathDiagnosticPiece &P);
PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P);
protected:
PathDiagnosticPiece(llvm::StringRef s, Kind k, DisplayHint hint = Below);
PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
public:
virtual ~PathDiagnosticPiece();
const std::string& getString() const { return str; }
/// getDisplayHint - Return a hint indicating where the diagnostic should
/// be displayed by the PathDiagnosticClient.
DisplayHint getDisplayHint() const { return Hint; }
virtual PathDiagnosticLocation getLocation() const = 0;
virtual void flattenLocations() = 0;
Kind getKind() const { return kind; }
void addRange(SourceRange R) { ranges.push_back(R); }
void addRange(SourceLocation B, SourceLocation E) {
ranges.push_back(SourceRange(B,E));
}
void addFixItHint(const FixItHint& Hint) {
FixItHints.push_back(Hint);
}
typedef const SourceRange* range_iterator;
range_iterator ranges_begin() const {
return ranges.empty() ? NULL : &ranges[0];
}
range_iterator ranges_end() const {
return ranges_begin() + ranges.size();
}
typedef const FixItHint *fixit_iterator;
fixit_iterator fixit_begin() const {
return FixItHints.empty()? 0 : &FixItHints[0];
}
fixit_iterator fixit_end() const {
return FixItHints.empty()? 0
: &FixItHints[0] + FixItHints.size();
}
static inline bool classof(const PathDiagnosticPiece* P) {
return true;
}
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
};
class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
private:
PathDiagnosticLocation Pos;
public:
PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
llvm::StringRef s,
PathDiagnosticPiece::Kind k,
bool addPosRange = true)
: PathDiagnosticPiece(s, k), Pos(pos) {
assert(Pos.asLocation().isValid() &&
"PathDiagnosticSpotPiece's must have a valid location.");
if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
}
PathDiagnosticLocation getLocation() const { return Pos; }
virtual void flattenLocations() { Pos.flatten(); }
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
};
class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
public:
PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
llvm::StringRef s, bool addPosRange = true)
: PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
~PathDiagnosticEventPiece();
static inline bool classof(const PathDiagnosticPiece* P) {
return P->getKind() == Event;
}
};
class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
std::vector<PathDiagnosticLocationPair> LPairs;
public:
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
const PathDiagnosticLocation &endPos,
llvm::StringRef s)
: PathDiagnosticPiece(s, ControlFlow) {
LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
}
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
const PathDiagnosticLocation &endPos)
: PathDiagnosticPiece(ControlFlow) {
LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
}
~PathDiagnosticControlFlowPiece();
PathDiagnosticLocation getStartLocation() const {
assert(!LPairs.empty() &&
"PathDiagnosticControlFlowPiece needs at least one location.");
return LPairs[0].getStart();
}
PathDiagnosticLocation getEndLocation() const {
assert(!LPairs.empty() &&
"PathDiagnosticControlFlowPiece needs at least one location.");
return LPairs[0].getEnd();
}
void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
virtual PathDiagnosticLocation getLocation() const {
return getStartLocation();
}
typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
iterator begin() { return LPairs.begin(); }
iterator end() { return LPairs.end(); }
virtual void flattenLocations() {
for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
}
typedef std::vector<PathDiagnosticLocationPair>::const_iterator
const_iterator;
const_iterator begin() const { return LPairs.begin(); }
const_iterator end() const { return LPairs.end(); }
static inline bool classof(const PathDiagnosticPiece* P) {
return P->getKind() == ControlFlow;
}
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
};
class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
std::vector<PathDiagnosticPiece*> SubPieces;
public:
PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
: PathDiagnosticSpotPiece(pos, "", Macro) {}
~PathDiagnosticMacroPiece();
bool containsEvent() const;
void push_back(PathDiagnosticPiece* P) { SubPieces.push_back(P); }
typedef std::vector<PathDiagnosticPiece*>::iterator iterator;
iterator begin() { return SubPieces.begin(); }
iterator end() { return SubPieces.end(); }
virtual void flattenLocations() {
PathDiagnosticSpotPiece::flattenLocations();
for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations();
}
typedef std::vector<PathDiagnosticPiece*>::const_iterator const_iterator;
const_iterator begin() const { return SubPieces.begin(); }
const_iterator end() const { return SubPieces.end(); }
static inline bool classof(const PathDiagnosticPiece* P) {
return P->getKind() == Macro;
}
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
};
/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
/// each which represent the pieces of the path.
class PathDiagnostic : public llvm::FoldingSetNode {
std::deque<PathDiagnosticPiece*> path;
unsigned Size;
std::string BugType;
std::string Desc;
std::string Category;
std::deque<std::string> OtherDesc;
public:
PathDiagnostic();
PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc,
llvm::StringRef category);
~PathDiagnostic();
llvm::StringRef getDescription() const { return Desc; }
llvm::StringRef getBugType() const { return BugType; }
llvm::StringRef getCategory() const { return Category; }
typedef std::deque<std::string>::const_iterator meta_iterator;
meta_iterator meta_begin() const { return OtherDesc.begin(); }
meta_iterator meta_end() const { return OtherDesc.end(); }
void addMeta(llvm::StringRef s) { OtherDesc.push_back(s); }
PathDiagnosticLocation getLocation() const {
assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic.");
return rbegin()->getLocation();
}
void push_front(PathDiagnosticPiece* piece) {
assert(piece);
path.push_front(piece);
++Size;
}
void push_back(PathDiagnosticPiece* piece) {
assert(piece);
path.push_back(piece);
++Size;
}
PathDiagnosticPiece* back() {
return path.back();
}
const PathDiagnosticPiece* back() const {
return path.back();
}
unsigned size() const { return Size; }
bool empty() const { return Size == 0; }
void resetPath(bool deletePieces = true);
class iterator {
public:
typedef std::deque<PathDiagnosticPiece*>::iterator ImplTy;
typedef PathDiagnosticPiece value_type;
typedef value_type& reference;
typedef value_type* pointer;
typedef ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
private:
ImplTy I;
public:
iterator(const ImplTy& i) : I(i) {}
bool operator==(const iterator& X) const { return I == X.I; }
bool operator!=(const iterator& X) const { return I != X.I; }
PathDiagnosticPiece& operator*() const { return **I; }
PathDiagnosticPiece* operator->() const { return *I; }
iterator& operator++() { ++I; return *this; }
iterator& operator--() { --I; return *this; }
};
class const_iterator {
public:
typedef std::deque<PathDiagnosticPiece*>::const_iterator ImplTy;
typedef const PathDiagnosticPiece value_type;
typedef value_type& reference;
typedef value_type* pointer;
typedef ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
private:
ImplTy I;
public:
const_iterator(const ImplTy& i) : I(i) {}
bool operator==(const const_iterator& X) const { return I == X.I; }
bool operator!=(const const_iterator& X) const { return I != X.I; }
reference operator*() const { return **I; }
pointer operator->() const { return *I; }
const_iterator& operator++() { ++I; return *this; }
const_iterator& operator--() { --I; return *this; }
};
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
// forward iterator creation methods.
iterator begin() { return path.begin(); }
iterator end() { return path.end(); }
const_iterator begin() const { return path.begin(); }
const_iterator end() const { return path.end(); }
// reverse iterator creation methods.
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
void flattenLocations() {
for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations();
}
void Profile(llvm::FoldingSetNodeID &ID) const;
};
} // end GR namespace
} //end clang namespace
#endif

View File

@ -0,0 +1,35 @@
//== NullDerefChecker.h - Null dereference checker --------------*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This defines NullDerefChecker and UndefDerefChecker, two builtin checks
// in ExprEngine that check for null and undefined pointers at loads
// and stores.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_DEREFCHECKER
#define LLVM_CLANG_GR_DEREFCHECKER
#include <utility>
namespace clang {
namespace ento {
class ExprEngine;
class ExplodedNode;
std::pair<ExplodedNode * const *, ExplodedNode * const *>
GetImplicitNullDereferences(ExprEngine &Eng);
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,67 @@
//==- LocalCheckers.h - Intra-Procedural+Flow-Sensitive Checkers -*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interface to call a set of intra-procedural (local)
// checkers that use flow/path-sensitive analyses to find bugs.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_LOCALCHECKERS_H
#define LLVM_CLANG_GR_LOCALCHECKERS_H
namespace clang {
class CFG;
class Decl;
class Diagnostic;
class ASTContext;
class LangOptions;
class ParentMap;
class LiveVariables;
class ObjCImplementationDecl;
class LangOptions;
class TranslationUnitDecl;
namespace ento {
class PathDiagnosticClient;
class TransferFuncs;
class BugType;
class BugReporter;
class ExprEngine;
void CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &map,
BugReporter& BR);
TransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
const LangOptions& lopts);
void CheckObjCDealloc(const ObjCImplementationDecl* D, const LangOptions& L,
BugReporter& BR);
void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID,
BugReporter& BR);
void CheckObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter& BR);
void RegisterAppleChecks(ExprEngine& Eng, const Decl &D);
void RegisterExperimentalChecks(ExprEngine &Eng);
void RegisterExperimentalInternalChecks(ExprEngine &Eng);
void CheckLLVMConventions(TranslationUnitDecl &TU, BugReporter &BR);
void CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR);
void CheckSizeofPointer(const Decl *D, BugReporter &BR);
void RegisterCallInliner(ExprEngine &Eng);
} // end GR namespace
} // end namespace clang
#endif

View File

@ -14,7 +14,7 @@
#ifndef LLVM_CLANG_GR_MANAGER_REGISTRY_H
#define LLVM_CLANG_GR_MANAGER_REGISTRY_H
#include "clang/EntoSA/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
namespace clang {

View File

@ -16,8 +16,8 @@
#define LLVM_CLANG_GR_ANALYSISMANAGER_H
#include "clang/Analysis/AnalysisContext.h"
#include "clang/EntoSA/BugReporter/BugReporter.h"
#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
namespace clang {

View File

@ -16,7 +16,7 @@
#ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H
#define LLVM_CLANG_GR_BASICVALUEFACTORY_H
#include "clang/EntoSA/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
#include "clang/AST/ASTContext.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/APSInt.h"

View File

@ -16,7 +16,7 @@
#define LLVM_CLANG_GR_CHECKER
#include "clang/Analysis/Support/SaveAndRestore.h"
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
//===----------------------------------------------------------------------===//
// Checker interface.

View File

@ -13,7 +13,7 @@
#ifndef LLVM_CLANG_GR_CHECKERVISITOR
#define LLVM_CLANG_GR_CHECKERVISITOR
#include "clang/EntoSA/PathSensitive/Checker.h"
#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
namespace clang {
@ -51,7 +51,7 @@ public:
case Stmt::NAME ## Class:\
static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\
break;
#include "clang/EntoSA/PathSensitive/CheckerVisitor.def"
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def"
}
}
@ -70,7 +70,7 @@ case Stmt::NAME ## Class:\
static_cast<ImplClass*>(this)->\
PostVisit ## NAME(C,static_cast<const NAME*>(S));\
break;
#include "clang/EntoSA/PathSensitive/CheckerVisitor.def"
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def"
}
}
@ -101,7 +101,7 @@ void PreVisit ## NAME(CheckerContext &C, const NAME* S) {\
void PostVisit ## NAME(CheckerContext &C, const NAME* S) {\
static_cast<ImplClass*>(this)->PostVisit ## FALLBACK(C, S);\
}
#include "clang/EntoSA/PathSensitive/CheckerVisitor.def"
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def"
};
} // end GR namespace

View File

@ -15,7 +15,7 @@
#define LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place.
#include "clang/EntoSA/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/PathSensitive/Store.h"
namespace llvm {
class APSInt;

View File

@ -16,10 +16,10 @@
#define LLVM_CLANG_GR_COREENGINE
#include "clang/AST/Expr.h"
#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
#include "clang/EntoSA/PathSensitive/WorkList.h"
#include "clang/EntoSA/PathSensitive/BlockCounter.h"
#include "clang/EntoSA/PathSensitive/SubEngine.h"
#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/PathSensitive/WorkList.h"
#include "clang/StaticAnalyzer/PathSensitive/BlockCounter.h"
#include "clang/StaticAnalyzer/PathSensitive/SubEngine.h"
#include "llvm/ADT/OwningPtr.h"
namespace clang {

View File

@ -14,8 +14,8 @@
#ifndef LLVM_CLANG_GR_ENVIRONMENT_H
#define LLVM_CLANG_GR_ENVIRONMENT_H
#include "clang/EntoSA/PathSensitive/Store.h"
#include "clang/EntoSA/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
#include "llvm/ADT/ImmutableMap.h"
namespace clang {

View File

@ -16,12 +16,12 @@
#ifndef LLVM_CLANG_GR_EXPRENGINE
#define LLVM_CLANG_GR_EXPRENGINE
#include "clang/EntoSA/PathSensitive/AnalysisManager.h"
#include "clang/EntoSA/PathSensitive/SubEngine.h"
#include "clang/EntoSA/PathSensitive/CoreEngine.h"
#include "clang/EntoSA/PathSensitive/GRState.h"
#include "clang/EntoSA/PathSensitive/TransferFuncs.h"
#include "clang/EntoSA/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/PathSensitive/SubEngine.h"
#include "clang/StaticAnalyzer/PathSensitive/CoreEngine.h"
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
#include "clang/AST/Type.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprCXX.h"

View File

@ -14,7 +14,7 @@
#ifndef LLVM_CLANG_GR_EXPRENGINE_BUILDERS
#define LLVM_CLANG_GR_EXPRENGINE_BUILDERS
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
#include "clang/Analysis/Support/SaveAndRestore.h"
namespace clang {

View File

@ -14,10 +14,10 @@
#ifndef LLVM_CLANG_GR_VALUESTATE_H
#define LLVM_CLANG_GR_VALUESTATE_H
#include "clang/EntoSA/PathSensitive/ConstraintManager.h"
#include "clang/EntoSA/PathSensitive/Environment.h"
#include "clang/EntoSA/PathSensitive/Store.h"
#include "clang/EntoSA/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/PathSensitive/ConstraintManager.h"
#include "clang/StaticAnalyzer/PathSensitive/Environment.h"
#include "clang/StaticAnalyzer/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/Support/Casting.h"

View File

@ -18,7 +18,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/EntoSA/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/ADT/FoldingSet.h"

View File

@ -17,9 +17,9 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/EntoSA/PathSensitive/SVals.h"
#include "clang/EntoSA/PathSensitive/BasicValueFactory.h"
#include "clang/EntoSA/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/PathSensitive/BasicValueFactory.h"
#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
namespace clang {

View File

@ -15,7 +15,7 @@
#ifndef LLVM_CLANG_GR_RVALUE_H
#define LLVM_CLANG_GR_RVALUE_H
#include "clang/EntoSA/PathSensitive/SymbolManager.h"
#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/ImmutableList.h"

View File

@ -14,8 +14,8 @@
#ifndef LLVM_CLANG_GR_STORE_H
#define LLVM_CLANG_GR_STORE_H
#include "clang/EntoSA/PathSensitive/MemRegion.h"
#include "clang/EntoSA/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Optional.h"

View File

@ -13,7 +13,7 @@
#ifndef LLVM_CLANG_GR_SUBENGINE_H
#define LLVM_CLANG_GR_SUBENGINE_H
#include "clang/EntoSA/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
namespace clang {

View File

@ -15,8 +15,8 @@
#ifndef LLVM_CLANG_GR_TRANSFERFUNCS
#define LLVM_CLANG_GR_TRANSFERFUNCS
#include "clang/EntoSA/PathSensitive/GRState.h"
#include "clang/EntoSA/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
#include <vector>
namespace clang {

View File

@ -15,7 +15,7 @@
#ifndef LLVM_CLANG_GR_WORKLIST
#define LLVM_CLANG_GR_WORKLIST
#include "clang/EntoSA/PathSensitive/BlockCounter.h"
#include "clang/StaticAnalyzer/PathSensitive/BlockCounter.h"
#include <cstddef>
namespace clang {

View File

@ -0,0 +1,33 @@
//===-- FrontendActions.h - Useful Frontend Actions -------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_FRONTENDACTIONS_H
#define LLVM_CLANG_GR_FRONTENDACTIONS_H
#include "clang/Frontend/FrontendAction.h"
namespace clang {
namespace ento {
//===----------------------------------------------------------------------===//
// AST Consumer Actions
//===----------------------------------------------------------------------===//
class AnalysisAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile);
};
} // end GR namespace
} // end namespace clang
#endif

View File

@ -0,0 +1,58 @@
//===-- ManagerRegistry.h - Pluggable analyzer module registry --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the ManagerRegistry and Register* classes.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_MANAGER_REGISTRY_H
#define LLVM_CLANG_GR_MANAGER_REGISTRY_H
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
namespace clang {
namespace ento {
/// ManagerRegistry - This class records manager creators registered at
/// runtime. The information is communicated to AnalysisManager through static
/// members. Better design is expected.
class ManagerRegistry {
public:
static StoreManagerCreator StoreMgrCreator;
static ConstraintManagerCreator ConstraintMgrCreator;
};
/// RegisterConstraintManager - This class is used to setup the constraint
/// manager of the static analyzer. The constructor takes a creator function
/// pointer for creating the constraint manager.
///
/// It is used like this:
///
/// class MyConstraintManager {};
/// ConstraintManager* CreateMyConstraintManager(GRStateManager& statemgr) {
/// return new MyConstraintManager(statemgr);
/// }
/// RegisterConstraintManager X(CreateMyConstraintManager);
class RegisterConstraintManager {
public:
RegisterConstraintManager(ConstraintManagerCreator CMC) {
assert(ManagerRegistry::ConstraintMgrCreator == 0
&& "ConstraintMgrCreator already set!");
ManagerRegistry::ConstraintMgrCreator = CMC;
}
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,42 @@
//===--- PathDiagnosticClients.h - Path Diagnostic Clients ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interface to create different path diagostic clients.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLIENTS_H
#define LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLiENTS_H
#include <string>
namespace clang {
class Preprocessor;
namespace ento {
class PathDiagnosticClient;
PathDiagnosticClient*
createHTMLDiagnosticClient(const std::string& prefix, const Preprocessor &PP);
PathDiagnosticClient*
createPlistDiagnosticClient(const std::string& prefix, const Preprocessor &PP,
PathDiagnosticClient *SubPD = 0);
PathDiagnosticClient*
createTextPathDiagnosticClient(const std::string& prefix,
const Preprocessor &PP);
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,208 @@
//== AnalysisManager.h - Path sensitive analysis data manager ------*- C++ -*-//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the AnalysisManager class that manages the data and policy
// for path sensitive analysis.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_ANALYSISMANAGER_H
#define LLVM_CLANG_GR_ANALYSISMANAGER_H
#include "clang/Analysis/AnalysisContext.h"
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
namespace clang {
namespace idx {
class Indexer;
class TranslationUnit;
}
namespace ento {
class AnalysisManager : public BugReporterData {
AnalysisContextManager AnaCtxMgr;
LocationContextManager LocCtxMgr;
ASTContext &Ctx;
Diagnostic &Diags;
const LangOptions &LangInfo;
llvm::OwningPtr<PathDiagnosticClient> PD;
// Configurable components creators.
StoreManagerCreator CreateStoreMgr;
ConstraintManagerCreator CreateConstraintMgr;
/// \brief Provide function definitions in other translation units. This is
/// NULL if we don't have multiple translation units. AnalysisManager does
/// not own the Indexer.
idx::Indexer *Idxer;
enum AnalysisScope { ScopeTU, ScopeDecl } AScope;
// The maximum number of exploded nodes the analyzer will generate.
unsigned MaxNodes;
// The maximum number of times the analyzer visit a block.
unsigned MaxVisit;
bool VisualizeEGDot;
bool VisualizeEGUbi;
bool PurgeDead;
/// EargerlyAssume - A flag indicating how the engine should handle
// expressions such as: 'x = (y != 0)'. When this flag is true then
// the subexpression 'y != 0' will be eagerly assumed to be true or false,
// thus evaluating it to the integers 0 or 1 respectively. The upside
// is that this can increase analysis precision until we have a better way
// to lazily evaluate such logic. The downside is that it eagerly
// bifurcates paths.
bool EagerlyAssume;
bool TrimGraph;
bool InlineCall;
public:
AnalysisManager(ASTContext &ctx, Diagnostic &diags,
const LangOptions &lang, PathDiagnosticClient *pd,
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
idx::Indexer *idxer,
unsigned maxnodes, unsigned maxvisit,
bool vizdot, bool vizubi, bool purge, bool eager, bool trim,
bool inlinecall, bool useUnoptimizedCFG,
bool addImplicitDtors, bool addInitializers)
: AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, addInitializers),
Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd),
CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),Idxer(idxer),
AScope(ScopeDecl), MaxNodes(maxnodes), MaxVisit(maxvisit),
VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge),
EagerlyAssume(eager), TrimGraph(trim), InlineCall(inlinecall) {}
~AnalysisManager() { FlushDiagnostics(); }
void ClearContexts() {
LocCtxMgr.clear();
AnaCtxMgr.clear();
}
AnalysisContextManager& getAnalysisContextManager() {
return AnaCtxMgr;
}
StoreManagerCreator getStoreManagerCreator() {
return CreateStoreMgr;
}
ConstraintManagerCreator getConstraintManagerCreator() {
return CreateConstraintMgr;
}
idx::Indexer *getIndexer() const { return Idxer; }
virtual ASTContext &getASTContext() {
return Ctx;
}
virtual SourceManager &getSourceManager() {
return getASTContext().getSourceManager();
}
virtual Diagnostic &getDiagnostic() {
return Diags;
}
const LangOptions &getLangOptions() const {
return LangInfo;
}
virtual PathDiagnosticClient *getPathDiagnosticClient() {
return PD.get();
}
void FlushDiagnostics() {
if (PD.get())
PD->FlushDiagnostics();
}
unsigned getMaxNodes() const { return MaxNodes; }
unsigned getMaxVisit() const { return MaxVisit; }
bool shouldVisualizeGraphviz() const { return VisualizeEGDot; }
bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; }
bool shouldVisualize() const {
return VisualizeEGDot || VisualizeEGUbi;
}
bool shouldTrimGraph() const { return TrimGraph; }
bool shouldPurgeDead() const { return PurgeDead; }
bool shouldEagerlyAssume() const { return EagerlyAssume; }
bool shouldInlineCall() const { return InlineCall; }
bool hasIndexer() const { return Idxer != 0; }
AnalysisContext *getAnalysisContextInAnotherTU(const Decl *D);
CFG *getCFG(Decl const *D) {
return AnaCtxMgr.getContext(D)->getCFG();
}
LiveVariables *getLiveVariables(Decl const *D) {
return AnaCtxMgr.getContext(D)->getLiveVariables();
}
ParentMap &getParentMap(Decl const *D) {
return AnaCtxMgr.getContext(D)->getParentMap();
}
AnalysisContext *getAnalysisContext(const Decl *D) {
return AnaCtxMgr.getContext(D);
}
AnalysisContext *getAnalysisContext(const Decl *D, idx::TranslationUnit *TU) {
return AnaCtxMgr.getContext(D, TU);
}
const StackFrameContext *getStackFrame(AnalysisContext *Ctx,
LocationContext const *Parent,
const Stmt *S,
const CFGBlock *Blk, unsigned Idx) {
return LocCtxMgr.getStackFrame(Ctx, Parent, S, Blk, Idx);
}
// Get the top level stack frame.
const StackFrameContext *getStackFrame(Decl const *D,
idx::TranslationUnit *TU) {
return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D, TU), 0, 0, 0, 0);
}
// Get a stack frame with parent.
StackFrameContext const *getStackFrame(const Decl *D,
LocationContext const *Parent,
const Stmt *S,
const CFGBlock *Blk, unsigned Idx) {
return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), Parent, S,
Blk,Idx);
}
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,201 @@
//=== BasicValueFactory.h - Basic values for Path Sens analysis --*- C++ -*---//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines BasicValueFactory, a class that manages the lifetime
// of APSInt objects and symbolic constraints used by ExprEngine
// and related classes.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H
#define LLVM_CLANG_GR_BASICVALUEFACTORY_H
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
#include "clang/AST/ASTContext.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ImmutableList.h"
namespace clang {
namespace ento {
class GRState;
class CompoundValData : public llvm::FoldingSetNode {
QualType T;
llvm::ImmutableList<SVal> L;
public:
CompoundValData(QualType t, llvm::ImmutableList<SVal> l)
: T(t), L(l) {}
typedef llvm::ImmutableList<SVal>::iterator iterator;
iterator begin() const { return L.begin(); }
iterator end() const { return L.end(); }
static void Profile(llvm::FoldingSetNodeID& ID, QualType T,
llvm::ImmutableList<SVal> L);
void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); }
};
class LazyCompoundValData : public llvm::FoldingSetNode {
const void *store;
const TypedRegion *region;
public:
LazyCompoundValData(const void *st, const TypedRegion *r)
: store(st), region(r) {}
const void *getStore() const { return store; }
const TypedRegion *getRegion() const { return region; }
static void Profile(llvm::FoldingSetNodeID& ID, const void *store,
const TypedRegion *region);
void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); }
};
class BasicValueFactory {
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
APSIntSetTy;
ASTContext& Ctx;
llvm::BumpPtrAllocator& BPAlloc;
APSIntSetTy APSIntSet;
void* PersistentSVals;
void* PersistentSValPairs;
llvm::ImmutableList<SVal>::Factory SValListFactory;
llvm::FoldingSet<CompoundValData> CompoundValDataSet;
llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet;
public:
BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc)
: Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0),
SValListFactory(Alloc) {}
~BasicValueFactory();
ASTContext& getContext() const { return Ctx; }
const llvm::APSInt& getValue(const llvm::APSInt& X);
const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned);
const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
const llvm::APSInt& getValue(uint64_t X, QualType T);
/// Convert - Create a new persistent APSInt with the same value as 'From'
/// but with the bitwidth and signedness of 'To'.
const llvm::APSInt &Convert(const llvm::APSInt& To,
const llvm::APSInt& From) {
if (To.isUnsigned() == From.isUnsigned() &&
To.getBitWidth() == From.getBitWidth())
return From;
return getValue(From.getSExtValue(), To.getBitWidth(), To.isUnsigned());
}
const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) {
assert(T->isIntegerType() || Loc::IsLocType(T));
unsigned bitwidth = Ctx.getTypeSize(T);
bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth())
return From;
return getValue(From.getSExtValue(), bitwidth, isUnsigned);
}
const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) {
QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy;
return getValue(X, T);
}
inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) {
return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned()));
}
inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) {
return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned()));
}
inline const llvm::APSInt& getMaxValue(QualType T) {
assert(T->isIntegerType() || Loc::IsLocType(T));
bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned));
}
inline const llvm::APSInt& getMinValue(QualType T) {
assert(T->isIntegerType() || Loc::IsLocType(T));
bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned));
}
inline const llvm::APSInt& Add1(const llvm::APSInt& V) {
llvm::APSInt X = V;
++X;
return getValue(X);
}
inline const llvm::APSInt& Sub1(const llvm::APSInt& V) {
llvm::APSInt X = V;
--X;
return getValue(X);
}
inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) {
return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
}
inline const llvm::APSInt &getIntWithPtrWidth(uint64_t X, bool isUnsigned) {
return getValue(X, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
}
inline const llvm::APSInt& getTruthValue(bool b, QualType T) {
return getValue(b ? 1 : 0, Ctx.getTypeSize(T), false);
}
inline const llvm::APSInt& getTruthValue(bool b) {
return getTruthValue(b, Ctx.IntTy);
}
const CompoundValData *getCompoundValData(QualType T,
llvm::ImmutableList<SVal> Vals);
const LazyCompoundValData *getLazyCompoundValData(const void *store,
const TypedRegion *region);
llvm::ImmutableList<SVal> getEmptySValList() {
return SValListFactory.getEmptyList();
}
llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) {
return SValListFactory.add(X, L);
}
const llvm::APSInt* evalAPSInt(BinaryOperator::Opcode Op,
const llvm::APSInt& V1,
const llvm::APSInt& V2);
const std::pair<SVal, uintptr_t>&
getPersistentSValWithData(const SVal& V, uintptr_t Data);
const std::pair<SVal, SVal>&
getPersistentSValPair(const SVal& V1, const SVal& V2);
const SVal* getPersistentSVal(SVal X);
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,59 @@
//==- BlockCounter.h - ADT for counting block visits ---------------*- C++ -*-//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines BlockCounter, an abstract data type used to count
// the number of times a given block has been visited along a path
// analyzed by CoreEngine.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_BLOCKCOUNTER
#define LLVM_CLANG_GR_BLOCKCOUNTER
namespace llvm {
class BumpPtrAllocator;
}
namespace clang {
class StackFrameContext;
namespace ento {
class BlockCounter {
void* Data;
BlockCounter(void* D) : Data(D) {}
public:
BlockCounter() : Data(0) {}
unsigned getNumVisited(const StackFrameContext *CallSite,
unsigned BlockID) const;
class Factory {
void* F;
public:
Factory(llvm::BumpPtrAllocator& Alloc);
~Factory();
BlockCounter GetEmptyCounter();
BlockCounter IncrementCount(BlockCounter BC,
const StackFrameContext *CallSite,
unsigned BlockID);
};
friend class Factory;
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,309 @@
//== Checker.h - Abstract interface for checkers -----------------*- C++ -*--=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines Checker and CheckerVisitor, classes used for creating
// domain-specific checks.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_CHECKER
#define LLVM_CLANG_GR_CHECKER
#include "clang/Analysis/Support/SaveAndRestore.h"
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
//===----------------------------------------------------------------------===//
// Checker interface.
//===----------------------------------------------------------------------===//
namespace clang {
namespace ento {
class CheckerContext {
ExplodedNodeSet &Dst;
StmtNodeBuilder &B;
ExprEngine &Eng;
ExplodedNode *Pred;
SaveAndRestore<bool> OldSink;
SaveAndRestore<const void*> OldTag;
SaveAndRestore<ProgramPoint::Kind> OldPointKind;
SaveOr OldHasGen;
const GRState *ST;
const Stmt *statement;
const unsigned size;
public:
bool *respondsToCallback;
public:
CheckerContext(ExplodedNodeSet &dst, StmtNodeBuilder &builder,
ExprEngine &eng, ExplodedNode *pred,
const void *tag, ProgramPoint::Kind K,
bool *respondsToCB = 0,
const Stmt *stmt = 0, const GRState *st = 0)
: Dst(dst), B(builder), Eng(eng), Pred(pred),
OldSink(B.BuildSinks),
OldTag(B.Tag, tag),
OldPointKind(B.PointKind, K),
OldHasGen(B.HasGeneratedNode),
ST(st), statement(stmt), size(Dst.size()),
respondsToCallback(respondsToCB) {}
~CheckerContext();
ExprEngine &getEngine() {
return Eng;
}
AnalysisManager &getAnalysisManager() {
return Eng.getAnalysisManager();
}
ConstraintManager &getConstraintManager() {
return Eng.getConstraintManager();
}
StoreManager &getStoreManager() {
return Eng.getStoreManager();
}
ExplodedNodeSet &getNodeSet() { return Dst; }
StmtNodeBuilder &getNodeBuilder() { return B; }
ExplodedNode *&getPredecessor() { return Pred; }
const GRState *getState() { return ST ? ST : B.GetState(Pred); }
ASTContext &getASTContext() {
return Eng.getContext();
}
BugReporter &getBugReporter() {
return Eng.getBugReporter();
}
SourceManager &getSourceManager() {
return getBugReporter().getSourceManager();
}
SValBuilder &getSValBuilder() {
return Eng.getSValBuilder();
}
ExplodedNode *generateNode(bool autoTransition = true) {
assert(statement && "Only transitions with statements currently supported");
ExplodedNode *N = generateNodeImpl(statement, getState(), false);
if (N && autoTransition)
Dst.Add(N);
return N;
}
ExplodedNode *generateNode(const Stmt *stmt, const GRState *state,
bool autoTransition = true) {
assert(state);
ExplodedNode *N = generateNodeImpl(stmt, state, false);
if (N && autoTransition)
addTransition(N);
return N;
}
ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred,
bool autoTransition = true) {
assert(statement && "Only transitions with statements currently supported");
ExplodedNode *N = generateNodeImpl(statement, state, pred, false);
if (N && autoTransition)
addTransition(N);
return N;
}
ExplodedNode *generateNode(const GRState *state, bool autoTransition = true) {
assert(statement && "Only transitions with statements currently supported");
ExplodedNode *N = generateNodeImpl(statement, state, false);
if (N && autoTransition)
addTransition(N);
return N;
}
ExplodedNode *generateSink(const Stmt *stmt, const GRState *state = 0) {
return generateNodeImpl(stmt, state ? state : getState(), true);
}
ExplodedNode *generateSink(const GRState *state = 0) {
assert(statement && "Only transitions with statements currently supported");
return generateNodeImpl(statement, state ? state : getState(), true);
}
void addTransition(ExplodedNode *node) {
Dst.Add(node);
}
void addTransition(const GRState *state) {
assert(state);
// If the 'state' is not new, we need to check if the cached state 'ST'
// is new.
if (state != getState() || (ST && ST != B.GetState(Pred)))
// state is new or equals to ST.
generateNode(state, true);
else
Dst.Add(Pred);
}
// Generate a node with a new program point different from the one that will
// be created by the StmtNodeBuilder.
void addTransition(const GRState *state, ProgramPoint Loc) {
ExplodedNode *N = B.generateNode(Loc, state, Pred);
if (N)
addTransition(N);
}
void EmitReport(BugReport *R) {
Eng.getBugReporter().EmitReport(R);
}
AnalysisContext *getCurrentAnalysisContext() const {
return Pred->getLocationContext()->getAnalysisContext();
}
private:
ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state,
bool markAsSink) {
ExplodedNode *node = B.generateNode(stmt, state, Pred);
if (markAsSink && node)
node->markAsSink();
return node;
}
ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state,
ExplodedNode *pred, bool markAsSink) {
ExplodedNode *node = B.generateNode(stmt, state, pred);
if (markAsSink && node)
node->markAsSink();
return node;
}
};
class Checker {
private:
friend class ExprEngine;
// FIXME: Remove the 'tag' option.
void GR_Visit(ExplodedNodeSet &Dst,
StmtNodeBuilder &Builder,
ExprEngine &Eng,
const Stmt *S,
ExplodedNode *Pred, void *tag, bool isPrevisit,
bool& respondsToCallback) {
CheckerContext C(Dst, Builder, Eng, Pred, tag,
isPrevisit ? ProgramPoint::PreStmtKind :
ProgramPoint::PostStmtKind, &respondsToCallback, S);
if (isPrevisit)
_PreVisit(C, S);
else
_PostVisit(C, S);
}
bool GR_evalNilReceiver(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
ExprEngine &Eng, const ObjCMessageExpr *ME,
ExplodedNode *Pred, const GRState *state, void *tag) {
CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
0, ME, state);
return evalNilReceiver(C, ME);
}
bool GR_evalCallExpr(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
ExprEngine &Eng, const CallExpr *CE,
ExplodedNode *Pred, void *tag) {
CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
0, CE);
return evalCallExpr(C, CE);
}
// FIXME: Remove the 'tag' option.
void GR_VisitBind(ExplodedNodeSet &Dst,
StmtNodeBuilder &Builder, ExprEngine &Eng,
const Stmt *StoreE, ExplodedNode *Pred, void *tag,
SVal location, SVal val,
bool isPrevisit) {
CheckerContext C(Dst, Builder, Eng, Pred, tag,
isPrevisit ? ProgramPoint::PreStmtKind :
ProgramPoint::PostStmtKind, 0, StoreE);
assert(isPrevisit && "Only previsit supported for now.");
PreVisitBind(C, StoreE, location, val);
}
// FIXME: Remove the 'tag' option.
void GR_visitLocation(ExplodedNodeSet &Dst,
StmtNodeBuilder &Builder,
ExprEngine &Eng,
const Stmt *S,
ExplodedNode *Pred, const GRState *state,
SVal location,
void *tag, bool isLoad) {
CheckerContext C(Dst, Builder, Eng, Pred, tag,
isLoad ? ProgramPoint::PreLoadKind :
ProgramPoint::PreStoreKind, 0, S, state);
visitLocation(C, S, location);
}
void GR_evalDeadSymbols(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
ExprEngine &Eng, const Stmt *S, ExplodedNode *Pred,
SymbolReaper &SymReaper, void *tag) {
CheckerContext C(Dst, Builder, Eng, Pred, tag,
ProgramPoint::PostPurgeDeadSymbolsKind, 0, S);
evalDeadSymbols(C, SymReaper);
}
public:
virtual ~Checker();
virtual void _PreVisit(CheckerContext &C, const Stmt *S) {}
virtual void _PostVisit(CheckerContext &C, const Stmt *S) {}
virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location) {}
virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
SVal location, SVal val) {}
virtual void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper) {}
virtual void evalEndPath(EndPathNodeBuilder &B, void *tag,
ExprEngine &Eng) {}
virtual void MarkLiveSymbols(const GRState *state, SymbolReaper &SymReaper) {}
virtual void VisitBranchCondition(BranchNodeBuilder &Builder,
ExprEngine &Eng,
const Stmt *Condition, void *tag) {}
virtual bool evalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME) {
return false;
}
virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE) {
return false;
}
virtual const GRState *evalAssume(const GRState *state, SVal Cond,
bool Assumption, bool *respondsToCallback) {
*respondsToCallback = false;
return state;
}
virtual bool WantsRegionChangeUpdate(const GRState *state) { return false; }
virtual const GRState *EvalRegionChanges(const GRState *state,
const MemRegion * const *Begin,
const MemRegion * const *End,
bool *respondsToCallback) {
*respondsToCallback = false;
return state;
}
virtual void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B,
ExprEngine &Eng) {}
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,44 @@
//== CheckerHelpers.h - Helper functions for checkers ------------*- C++ -*--=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines CheckerVisitor.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_PATHSENSITIVE_CHECKERHELPERS
#define LLVM_CLANG_GR_PATHSENSITIVE_CHECKERHELPERS
#include "clang/AST/Stmt.h"
namespace clang {
namespace ento {
bool containsMacro(const Stmt *S);
bool containsEnum(const Stmt *S);
bool containsStaticLocal(const Stmt *S);
bool containsBuiltinOffsetOf(const Stmt *S);
template <class T> bool containsStmt(const Stmt *S) {
if (isa<T>(S))
return true;
for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
++I)
if (const Stmt *child = *I)
if (containsStmt<T>(child))
return true;
return false;
}
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,43 @@
//===-- CheckerVisitor.def - Metadata for CheckerVisitor ----------------*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the AST nodes accepted by the CheckerVisitor class.
//
//===---------------------------------------------------------------------===//
#ifndef PREVISIT
#define PREVISIT(NODE, FALLBACK)
#endif
#ifndef POSTVISIT
#define POSTVISIT(NODE, FALLBACK)
#endif
PREVISIT(ArraySubscriptExpr, Stmt)
PREVISIT(BinaryOperator, Stmt)
PREVISIT(CallExpr, GenericCall)
PREVISIT(CStyleCastExpr, CastExpr)
PREVISIT(CXXFunctionalCastExpr, CastExpr)
PREVISIT(CXXOperatorCallExpr, GenericCall)
PREVISIT(CXXMemberCallExpr, GenericCall)
PREVISIT(DeclStmt, Stmt)
PREVISIT(ImplicitCastExpr, CastExpr)
PREVISIT(ObjCAtSynchronizedStmt, Stmt)
PREVISIT(ObjCMessageExpr, Stmt)
PREVISIT(ReturnStmt, Stmt)
POSTVISIT(BlockExpr, Stmt)
POSTVISIT(BinaryOperator, Stmt)
POSTVISIT(CallExpr, GenericCall)
POSTVISIT(CXXOperatorCallExpr, GenericCall)
POSTVISIT(CXXMemberCallExpr, GenericCall)
POSTVISIT(ObjCMessageExpr, Stmt)
#undef PREVISIT
#undef POSTVISIT

View File

@ -0,0 +1,111 @@
//== CheckerVisitor.h - Abstract visitor for checkers ------------*- C++ -*--=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines CheckerVisitor.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_CHECKERVISITOR
#define LLVM_CLANG_GR_CHECKERVISITOR
#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
namespace clang {
namespace ento {
//===----------------------------------------------------------------------===//
// Checker visitor interface. Used by subclasses of Checker to specify their
// own checker visitor logic.
//===----------------------------------------------------------------------===//
/// CheckerVisitor - This class implements a simple visitor for Stmt subclasses.
/// Since Expr derives from Stmt, this also includes support for visiting Exprs.
template<typename ImplClass>
class CheckerVisitor : public Checker {
public:
virtual void _PreVisit(CheckerContext &C, const Stmt *S) {
PreVisit(C, S);
}
virtual void _PostVisit(CheckerContext &C, const Stmt *S) {
PostVisit(C, S);
}
void PreVisit(CheckerContext &C, const Stmt *S) {
switch (S->getStmtClass()) {
default:
assert(false && "Unsupport statement.");
return;
case Stmt::CompoundAssignOperatorClass:
static_cast<ImplClass*>(this)->PreVisitBinaryOperator(C,
static_cast<const BinaryOperator*>(S));
break;
#define PREVISIT(NAME, FALLBACK) \
case Stmt::NAME ## Class:\
static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\
break;
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def"
}
}
void PostVisit(CheckerContext &C, const Stmt *S) {
switch (S->getStmtClass()) {
default:
assert(false && "Unsupport statement.");
return;
case Stmt::CompoundAssignOperatorClass:
static_cast<ImplClass*>(this)->PostVisitBinaryOperator(C,
static_cast<const BinaryOperator*>(S));
break;
#define POSTVISIT(NAME, FALLBACK) \
case Stmt::NAME ## Class:\
static_cast<ImplClass*>(this)->\
PostVisit ## NAME(C,static_cast<const NAME*>(S));\
break;
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def"
}
}
void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE) {
static_cast<ImplClass*>(this)->PreVisitStmt(C, CE);
}
void PostVisitGenericCall(CheckerContext &C, const CallExpr *CE) {
static_cast<ImplClass*>(this)->PostVisitStmt(C, CE);
}
void PreVisitStmt(CheckerContext &C, const Stmt *S) {
*C.respondsToCallback = false;
}
void PostVisitStmt(CheckerContext &C, const Stmt *S) {
*C.respondsToCallback = false;
}
void PreVisitCastExpr(CheckerContext &C, const CastExpr *E) {
static_cast<ImplClass*>(this)->PreVisitStmt(C, E);
}
#define PREVISIT(NAME, FALLBACK) \
void PreVisit ## NAME(CheckerContext &C, const NAME* S) {\
static_cast<ImplClass*>(this)->PreVisit ## FALLBACK(C, S);\
}
#define POSTVISIT(NAME, FALLBACK) \
void PostVisit ## NAME(CheckerContext &C, const NAME* S) {\
static_cast<ImplClass*>(this)->PostVisit ## FALLBACK(C, S);\
}
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def"
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,76 @@
//== ConstraintManager.h - Constraints on symbolic values.-------*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defined the interface to manage constraints on symbolic values.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
#define LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place.
#include "clang/StaticAnalyzer/PathSensitive/Store.h"
namespace llvm {
class APSInt;
}
namespace clang {
namespace ento {
class GRState;
class GRStateManager;
class SubEngine;
class SVal;
class ConstraintManager {
public:
virtual ~ConstraintManager();
virtual const GRState *assume(const GRState *state, DefinedSVal Cond,
bool Assumption) = 0;
std::pair<const GRState*, const GRState*> assumeDual(const GRState *state,
DefinedSVal Cond) {
return std::make_pair(assume(state, Cond, true),
assume(state, Cond, false));
}
virtual const llvm::APSInt* getSymVal(const GRState *state,
SymbolRef sym) const = 0;
virtual bool isEqual(const GRState *state, SymbolRef sym,
const llvm::APSInt& V) const = 0;
virtual const GRState *RemoveDeadBindings(const GRState *state,
SymbolReaper& SymReaper) = 0;
virtual void print(const GRState *state, llvm::raw_ostream& Out,
const char* nl, const char *sep) = 0;
virtual void EndPath(const GRState *state) {}
/// canReasonAbout - Not all ConstraintManagers can accurately reason about
/// all SVal values. This method returns true if the ConstraintManager can
/// reasonably handle a given SVal value. This is typically queried by
/// ExprEngine to determine if the value should be replaced with a
/// conjured symbolic value in order to recover some precision.
virtual bool canReasonAbout(SVal X) const = 0;
};
ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr,
SubEngine &subengine);
ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr,
SubEngine &subengine);
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,542 @@
//==- CoreEngine.h - Path-Sensitive Dataflow Engine ----------------*- C++ -*-//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a generic engine for intraprocedural, path-sensitive,
// dataflow analysis via graph reachability.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_COREENGINE
#define LLVM_CLANG_GR_COREENGINE
#include "clang/AST/Expr.h"
#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/PathSensitive/WorkList.h"
#include "clang/StaticAnalyzer/PathSensitive/BlockCounter.h"
#include "clang/StaticAnalyzer/PathSensitive/SubEngine.h"
#include "llvm/ADT/OwningPtr.h"
namespace clang {
namespace ento {
//===----------------------------------------------------------------------===//
/// CoreEngine - Implements the core logic of the graph-reachability
/// analysis. It traverses the CFG and generates the ExplodedGraph.
/// Program "states" are treated as opaque void pointers.
/// The template class CoreEngine (which subclasses CoreEngine)
/// provides the matching component to the engine that knows the actual types
/// for states. Note that this engine only dispatches to transfer functions
/// at the statement and block-level. The analyses themselves must implement
/// any transfer function logic and the sub-expression level (if any).
class CoreEngine {
friend class StmtNodeBuilder;
friend class BranchNodeBuilder;
friend class IndirectGotoNodeBuilder;
friend class SwitchNodeBuilder;
friend class EndPathNodeBuilder;
friend class CallEnterNodeBuilder;
friend class CallExitNodeBuilder;
public:
typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> >
BlocksAborted;
private:
SubEngine& SubEng;
/// G - The simulation graph. Each node is a (location,state) pair.
llvm::OwningPtr<ExplodedGraph> G;
/// WList - A set of queued nodes that need to be processed by the
/// worklist algorithm. It is up to the implementation of WList to decide
/// the order that nodes are processed.
WorkList* WList;
/// BCounterFactory - A factory object for created BlockCounter objects.
/// These are used to record for key nodes in the ExplodedGraph the
/// number of times different CFGBlocks have been visited along a path.
BlockCounter::Factory BCounterFactory;
/// The locations where we stopped doing work because we visited a location
/// too many times.
BlocksAborted blocksAborted;
void generateNode(const ProgramPoint& Loc, const GRState* State,
ExplodedNode* Pred);
void HandleBlockEdge(const BlockEdge& E, ExplodedNode* Pred);
void HandleBlockEntrance(const BlockEntrance& E, ExplodedNode* Pred);
void HandleBlockExit(const CFGBlock* B, ExplodedNode* Pred);
void HandlePostStmt(const CFGBlock* B, unsigned StmtIdx, ExplodedNode *Pred);
void HandleBranch(const Stmt* Cond, const Stmt* Term, const CFGBlock* B,
ExplodedNode* Pred);
void HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
unsigned Index, ExplodedNode *Pred);
void HandleCallExit(const CallExit &L, ExplodedNode *Pred);
/// Get the initial state from the subengine.
const GRState* getInitialState(const LocationContext *InitLoc) {
return SubEng.getInitialState(InitLoc);
}
void ProcessEndPath(EndPathNodeBuilder& Builder) {
SubEng.ProcessEndPath(Builder);
}
void ProcessElement(const CFGElement E, StmtNodeBuilder& Builder) {
SubEng.ProcessElement(E, Builder);
}
bool ProcessBlockEntrance(const CFGBlock* Blk, const ExplodedNode *Pred,
BlockCounter BC) {
return SubEng.ProcessBlockEntrance(Blk, Pred, BC);
}
void ProcessBranch(const Stmt* Condition, const Stmt* Terminator,
BranchNodeBuilder& Builder) {
SubEng.ProcessBranch(Condition, Terminator, Builder);
}
void ProcessIndirectGoto(IndirectGotoNodeBuilder& Builder) {
SubEng.ProcessIndirectGoto(Builder);
}
void ProcessSwitch(SwitchNodeBuilder& Builder) {
SubEng.ProcessSwitch(Builder);
}
void ProcessCallEnter(CallEnterNodeBuilder &Builder) {
SubEng.ProcessCallEnter(Builder);
}
void ProcessCallExit(CallExitNodeBuilder &Builder) {
SubEng.ProcessCallExit(Builder);
}
private:
CoreEngine(const CoreEngine&); // Do not implement.
CoreEngine& operator=(const CoreEngine&);
public:
/// Construct a CoreEngine object to analyze the provided CFG using
/// a DFS exploration of the exploded graph.
CoreEngine(SubEngine& subengine)
: SubEng(subengine), G(new ExplodedGraph()),
WList(WorkList::MakeBFS()),
BCounterFactory(G->getAllocator()) {}
/// Construct a CoreEngine object to analyze the provided CFG and to
/// use the provided worklist object to execute the worklist algorithm.
/// The CoreEngine object assumes ownership of 'wlist'.
CoreEngine(WorkList* wlist, SubEngine& subengine)
: SubEng(subengine), G(new ExplodedGraph()), WList(wlist),
BCounterFactory(G->getAllocator()) {}
~CoreEngine() {
delete WList;
}
/// getGraph - Returns the exploded graph.
ExplodedGraph& getGraph() { return *G.get(); }
/// takeGraph - Returns the exploded graph. Ownership of the graph is
/// transfered to the caller.
ExplodedGraph* takeGraph() { return G.take(); }
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of
/// steps. Returns true if there is still simulation state on the worklist.
bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
const GRState *InitState);
void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
const GRState *InitState,
ExplodedNodeSet &Dst);
// Functions for external checking of whether we have unfinished work
bool wasBlockAborted() const { return !blocksAborted.empty(); }
bool hasWorkRemaining() const { return wasBlockAborted() || WList->hasWork(); }
WorkList *getWorkList() const { return WList; }
BlocksAborted::const_iterator blocks_aborted_begin() const {
return blocksAborted.begin();
}
BlocksAborted::const_iterator blocks_aborted_end() const {
return blocksAborted.end();
}
};
class StmtNodeBuilder {
CoreEngine& Eng;
const CFGBlock& B;
const unsigned Idx;
ExplodedNode* Pred;
GRStateManager& Mgr;
public:
bool PurgingDeadSymbols;
bool BuildSinks;
bool HasGeneratedNode;
ProgramPoint::Kind PointKind;
const void *Tag;
const GRState* CleanedState;
typedef llvm::SmallPtrSet<ExplodedNode*,5> DeferredTy;
DeferredTy Deferred;
void GenerateAutoTransition(ExplodedNode* N);
public:
StmtNodeBuilder(const CFGBlock* b, unsigned idx, ExplodedNode* N,
CoreEngine* e, GRStateManager &mgr);
~StmtNodeBuilder();
ExplodedNode* getBasePredecessor() const { return Pred; }
// FIXME: This should not be exposed.
WorkList *getWorkList() { return Eng.WList; }
void SetCleanedState(const GRState* St) {
CleanedState = St;
}
BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
unsigned getCurrentBlockCount() const {
return getBlockCounter().getNumVisited(
Pred->getLocationContext()->getCurrentStackFrame(),
B.getBlockID());
}
ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) {
HasGeneratedNode = true;
return generateNodeInternal(PP, St, Pred);
}
ExplodedNode* generateNode(const Stmt *S, const GRState *St,
ExplodedNode *Pred, ProgramPoint::Kind K) {
HasGeneratedNode = true;
if (PurgingDeadSymbols)
K = ProgramPoint::PostPurgeDeadSymbolsKind;
return generateNodeInternal(S, St, Pred, K, Tag);
}
ExplodedNode* generateNode(const Stmt *S, const GRState *St,
ExplodedNode *Pred) {
return generateNode(S, St, Pred, PointKind);
}
ExplodedNode *generateNode(const ProgramPoint &PP, const GRState* State,
ExplodedNode* Pred) {
HasGeneratedNode = true;
return generateNodeInternal(PP, State, Pred);
}
ExplodedNode*
generateNodeInternal(const ProgramPoint &PP, const GRState* State,
ExplodedNode* Pred);
ExplodedNode*
generateNodeInternal(const Stmt* S, const GRState* State, ExplodedNode* Pred,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
const void *tag = 0);
/// getStmt - Return the current block-level expression associated with
/// this builder.
const Stmt* getStmt() const {
CFGStmt CS = B[Idx].getAs<CFGStmt>();
if (CS)
return CS.getStmt();
else
return 0;
}
/// getBlock - Return the CFGBlock associated with the block-level expression
/// of this builder.
const CFGBlock* getBlock() const { return &B; }
unsigned getIndex() const { return Idx; }
const GRState* GetState(ExplodedNode* Pred) const {
if (Pred == getBasePredecessor())
return CleanedState;
else
return Pred->getState();
}
ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
ExplodedNode* Pred, const GRState* St) {
return MakeNode(Dst, S, Pred, St, PointKind);
}
ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S,ExplodedNode* Pred,
const GRState* St, ProgramPoint::Kind K);
ExplodedNode* MakeSinkNode(ExplodedNodeSet& Dst, const Stmt* S,
ExplodedNode* Pred, const GRState* St) {
bool Tmp = BuildSinks;
BuildSinks = true;
ExplodedNode* N = MakeNode(Dst, S, Pred, St);
BuildSinks = Tmp;
return N;
}
};
class BranchNodeBuilder {
CoreEngine& Eng;
const CFGBlock* Src;
const CFGBlock* DstT;
const CFGBlock* DstF;
ExplodedNode* Pred;
typedef llvm::SmallVector<ExplodedNode*,3> DeferredTy;
DeferredTy Deferred;
bool GeneratedTrue;
bool GeneratedFalse;
bool InFeasibleTrue;
bool InFeasibleFalse;
public:
BranchNodeBuilder(const CFGBlock* src, const CFGBlock* dstT,
const CFGBlock* dstF, ExplodedNode* pred, CoreEngine* e)
: Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred),
GeneratedTrue(false), GeneratedFalse(false),
InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {}
~BranchNodeBuilder();
ExplodedNode* getPredecessor() const { return Pred; }
const ExplodedGraph& getGraph() const { return *Eng.G; }
BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
ExplodedNode* generateNode(const GRState* State, bool branch);
const CFGBlock* getTargetBlock(bool branch) const {
return branch ? DstT : DstF;
}
void markInfeasible(bool branch) {
if (branch)
InFeasibleTrue = GeneratedTrue = true;
else
InFeasibleFalse = GeneratedFalse = true;
}
bool isFeasible(bool branch) {
return branch ? !InFeasibleTrue : !InFeasibleFalse;
}
const GRState* getState() const {
return getPredecessor()->getState();
}
};
class IndirectGotoNodeBuilder {
CoreEngine& Eng;
const CFGBlock* Src;
const CFGBlock& DispatchBlock;
const Expr* E;
ExplodedNode* Pred;
public:
IndirectGotoNodeBuilder(ExplodedNode* pred, const CFGBlock* src,
const Expr* e, const CFGBlock* dispatch, CoreEngine* eng)
: Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
class iterator {
CFGBlock::const_succ_iterator I;
friend class IndirectGotoNodeBuilder;
iterator(CFGBlock::const_succ_iterator i) : I(i) {}
public:
iterator& operator++() { ++I; return *this; }
bool operator!=(const iterator& X) const { return I != X.I; }
const LabelStmt* getLabel() const {
return llvm::cast<LabelStmt>((*I)->getLabel());
}
const CFGBlock* getBlock() const {
return *I;
}
};
iterator begin() { return iterator(DispatchBlock.succ_begin()); }
iterator end() { return iterator(DispatchBlock.succ_end()); }
ExplodedNode* generateNode(const iterator& I, const GRState* State,
bool isSink = false);
const Expr* getTarget() const { return E; }
const GRState* getState() const { return Pred->State; }
};
class SwitchNodeBuilder {
CoreEngine& Eng;
const CFGBlock* Src;
const Expr* Condition;
ExplodedNode* Pred;
public:
SwitchNodeBuilder(ExplodedNode* pred, const CFGBlock* src,
const Expr* condition, CoreEngine* eng)
: Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
class iterator {
CFGBlock::const_succ_reverse_iterator I;
friend class SwitchNodeBuilder;
iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {}
public:
iterator& operator++() { ++I; return *this; }
bool operator!=(const iterator &X) const { return I != X.I; }
bool operator==(const iterator &X) const { return I == X.I; }
const CaseStmt* getCase() const {
return llvm::cast<CaseStmt>((*I)->getLabel());
}
const CFGBlock* getBlock() const {
return *I;
}
};
iterator begin() { return iterator(Src->succ_rbegin()+1); }
iterator end() { return iterator(Src->succ_rend()); }
const SwitchStmt *getSwitch() const {
return llvm::cast<SwitchStmt>(Src->getTerminator());
}
ExplodedNode* generateCaseStmtNode(const iterator& I, const GRState* State);
ExplodedNode* generateDefaultCaseNode(const GRState* State,
bool isSink = false);
const Expr* getCondition() const { return Condition; }
const GRState* getState() const { return Pred->State; }
};
class EndPathNodeBuilder {
CoreEngine &Eng;
const CFGBlock& B;
ExplodedNode* Pred;
public:
bool HasGeneratedNode;
public:
EndPathNodeBuilder(const CFGBlock* b, ExplodedNode* N, CoreEngine* e)
: Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {}
~EndPathNodeBuilder();
WorkList &getWorkList() { return *Eng.WList; }
ExplodedNode* getPredecessor() const { return Pred; }
BlockCounter getBlockCounter() const {
return Eng.WList->getBlockCounter();
}
unsigned getCurrentBlockCount() const {
return getBlockCounter().getNumVisited(
Pred->getLocationContext()->getCurrentStackFrame(),
B.getBlockID());
}
ExplodedNode* generateNode(const GRState* State, const void *tag = 0,
ExplodedNode *P = 0);
void GenerateCallExitNode(const GRState *state);
const CFGBlock* getBlock() const { return &B; }
const GRState* getState() const {
return getPredecessor()->getState();
}
};
class CallEnterNodeBuilder {
CoreEngine &Eng;
const ExplodedNode *Pred;
// The call site. For implicit automatic object dtor, this is the trigger
// statement.
const Stmt *CE;
// The context of the callee.
const StackFrameContext *CalleeCtx;
// The parent block of the CallExpr.
const CFGBlock *Block;
// The CFGBlock index of the CallExpr.
unsigned Index;
public:
CallEnterNodeBuilder(CoreEngine &eng, const ExplodedNode *pred,
const Stmt *s, const StackFrameContext *callee,
const CFGBlock *blk, unsigned idx)
: Eng(eng), Pred(pred), CE(s), CalleeCtx(callee), Block(blk), Index(idx) {}
const GRState *getState() const { return Pred->getState(); }
const LocationContext *getLocationContext() const {
return Pred->getLocationContext();
}
const Stmt *getCallExpr() const { return CE; }
const StackFrameContext *getCalleeContext() const { return CalleeCtx; }
const CFGBlock *getBlock() const { return Block; }
unsigned getIndex() const { return Index; }
void generateNode(const GRState *state);
};
class CallExitNodeBuilder {
CoreEngine &Eng;
const ExplodedNode *Pred;
public:
CallExitNodeBuilder(CoreEngine &eng, const ExplodedNode *pred)
: Eng(eng), Pred(pred) {}
const ExplodedNode *getPredecessor() const { return Pred; }
const GRState *getState() const { return Pred->getState(); }
void generateNode(const GRState *state);
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,106 @@
//== Environment.h - Map from Stmt* to Locations/Values ---------*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defined the Environment and EnvironmentManager classes.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_ENVIRONMENT_H
#define LLVM_CLANG_GR_ENVIRONMENT_H
#include "clang/StaticAnalyzer/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
#include "llvm/ADT/ImmutableMap.h"
namespace clang {
class LiveVariables;
namespace ento {
class EnvironmentManager;
class SValBuilder;
/// Environment - An immutable map from Stmts to their current
/// symbolic values (SVals).
///
class Environment {
private:
friend class EnvironmentManager;
// Type definitions.
typedef llvm::ImmutableMap<const Stmt*,SVal> BindingsTy;
// Data.
BindingsTy ExprBindings;
Environment(BindingsTy eb)
: ExprBindings(eb) {}
SVal lookupExpr(const Stmt* E) const;
public:
typedef BindingsTy::iterator iterator;
iterator begin() const { return ExprBindings.begin(); }
iterator end() const { return ExprBindings.end(); }
/// GetSVal - Fetches the current binding of the expression in the
/// Environment.
SVal getSVal(const Stmt* Ex, SValBuilder& svalBuilder) const;
/// Profile - Profile the contents of an Environment object for use
/// in a FoldingSet.
static void Profile(llvm::FoldingSetNodeID& ID, const Environment* env) {
env->ExprBindings.Profile(ID);
}
/// Profile - Used to profile the contents of this object for inclusion
/// in a FoldingSet.
void Profile(llvm::FoldingSetNodeID& ID) const {
Profile(ID, this);
}
bool operator==(const Environment& RHS) const {
return ExprBindings == RHS.ExprBindings;
}
};
class EnvironmentManager {
private:
typedef Environment::BindingsTy::Factory FactoryTy;
FactoryTy F;
public:
EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {}
~EnvironmentManager() {}
Environment getInitialEnvironment() {
return Environment(F.getEmptyMap());
}
/// Bind the value 'V' to the statement 'S'.
Environment bindExpr(Environment Env, const Stmt *S, SVal V,
bool Invalidate);
/// Bind the location 'location' and value 'V' to the statement 'S'. This
/// is used when simulating loads/stores.
Environment bindExprAndLocation(Environment Env, const Stmt *S, SVal location,
SVal V);
Environment RemoveDeadBindings(Environment Env,
SymbolReaper &SymReaper, const GRState *ST,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,435 @@
//=-- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -*- C++ -*-------==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the template classes ExplodedNode and ExplodedGraph,
// which represent a path-sensitive, intra-procedural "exploded graph."
// See "Precise interprocedural dataflow analysis via graph reachability"
// by Reps, Horwitz, and Sagiv
// (http://portal.acm.org/citation.cfm?id=199462) for the definition of an
// exploded graph.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_EXPLODEDGRAPH
#define LLVM_CLANG_GR_EXPLODEDGRAPH
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/Decl.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/Allocator.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/Support/Casting.h"
#include "clang/Analysis/Support/BumpVector.h"
namespace clang {
class CFG;
namespace ento {
class GRState;
class ExplodedGraph;
//===----------------------------------------------------------------------===//
// ExplodedGraph "implementation" classes. These classes are not typed to
// contain a specific kind of state. Typed-specialized versions are defined
// on top of these classes.
//===----------------------------------------------------------------------===//
class ExplodedNode : public llvm::FoldingSetNode {
friend class ExplodedGraph;
friend class CoreEngine;
friend class StmtNodeBuilder;
friend class BranchNodeBuilder;
friend class IndirectGotoNodeBuilder;
friend class SwitchNodeBuilder;
friend class EndPathNodeBuilder;
class NodeGroup {
enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 };
uintptr_t P;
unsigned getKind() const {
return P & 0x1;
}
void* getPtr() const {
assert (!getFlag());
return reinterpret_cast<void*>(P & ~Mask);
}
ExplodedNode *getNode() const {
return reinterpret_cast<ExplodedNode*>(getPtr());
}
public:
NodeGroup() : P(0) {}
ExplodedNode **begin() const;
ExplodedNode **end() const;
unsigned size() const;
bool empty() const { return (P & ~Mask) == 0; }
void addNode(ExplodedNode* N, ExplodedGraph &G);
void setFlag() {
assert(P == 0);
P = AuxFlag;
}
bool getFlag() const {
return P & AuxFlag ? true : false;
}
};
/// Location - The program location (within a function body) associated
/// with this node.
const ProgramPoint Location;
/// State - The state associated with this node.
const GRState* State;
/// Preds - The predecessors of this node.
NodeGroup Preds;
/// Succs - The successors of this node.
NodeGroup Succs;
public:
explicit ExplodedNode(const ProgramPoint& loc, const GRState* state)
: Location(loc), State(state) {}
/// getLocation - Returns the edge associated with the given node.
ProgramPoint getLocation() const { return Location; }
const LocationContext *getLocationContext() const {
return getLocation().getLocationContext();
}
const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); }
CFG &getCFG() const { return *getLocationContext()->getCFG(); }
ParentMap &getParentMap() const {return getLocationContext()->getParentMap();}
LiveVariables &getLiveVariables() const {
return *getLocationContext()->getLiveVariables();
}
const GRState* getState() const { return State; }
template <typename T>
const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); }
static void Profile(llvm::FoldingSetNodeID &ID,
const ProgramPoint& Loc, const GRState* state) {
ID.Add(Loc);
ID.AddPointer(state);
}
void Profile(llvm::FoldingSetNodeID& ID) const {
Profile(ID, getLocation(), getState());
}
/// addPredeccessor - Adds a predecessor to the current node, and
/// in tandem add this node as a successor of the other node.
void addPredecessor(ExplodedNode* V, ExplodedGraph &G);
unsigned succ_size() const { return Succs.size(); }
unsigned pred_size() const { return Preds.size(); }
bool succ_empty() const { return Succs.empty(); }
bool pred_empty() const { return Preds.empty(); }
bool isSink() const { return Succs.getFlag(); }
void markAsSink() { Succs.setFlag(); }
ExplodedNode* getFirstPred() {
return pred_empty() ? NULL : *(pred_begin());
}
const ExplodedNode* getFirstPred() const {
return const_cast<ExplodedNode*>(this)->getFirstPred();
}
// Iterators over successor and predecessor vertices.
typedef ExplodedNode** succ_iterator;
typedef const ExplodedNode* const * const_succ_iterator;
typedef ExplodedNode** pred_iterator;
typedef const ExplodedNode* const * const_pred_iterator;
pred_iterator pred_begin() { return Preds.begin(); }
pred_iterator pred_end() { return Preds.end(); }
const_pred_iterator pred_begin() const {
return const_cast<ExplodedNode*>(this)->pred_begin();
}
const_pred_iterator pred_end() const {
return const_cast<ExplodedNode*>(this)->pred_end();
}
succ_iterator succ_begin() { return Succs.begin(); }
succ_iterator succ_end() { return Succs.end(); }
const_succ_iterator succ_begin() const {
return const_cast<ExplodedNode*>(this)->succ_begin();
}
const_succ_iterator succ_end() const {
return const_cast<ExplodedNode*>(this)->succ_end();
}
// For debugging.
public:
class Auditor {
public:
virtual ~Auditor();
virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst) = 0;
};
static void SetAuditor(Auditor* A);
};
// FIXME: Is this class necessary?
class InterExplodedGraphMap {
llvm::DenseMap<const ExplodedNode*, ExplodedNode*> M;
friend class ExplodedGraph;
public:
ExplodedNode* getMappedNode(const ExplodedNode* N) const;
InterExplodedGraphMap() {}
virtual ~InterExplodedGraphMap() {}
};
class ExplodedGraph {
protected:
friend class CoreEngine;
// Type definitions.
typedef llvm::SmallVector<ExplodedNode*,2> RootsTy;
typedef llvm::SmallVector<ExplodedNode*,10> EndNodesTy;
/// Roots - The roots of the simulation graph. Usually there will be only
/// one, but clients are free to establish multiple subgraphs within a single
/// SimulGraph. Moreover, these subgraphs can often merge when paths from
/// different roots reach the same state at the same program location.
RootsTy Roots;
/// EndNodes - The nodes in the simulation graph which have been
/// specially marked as the endpoint of an abstract simulation path.
EndNodesTy EndNodes;
/// Nodes - The nodes in the graph.
llvm::FoldingSet<ExplodedNode> Nodes;
/// BVC - Allocator and context for allocating nodes and their predecessor
/// and successor groups.
BumpVectorContext BVC;
/// NumNodes - The number of nodes in the graph.
unsigned NumNodes;
public:
/// getNode - Retrieve the node associated with a (Location,State) pair,
/// where the 'Location' is a ProgramPoint in the CFG. If no node for
/// this pair exists, it is created. IsNew is set to true if
/// the node was freshly created.
ExplodedNode* getNode(const ProgramPoint& L, const GRState *State,
bool* IsNew = 0);
ExplodedGraph* MakeEmptyGraph() const {
return new ExplodedGraph();
}
/// addRoot - Add an untyped node to the set of roots.
ExplodedNode* addRoot(ExplodedNode* V) {
Roots.push_back(V);
return V;
}
/// addEndOfPath - Add an untyped node to the set of EOP nodes.
ExplodedNode* addEndOfPath(ExplodedNode* V) {
EndNodes.push_back(V);
return V;
}
ExplodedGraph() : NumNodes(0) {}
~ExplodedGraph() {}
unsigned num_roots() const { return Roots.size(); }
unsigned num_eops() const { return EndNodes.size(); }
bool empty() const { return NumNodes == 0; }
unsigned size() const { return NumNodes; }
// Iterators.
typedef ExplodedNode NodeTy;
typedef llvm::FoldingSet<ExplodedNode> AllNodesTy;
typedef NodeTy** roots_iterator;
typedef NodeTy* const * const_roots_iterator;
typedef NodeTy** eop_iterator;
typedef NodeTy* const * const_eop_iterator;
typedef AllNodesTy::iterator node_iterator;
typedef AllNodesTy::const_iterator const_node_iterator;
node_iterator nodes_begin() { return Nodes.begin(); }
node_iterator nodes_end() { return Nodes.end(); }
const_node_iterator nodes_begin() const { return Nodes.begin(); }
const_node_iterator nodes_end() const { return Nodes.end(); }
roots_iterator roots_begin() { return Roots.begin(); }
roots_iterator roots_end() { return Roots.end(); }
const_roots_iterator roots_begin() const { return Roots.begin(); }
const_roots_iterator roots_end() const { return Roots.end(); }
eop_iterator eop_begin() { return EndNodes.begin(); }
eop_iterator eop_end() { return EndNodes.end(); }
const_eop_iterator eop_begin() const { return EndNodes.begin(); }
const_eop_iterator eop_end() const { return EndNodes.end(); }
llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); }
BumpVectorContext &getNodeAllocator() { return BVC; }
typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> NodeMap;
std::pair<ExplodedGraph*, InterExplodedGraphMap*>
Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
llvm::DenseMap<const void*, const void*> *InverseMap = 0) const;
ExplodedGraph* TrimInternal(const ExplodedNode* const * NBeg,
const ExplodedNode* const * NEnd,
InterExplodedGraphMap *M,
llvm::DenseMap<const void*, const void*> *InverseMap) const;
};
class ExplodedNodeSet {
typedef llvm::SmallPtrSet<ExplodedNode*,5> ImplTy;
ImplTy Impl;
public:
ExplodedNodeSet(ExplodedNode* N) {
assert (N && !static_cast<ExplodedNode*>(N)->isSink());
Impl.insert(N);
}
ExplodedNodeSet() {}
inline void Add(ExplodedNode* N) {
if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N);
}
ExplodedNodeSet& operator=(const ExplodedNodeSet &X) {
Impl = X.Impl;
return *this;
}
typedef ImplTy::iterator iterator;
typedef ImplTy::const_iterator const_iterator;
unsigned size() const { return Impl.size(); }
bool empty() const { return Impl.empty(); }
void clear() { Impl.clear(); }
void insert(const ExplodedNodeSet &S) {
if (empty())
Impl = S.Impl;
else
Impl.insert(S.begin(), S.end());
}
inline iterator begin() { return Impl.begin(); }
inline iterator end() { return Impl.end(); }
inline const_iterator begin() const { return Impl.begin(); }
inline const_iterator end() const { return Impl.end(); }
};
} // end GR namespace
} // end clang namespace
// GraphTraits
namespace llvm {
template<> struct GraphTraits<clang::ento::ExplodedNode*> {
typedef clang::ento::ExplodedNode NodeType;
typedef NodeType::succ_iterator ChildIteratorType;
typedef llvm::df_iterator<NodeType*> nodes_iterator;
static inline NodeType* getEntryNode(NodeType* N) {
return N;
}
static inline ChildIteratorType child_begin(NodeType* N) {
return N->succ_begin();
}
static inline ChildIteratorType child_end(NodeType* N) {
return N->succ_end();
}
static inline nodes_iterator nodes_begin(NodeType* N) {
return df_begin(N);
}
static inline nodes_iterator nodes_end(NodeType* N) {
return df_end(N);
}
};
template<> struct GraphTraits<const clang::ento::ExplodedNode*> {
typedef const clang::ento::ExplodedNode NodeType;
typedef NodeType::const_succ_iterator ChildIteratorType;
typedef llvm::df_iterator<NodeType*> nodes_iterator;
static inline NodeType* getEntryNode(NodeType* N) {
return N;
}
static inline ChildIteratorType child_begin(NodeType* N) {
return N->succ_begin();
}
static inline ChildIteratorType child_end(NodeType* N) {
return N->succ_end();
}
static inline nodes_iterator nodes_begin(NodeType* N) {
return df_begin(N);
}
static inline nodes_iterator nodes_end(NodeType* N) {
return df_end(N);
}
};
} // end llvm namespace
#endif

View File

@ -0,0 +1,544 @@
//===-- ExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a meta-engine for path-sensitive dataflow analysis that
// is built on CoreEngine, but provides the boilerplate to execute transfer
// functions and build the ExplodedGraph at the expression level.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_EXPRENGINE
#define LLVM_CLANG_GR_EXPRENGINE
#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/PathSensitive/SubEngine.h"
#include "clang/StaticAnalyzer/PathSensitive/CoreEngine.h"
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
#include "clang/AST/Type.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtObjC.h"
namespace clang {
class ObjCForCollectionStmt;
namespace ento {
class AnalysisManager;
class Checker;
class ExprEngine : public SubEngine {
AnalysisManager &AMgr;
CoreEngine Engine;
/// G - the simulation graph.
ExplodedGraph& G;
/// Builder - The current StmtNodeBuilder which is used when building the
/// nodes for a given statement.
StmtNodeBuilder* Builder;
/// StateMgr - Object that manages the data for all created states.
GRStateManager StateMgr;
/// SymMgr - Object that manages the symbol information.
SymbolManager& SymMgr;
/// svalBuilder - SValBuilder object that creates SVals from expressions.
SValBuilder &svalBuilder;
/// EntryNode - The immediate predecessor node.
ExplodedNode* EntryNode;
/// CleanedState - The state for EntryNode "cleaned" of all dead
/// variables and symbols (as determined by a liveness analysis).
const GRState* CleanedState;
/// currentStmt - The current block-level statement.
const Stmt* currentStmt;
// Obj-C Class Identifiers.
IdentifierInfo* NSExceptionII;
// Obj-C Selectors.
Selector* NSExceptionInstanceRaiseSelectors;
Selector RaiseSel;
enum CallbackKind {
PreVisitStmtCallback,
PostVisitStmtCallback,
ProcessAssumeCallback,
EvalRegionChangesCallback
};
typedef uint32_t CallbackTag;
/// GetCallbackTag - Create a tag for a certain kind of callback. The 'Sub'
/// argument can be used to differentiate callbacks that depend on another
/// value from a small set of possibilities, such as statement classes.
static inline CallbackTag GetCallbackTag(CallbackKind K, uint32_t Sub = 0) {
assert(Sub == ((Sub << 8) >> 8) && "Tag sub-kind must fit into 24 bits");
return K | (Sub << 8);
}
typedef llvm::DenseMap<void *, unsigned> CheckerMap;
typedef std::vector<std::pair<void *, Checker*> > CheckersOrdered;
typedef llvm::DenseMap<CallbackTag, CheckersOrdered *> CheckersOrderedCache;
/// A registration map from checker tag to the index into the
/// ordered checkers vector.
CheckerMap CheckerM;
/// An ordered vector of checkers that are called when evaluating
/// various expressions and statements.
CheckersOrdered Checkers;
/// A map used for caching the checkers that respond to the callback for
/// a particular callback tag.
CheckersOrderedCache COCache;
/// The BugReporter associated with this engine. It is important that
/// this object be placed at the very end of member variables so that its
/// destructor is called before the rest of the ExprEngine is destroyed.
GRBugReporter BR;
llvm::OwningPtr<TransferFuncs> TF;
public:
ExprEngine(AnalysisManager &mgr, TransferFuncs *tf);
~ExprEngine();
void ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) {
Engine.ExecuteWorkList(L, Steps, 0);
}
/// Execute the work list with an initial state. Nodes that reaches the exit
/// of the function are added into the Dst set, which represent the exit
/// state of the function call.
void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
const GRState *InitState,
ExplodedNodeSet &Dst) {
Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst);
}
/// getContext - Return the ASTContext associated with this analysis.
ASTContext& getContext() const { return AMgr.getASTContext(); }
virtual AnalysisManager &getAnalysisManager() { return AMgr; }
SValBuilder &getSValBuilder() { return svalBuilder; }
TransferFuncs& getTF() { return *TF; }
BugReporter& getBugReporter() { return BR; }
StmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; }
// FIXME: Remove once TransferFuncs is no longer referenced.
void setTransferFunction(TransferFuncs* tf);
/// ViewGraph - Visualize the ExplodedGraph created by executing the
/// simulation.
void ViewGraph(bool trim = false);
void ViewGraph(ExplodedNode** Beg, ExplodedNode** End);
/// getInitialState - Return the initial state used for the root vertex
/// in the ExplodedGraph.
const GRState* getInitialState(const LocationContext *InitLoc);
ExplodedGraph& getGraph() { return G; }
const ExplodedGraph& getGraph() const { return G; }
template <typename CHECKER>
void registerCheck(CHECKER *check) {
unsigned entry = Checkers.size();
void *tag = CHECKER::getTag();
Checkers.push_back(std::make_pair(tag, check));
CheckerM[tag] = entry;
}
Checker *lookupChecker(void *tag) const;
template <typename CHECKER>
CHECKER *getChecker() const {
return static_cast<CHECKER*>(lookupChecker(CHECKER::getTag()));
}
/// ProcessElement - Called by CoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a CFG element.
void ProcessElement(const CFGElement E, StmtNodeBuilder& builder);
void ProcessStmt(const CFGStmt S, StmtNodeBuilder &builder);
void ProcessInitializer(const CFGInitializer I, StmtNodeBuilder &builder);
void ProcessImplicitDtor(const CFGImplicitDtor D, StmtNodeBuilder &builder);
void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D,
StmtNodeBuilder &builder);
void ProcessBaseDtor(const CFGBaseDtor D, StmtNodeBuilder &builder);
void ProcessMemberDtor(const CFGMemberDtor D, StmtNodeBuilder &builder);
void ProcessTemporaryDtor(const CFGTemporaryDtor D,
StmtNodeBuilder &builder);
/// ProcessBlockEntrance - Called by CoreEngine when start processing
/// a CFGBlock. This method returns true if the analysis should continue
/// exploring the given path, and false otherwise.
bool ProcessBlockEntrance(const CFGBlock* B, const ExplodedNode *Pred,
BlockCounter BC);
/// ProcessBranch - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
void ProcessBranch(const Stmt* Condition, const Stmt* Term,
BranchNodeBuilder& builder);
/// ProcessIndirectGoto - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder);
/// ProcessSwitch - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a switch statement.
void ProcessSwitch(SwitchNodeBuilder& builder);
/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
void ProcessEndPath(EndPathNodeBuilder& builder);
/// Generate the entry node of the callee.
void ProcessCallEnter(CallEnterNodeBuilder &builder);
/// Generate the first post callsite node.
void ProcessCallExit(CallExitNodeBuilder &builder);
/// Called by CoreEngine when the analysis worklist has terminated.
void ProcessEndWorklist(bool hasWorkRemaining);
/// evalAssume - Callback function invoked by the ConstraintManager when
/// making assumptions about state values.
const GRState *ProcessAssume(const GRState *state, SVal cond,bool assumption);
/// WantsRegionChangeUpdate - Called by GRStateManager to determine if a
/// region change should trigger a ProcessRegionChanges update.
bool WantsRegionChangeUpdate(const GRState* state);
/// ProcessRegionChanges - Called by GRStateManager whenever a change is made
/// to the store. Used to update checkers that track region values.
const GRState* ProcessRegionChanges(const GRState *state,
const MemRegion * const *Begin,
const MemRegion * const *End);
virtual GRStateManager& getStateManager() { return StateMgr; }
StoreManager& getStoreManager() { return StateMgr.getStoreManager(); }
ConstraintManager& getConstraintManager() {
return StateMgr.getConstraintManager();
}
// FIXME: Remove when we migrate over to just using SValBuilder.
BasicValueFactory& getBasicVals() {
return StateMgr.getBasicVals();
}
const BasicValueFactory& getBasicVals() const {
return StateMgr.getBasicVals();
}
// FIXME: Remove when we migrate over to just using ValueManager.
SymbolManager& getSymbolManager() { return SymMgr; }
const SymbolManager& getSymbolManager() const { return SymMgr; }
// Functions for external checking of whether we have unfinished work
bool wasBlockAborted() const { return Engine.wasBlockAborted(); }
bool hasEmptyWorkList() const { return !Engine.getWorkList()->hasWork(); }
bool hasWorkRemaining() const {
return wasBlockAborted() || Engine.getWorkList()->hasWork();
}
const CoreEngine &getCoreEngine() const { return Engine; }
protected:
const GRState* GetState(ExplodedNode* N) {
return N == EntryNode ? CleanedState : N->getState();
}
public:
ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
ExplodedNode* Pred, const GRState* St,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
const void *tag = 0);
/// CheckerVisit - Dispatcher for performing checker-specific logic
/// at specific statements.
void CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
CallbackKind Kind);
bool CheckerEvalCall(const CallExpr *CE,
ExplodedNodeSet &Dst,
ExplodedNode *Pred);
void CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
ExplodedNodeSet &Dst,
const GRState *state,
ExplodedNode *Pred);
void CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst,
ExplodedNodeSet &Src, SVal location, SVal val,
bool isPrevisit);
/// Visit - Transfer function logic for all statements. Dispatches to
/// other functions that handle specific kinds of statements.
void Visit(const Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst);
/// VisitArraySubscriptExpr - Transfer function for array accesses.
void VisitLvalArraySubscriptExpr(const ArraySubscriptExpr* Ex,
ExplodedNode* Pred,
ExplodedNodeSet& Dst);
/// VisitAsmStmt - Transfer function logic for inline asm.
void VisitAsmStmt(const AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst);
void VisitAsmStmtHelperOutputs(const AsmStmt* A,
AsmStmt::const_outputs_iterator I,
AsmStmt::const_outputs_iterator E,
ExplodedNode* Pred, ExplodedNodeSet& Dst);
void VisitAsmStmtHelperInputs(const AsmStmt* A,
AsmStmt::const_inputs_iterator I,
AsmStmt::const_inputs_iterator E,
ExplodedNode* Pred, ExplodedNodeSet& Dst);
/// VisitBlockExpr - Transfer function logic for BlockExprs.
void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
/// VisitBinaryOperator - Transfer function logic for binary operators.
void VisitBinaryOperator(const BinaryOperator* B, ExplodedNode* Pred,
ExplodedNodeSet& Dst);
/// VisitCall - Transfer function for function calls.
void VisitCall(const CallExpr* CE, ExplodedNode* Pred,
CallExpr::const_arg_iterator AI,
CallExpr::const_arg_iterator AE,
ExplodedNodeSet& Dst);
/// VisitCast - Transfer function logic for all casts (implicit and explicit).
void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
/// VisitCompoundLiteralExpr - Transfer function logic for compound literals.
void VisitCompoundLiteralExpr(const CompoundLiteralExpr* CL,
ExplodedNode* Pred, ExplodedNodeSet& Dst);
/// Transfer function logic for DeclRefExprs and BlockDeclRefExprs.
void VisitCommonDeclRefExpr(const Expr* DR, const NamedDecl *D,
ExplodedNode* Pred, ExplodedNodeSet& Dst);
/// VisitDeclStmt - Transfer function logic for DeclStmts.
void VisitDeclStmt(const DeclStmt* DS, ExplodedNode* Pred,
ExplodedNodeSet& Dst);
/// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
void VisitGuardedExpr(const Expr* Ex, const Expr* L, const Expr* R,
ExplodedNode* Pred, ExplodedNodeSet& Dst);
/// VisitCondInit - Transfer function for handling the initialization
/// of a condition variable in an IfStmt, SwitchStmt, etc.
void VisitCondInit(const VarDecl *VD, const Stmt *S, ExplodedNode *Pred,
ExplodedNodeSet& Dst);
void VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred,
ExplodedNodeSet& Dst);
/// VisitLogicalExpr - Transfer function logic for '&&', '||'
void VisitLogicalExpr(const BinaryOperator* B, ExplodedNode* Pred,
ExplodedNodeSet& Dst);
/// VisitMemberExpr - Transfer function for member expressions.
void VisitMemberExpr(const MemberExpr* M, ExplodedNode* Pred,
ExplodedNodeSet& Dst);
/// Transfer function logic for ObjCAtSynchronizedStmts.
void VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
/// Transfer function logic for computing the lvalue of an Objective-C ivar.
void VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* DR, ExplodedNode* Pred,
ExplodedNodeSet& Dst);
/// VisitObjCForCollectionStmt - Transfer function logic for
/// ObjCForCollectionStmt.
void VisitObjCForCollectionStmt(const ObjCForCollectionStmt* S,
ExplodedNode* Pred, ExplodedNodeSet& Dst);
void VisitObjCForCollectionStmtAux(const ObjCForCollectionStmt* S,
ExplodedNode* Pred,
ExplodedNodeSet& Dst, SVal ElementV);
/// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
void VisitObjCMessageExpr(const ObjCMessageExpr* ME, ExplodedNode* Pred,
ExplodedNodeSet& Dst);
/// VisitReturnStmt - Transfer function logic for return statements.
void VisitReturnStmt(const ReturnStmt* R, ExplodedNode* Pred,
ExplodedNodeSet& Dst);
/// VisitOffsetOfExpr - Transfer function for offsetof.
void VisitOffsetOfExpr(const OffsetOfExpr* Ex, ExplodedNode* Pred,
ExplodedNodeSet& Dst);
/// VisitSizeOfAlignOfExpr - Transfer function for sizeof.
void VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex, ExplodedNode* Pred,
ExplodedNodeSet& Dst);
/// VisitUnaryOperator - Transfer function logic for unary operators.
void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode* Pred,
ExplodedNodeSet& Dst);
void VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet & Dst);
void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *expr,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
VisitCXXConstructExpr(expr, 0, Pred, Dst);
}
void VisitCXXConstructExpr(const CXXConstructExpr *E, const MemRegion *Dest,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
void VisitCXXDestructor(const CXXDestructorDecl *DD,
const MemRegion *Dest, const Stmt *S,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
void VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
void VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
void VisitAggExpr(const Expr *E, const MemRegion *Dest, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
/// Create a C++ temporary object for an rvalue.
void CreateCXXTemporaryObject(const Expr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
/// Synthesize CXXThisRegion.
const CXXThisRegion *getCXXThisRegion(const CXXRecordDecl *RD,
const StackFrameContext *SFC);
const CXXThisRegion *getCXXThisRegion(const CXXMethodDecl *decl,
const StackFrameContext *frameCtx);
/// Evaluate arguments with a work list algorithm.
void evalArguments(ConstExprIterator AI, ConstExprIterator AE,
const FunctionProtoType *FnType,
ExplodedNode *Pred, ExplodedNodeSet &Dst,
bool FstArgAsLValue = false);
/// Evaluate method call itself. Used for CXXMethodCallExpr and
/// CXXOperatorCallExpr.
void evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD,
const Expr *ThisExpr, ExplodedNode *Pred,
ExplodedNodeSet &Src, ExplodedNodeSet &Dst);
/// evalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
/// with those assumptions.
void evalEagerlyAssume(ExplodedNodeSet& Dst, ExplodedNodeSet& Src,
const Expr *Ex);
SVal evalMinus(SVal X) {
return X.isValid() ? svalBuilder.evalMinus(cast<NonLoc>(X)) : X;
}
SVal evalComplement(SVal X) {
return X.isValid() ? svalBuilder.evalComplement(cast<NonLoc>(X)) : X;
}
public:
SVal evalBinOp(const GRState *state, BinaryOperator::Opcode op,
NonLoc L, NonLoc R, QualType T) {
return svalBuilder.evalBinOpNN(state, op, L, R, T);
}
SVal evalBinOp(const GRState *state, BinaryOperator::Opcode op,
NonLoc L, SVal R, QualType T) {
return R.isValid() ? svalBuilder.evalBinOpNN(state,op,L, cast<NonLoc>(R), T) : R;
}
SVal evalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
SVal LHS, SVal RHS, QualType T) {
return svalBuilder.evalBinOp(ST, Op, LHS, RHS, T);
}
protected:
void evalObjCMessageExpr(ExplodedNodeSet& Dst, const ObjCMessageExpr* ME,
ExplodedNode* Pred, const GRState *state) {
assert (Builder && "StmtNodeBuilder must be defined.");
getTF().evalObjCMessageExpr(Dst, *this, *Builder, ME, Pred, state);
}
const GRState* MarkBranch(const GRState* St, const Stmt* Terminator,
bool branchTaken);
/// evalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by evalStore, VisitDeclStmt, and others.
void evalBind(ExplodedNodeSet& Dst, const Stmt* StoreE, ExplodedNode* Pred,
const GRState* St, SVal location, SVal Val,
bool atDeclInit = false);
public:
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
// FIXME: Comment on the meaning of the arguments, when 'St' may not
// be the same as Pred->state, and when 'location' may not be the
// same as state->getLValue(Ex).
/// Simulate a read of the result of Ex.
void evalLoad(ExplodedNodeSet& Dst, const Expr* Ex, ExplodedNode* Pred,
const GRState* St, SVal location, const void *tag = 0,
QualType LoadTy = QualType());
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
void evalStore(ExplodedNodeSet& Dst, const Expr* AssignE, const Expr* StoreE,
ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val,
const void *tag = 0);
private:
void evalLoadCommon(ExplodedNodeSet& Dst, const Expr* Ex, ExplodedNode* Pred,
const GRState* St, SVal location, const void *tag,
QualType LoadTy);
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
void evalLocation(ExplodedNodeSet &Dst, const Stmt *S, ExplodedNode* Pred,
const GRState* St, SVal location,
const void *tag, bool isLoad);
bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred);
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,81 @@
//===-- ExprEngineBuilders.h - "Builder" classes for ExprEngine ---*- C++ -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines smart builder "references" which are used to marshal
// builders between ExprEngine objects and their related components.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_EXPRENGINE_BUILDERS
#define LLVM_CLANG_GR_EXPRENGINE_BUILDERS
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
#include "clang/Analysis/Support/SaveAndRestore.h"
namespace clang {
namespace ento {
class StmtNodeBuilderRef {
ExplodedNodeSet &Dst;
StmtNodeBuilder &B;
ExprEngine& Eng;
ExplodedNode* Pred;
const GRState* state;
const Stmt* stmt;
const unsigned OldSize;
const bool AutoCreateNode;
SaveAndRestore<bool> OldSink;
SaveAndRestore<const void*> OldTag;
SaveOr OldHasGen;
private:
friend class ExprEngine;
StmtNodeBuilderRef(); // do not implement
void operator=(const StmtNodeBuilderRef&); // do not implement
StmtNodeBuilderRef(ExplodedNodeSet &dst,
StmtNodeBuilder &builder,
ExprEngine& eng,
ExplodedNode* pred,
const GRState *st,
const Stmt* s, bool auto_create_node)
: Dst(dst), B(builder), Eng(eng), Pred(pred),
state(st), stmt(s), OldSize(Dst.size()), AutoCreateNode(auto_create_node),
OldSink(B.BuildSinks), OldTag(B.Tag), OldHasGen(B.HasGeneratedNode) {}
public:
~StmtNodeBuilderRef() {
// Handle the case where no nodes where generated. Auto-generate that
// contains the updated state if we aren't generating sinks.
if (!B.BuildSinks && Dst.size() == OldSize && !B.HasGeneratedNode) {
if (AutoCreateNode)
B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
else
Dst.Add(Pred);
}
}
const GRState *getState() { return state; }
GRStateManager& getStateManager() {
return Eng.getStateManager();
}
ExplodedNode* MakeNode(const GRState* state) {
return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
}
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,760 @@
//== GRState.h - Path-sensitive "State" for tracking values -----*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines SymbolRef, ExprBindKey, and GRState*.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_VALUESTATE_H
#define LLVM_CLANG_GR_VALUESTATE_H
#include "clang/StaticAnalyzer/PathSensitive/ConstraintManager.h"
#include "clang/StaticAnalyzer/PathSensitive/Environment.h"
#include "clang/StaticAnalyzer/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/Support/Casting.h"
namespace llvm {
class APSInt;
class BumpPtrAllocator;
class raw_ostream;
}
namespace clang {
class ASTContext;
namespace ento {
class GRStateManager;
class Checker;
typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&,
SubEngine&);
typedef StoreManager* (*StoreManagerCreator)(GRStateManager&);
//===----------------------------------------------------------------------===//
// GRStateTrait - Traits used by the Generic Data Map of a GRState.
//===----------------------------------------------------------------------===//
template <typename T> struct GRStatePartialTrait;
template <typename T> struct GRStateTrait {
typedef typename T::data_type data_type;
static inline void* GDMIndex() { return &T::TagInt; }
static inline void* MakeVoidPtr(data_type D) { return (void*) D; }
static inline data_type MakeData(void* const* P) {
return P ? (data_type) *P : (data_type) 0;
}
};
class GRStateManager;
/// GRState - This class encapsulates:
///
/// 1. A mapping from expressions to values (Environment)
/// 2. A mapping from locations to values (Store)
/// 3. Constraints on symbolic values (GenericDataMap)
///
/// Together these represent the "abstract state" of a program.
///
/// GRState is intended to be used as a functional object; that is,
/// once it is created and made "persistent" in a FoldingSet, its
/// values will never change.
class GRState : public llvm::FoldingSetNode {
public:
typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy;
typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
private:
void operator=(const GRState& R) const; // Do not implement.
friend class GRStateManager;
GRStateManager *StateMgr;
Environment Env; // Maps a Stmt to its current SVal.
Store St; // Maps a location to its current value.
GenericDataMap GDM; // Custom data stored by a client of this class.
/// makeWithStore - Return a GRState with the same values as the current
/// state with the exception of using the specified Store.
const GRState *makeWithStore(Store store) const;
public:
/// This ctor is used when creating the first GRState object.
GRState(GRStateManager *mgr, const Environment& env,
Store st, GenericDataMap gdm)
: StateMgr(mgr),
Env(env),
St(st),
GDM(gdm) {}
/// Copy ctor - We must explicitly define this or else the "Next" ptr
/// in FoldingSetNode will also get copied.
GRState(const GRState& RHS)
: llvm::FoldingSetNode(),
StateMgr(RHS.StateMgr),
Env(RHS.Env),
St(RHS.St),
GDM(RHS.GDM) {}
/// getStateManager - Return the GRStateManager associated with this state.
GRStateManager &getStateManager() const {
return *StateMgr;
}
/// getEnvironment - Return the environment associated with this state.
/// The environment is the mapping from expressions to values.
const Environment& getEnvironment() const { return Env; }
/// getStore - Return the store associated with this state. The store
/// is a mapping from locations to values.
Store getStore() const { return St; }
void setStore(Store s) { St = s; }
/// getGDM - Return the generic data map associated with this state.
GenericDataMap getGDM() const { return GDM; }
void setGDM(GenericDataMap gdm) { GDM = gdm; }
/// Profile - Profile the contents of a GRState object for use in a
/// FoldingSet. Two GRState objects are considered equal if they
/// have the same Environment, Store, and GenericDataMap.
static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) {
V->Env.Profile(ID);
ID.AddPointer(V->St);
V->GDM.Profile(ID);
}
/// Profile - Used to profile the contents of this object for inclusion
/// in a FoldingSet.
void Profile(llvm::FoldingSetNodeID& ID) const {
Profile(ID, this);
}
BasicValueFactory &getBasicVals() const;
SymbolManager &getSymbolManager() const;
//==---------------------------------------------------------------------==//
// Constraints on values.
//==---------------------------------------------------------------------==//
//
// Each GRState records constraints on symbolic values. These constraints
// are managed using the ConstraintManager associated with a GRStateManager.
// As constraints gradually accrue on symbolic values, added constraints
// may conflict and indicate that a state is infeasible (as no real values
// could satisfy all the constraints). This is the principal mechanism
// for modeling path-sensitivity in ExprEngine/GRState.
//
// Various "assume" methods form the interface for adding constraints to
// symbolic values. A call to 'assume' indicates an assumption being placed
// on one or symbolic values. 'assume' methods take the following inputs:
//
// (1) A GRState object representing the current state.
//
// (2) The assumed constraint (which is specific to a given "assume" method).
//
// (3) A binary value "Assumption" that indicates whether the constraint is
// assumed to be true or false.
//
// The output of "assume*" is a new GRState object with the added constraints.
// If no new state is feasible, NULL is returned.
//
const GRState *assume(DefinedOrUnknownSVal cond, bool assumption) const;
/// This method assumes both "true" and "false" for 'cond', and
/// returns both corresponding states. It's shorthand for doing
/// 'assume' twice.
std::pair<const GRState*, const GRState*>
assume(DefinedOrUnknownSVal cond) const;
const GRState *assumeInBound(DefinedOrUnknownSVal idx,
DefinedOrUnknownSVal upperBound,
bool assumption) const;
//==---------------------------------------------------------------------==//
// Utility methods for getting regions.
//==---------------------------------------------------------------------==//
const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const;
//==---------------------------------------------------------------------==//
// Binding and retrieving values to/from the environment and symbolic store.
//==---------------------------------------------------------------------==//
/// BindCompoundLiteral - Return the state that has the bindings currently
/// in this state plus the bindings for the CompoundLiteral.
const GRState *bindCompoundLiteral(const CompoundLiteralExpr* CL,
const LocationContext *LC,
SVal V) const;
/// Create a new state by binding the value 'V' to the statement 'S' in the
/// state's environment.
const GRState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const;
/// Create a new state by binding the value 'V' and location 'locaton' to the
/// statement 'S' in the state's environment.
const GRState *bindExprAndLocation(const Stmt *S, SVal location, SVal V)
const;
const GRState *bindDecl(const VarRegion *VR, SVal V) const;
const GRState *bindDeclWithNoInit(const VarRegion *VR) const;
const GRState *bindLoc(Loc location, SVal V) const;
const GRState *bindLoc(SVal location, SVal V) const;
const GRState *bindDefault(SVal loc, SVal V) const;
const GRState *unbindLoc(Loc LV) const;
/// InvalidateRegion - Returns the state with bindings for the given region
/// cleared from the store. See InvalidateRegions.
const GRState *InvalidateRegion(const MemRegion *R,
const Expr *E, unsigned BlockCount,
StoreManager::InvalidatedSymbols *IS = NULL)
const {
return InvalidateRegions(&R, &R+1, E, BlockCount, IS, false);
}
/// InvalidateRegions - Returns the state with bindings for the given regions
/// cleared from the store. The regions are provided as a continuous array
/// from Begin to End. Optionally invalidates global regions as well.
const GRState *InvalidateRegions(const MemRegion * const *Begin,
const MemRegion * const *End,
const Expr *E, unsigned BlockCount,
StoreManager::InvalidatedSymbols *IS,
bool invalidateGlobals) const;
/// EnterStackFrame - Returns the state for entry to the given stack frame,
/// preserving the current state.
const GRState *EnterStackFrame(const StackFrameContext *frame) const;
/// Get the lvalue for a variable reference.
Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
/// Get the lvalue for a StringLiteral.
Loc getLValue(const StringLiteral *literal) const;
Loc getLValue(const CompoundLiteralExpr *literal,
const LocationContext *LC) const;
/// Get the lvalue for an ivar reference.
SVal getLValue(const ObjCIvarDecl *decl, SVal base) const;
/// Get the lvalue for a field reference.
SVal getLValue(const FieldDecl *decl, SVal Base) const;
/// Get the lvalue for an array index.
SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const;
const llvm::APSInt *getSymVal(SymbolRef sym) const;
/// Returns the SVal bound to the statement 'S' in the state's environment.
SVal getSVal(const Stmt* S) const;
SVal getSValAsScalarOrLoc(const Stmt *Ex) const;
SVal getSVal(Loc LV, QualType T = QualType()) const;
/// Returns the "raw" SVal bound to LV before any value simplfication.
SVal getRawSVal(Loc LV, QualType T= QualType()) const;
SVal getSVal(const MemRegion* R) const;
SVal getSValAsScalarOrLoc(const MemRegion *R) const;
const llvm::APSInt *getSymVal(SymbolRef sym);
bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const;
bool scanReachableSymbols(const SVal *I, const SVal *E,
SymbolVisitor &visitor) const;
bool scanReachableSymbols(const MemRegion * const *I,
const MemRegion * const *E,
SymbolVisitor &visitor) const;
template <typename CB> CB scanReachableSymbols(SVal val) const;
template <typename CB> CB scanReachableSymbols(const SVal *beg,
const SVal *end) const;
template <typename CB> CB
scanReachableSymbols(const MemRegion * const *beg,
const MemRegion * const *end) const;
//==---------------------------------------------------------------------==//
// Accessing the Generic Data Map (GDM).
//==---------------------------------------------------------------------==//
void* const* FindGDM(void* K) const;
template<typename T>
const GRState *add(typename GRStateTrait<T>::key_type K) const;
template <typename T>
typename GRStateTrait<T>::data_type
get() const {
return GRStateTrait<T>::MakeData(FindGDM(GRStateTrait<T>::GDMIndex()));
}
template<typename T>
typename GRStateTrait<T>::lookup_type
get(typename GRStateTrait<T>::key_type key) const {
void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
return GRStateTrait<T>::Lookup(GRStateTrait<T>::MakeData(d), key);
}
template <typename T>
typename GRStateTrait<T>::context_type get_context() const;
template<typename T>
const GRState *remove(typename GRStateTrait<T>::key_type K) const;
template<typename T>
const GRState *remove(typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::context_type C) const;
template <typename T>
const GRState *remove() const;
template<typename T>
const GRState *set(typename GRStateTrait<T>::data_type D) const;
template<typename T>
const GRState *set(typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::value_type E) const;
template<typename T>
const GRState *set(typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::value_type E,
typename GRStateTrait<T>::context_type C) const;
template<typename T>
bool contains(typename GRStateTrait<T>::key_type key) const {
void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
return GRStateTrait<T>::Contains(GRStateTrait<T>::MakeData(d), key);
}
// State pretty-printing.
class Printer {
public:
virtual ~Printer() {}
virtual void Print(llvm::raw_ostream& Out, const GRState* state,
const char* nl, const char* sep) = 0;
};
// Pretty-printing.
void print(llvm::raw_ostream& Out, CFG &C, const char *nl = "\n",
const char *sep = "") const;
void printStdErr(CFG &C) const;
void printDOT(llvm::raw_ostream& Out, CFG &C) const;
};
class GRStateSet {
typedef llvm::SmallPtrSet<const GRState*,5> ImplTy;
ImplTy Impl;
public:
GRStateSet() {}
inline void Add(const GRState* St) {
Impl.insert(St);
}
typedef ImplTy::const_iterator iterator;
inline unsigned size() const { return Impl.size(); }
inline bool empty() const { return Impl.empty(); }
inline iterator begin() const { return Impl.begin(); }
inline iterator end() const { return Impl.end(); }
class AutoPopulate {
GRStateSet& S;
unsigned StartSize;
const GRState* St;
public:
AutoPopulate(GRStateSet& s, const GRState* st)
: S(s), StartSize(S.size()), St(st) {}
~AutoPopulate() {
if (StartSize == S.size())
S.Add(St);
}
};
};
//===----------------------------------------------------------------------===//
// GRStateManager - Factory object for GRStates.
//===----------------------------------------------------------------------===//
class GRStateManager {
friend class GRState;
friend class ExprEngine; // FIXME: Remove.
private:
/// Eng - The SubEngine that owns this state manager.
SubEngine &Eng;
EnvironmentManager EnvMgr;
llvm::OwningPtr<StoreManager> StoreMgr;
llvm::OwningPtr<ConstraintManager> ConstraintMgr;
GRState::GenericDataMap::Factory GDMFactory;
typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy;
GDMContextsTy GDMContexts;
/// Printers - A set of printer objects used for pretty-printing a GRState.
/// GRStateManager owns these objects.
std::vector<GRState::Printer*> Printers;
/// StateSet - FoldingSet containing all the states created for analyzing
/// a particular function. This is used to unique states.
llvm::FoldingSet<GRState> StateSet;
/// Object that manages the data for all created SVals.
llvm::OwningPtr<SValBuilder> svalBuilder;
/// Alloc - A BumpPtrAllocator to allocate states.
llvm::BumpPtrAllocator &Alloc;
public:
GRStateManager(ASTContext& Ctx,
StoreManagerCreator CreateStoreManager,
ConstraintManagerCreator CreateConstraintManager,
llvm::BumpPtrAllocator& alloc,
SubEngine &subeng)
: Eng(subeng),
EnvMgr(alloc),
GDMFactory(alloc),
svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),
Alloc(alloc) {
StoreMgr.reset((*CreateStoreManager)(*this));
ConstraintMgr.reset((*CreateConstraintManager)(*this, subeng));
}
~GRStateManager();
const GRState *getInitialState(const LocationContext *InitLoc);
ASTContext &getContext() { return svalBuilder->getContext(); }
const ASTContext &getContext() const { return svalBuilder->getContext(); }
BasicValueFactory &getBasicVals() {
return svalBuilder->getBasicValueFactory();
}
const BasicValueFactory& getBasicVals() const {
return svalBuilder->getBasicValueFactory();
}
SValBuilder &getSValBuilder() {
return *svalBuilder;
}
SymbolManager &getSymbolManager() {
return svalBuilder->getSymbolManager();
}
const SymbolManager &getSymbolManager() const {
return svalBuilder->getSymbolManager();
}
llvm::BumpPtrAllocator& getAllocator() { return Alloc; }
MemRegionManager& getRegionManager() {
return svalBuilder->getRegionManager();
}
const MemRegionManager& getRegionManager() const {
return svalBuilder->getRegionManager();
}
StoreManager& getStoreManager() { return *StoreMgr; }
ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
SubEngine& getOwningEngine() { return Eng; }
const GRState* RemoveDeadBindings(const GRState* St,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper);
/// Marshal a new state for the callee in another translation unit.
/// 'state' is owned by the caller's engine.
const GRState *MarshalState(const GRState *state, const StackFrameContext *L);
public:
SVal ArrayToPointer(Loc Array) {
return StoreMgr->ArrayToPointer(Array);
}
// Methods that manipulate the GDM.
const GRState* addGDM(const GRState* St, void* Key, void* Data);
const GRState *removeGDM(const GRState *state, void *Key);
// Methods that query & manipulate the Store.
void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) {
StoreMgr->iterBindings(state->getStore(), F);
}
const GRState* getPersistentState(GRState& Impl);
//==---------------------------------------------------------------------==//
// Generic Data Map methods.
//==---------------------------------------------------------------------==//
//
// GRStateManager and GRState support a "generic data map" that allows
// different clients of GRState objects to embed arbitrary data within a
// GRState object. The generic data map is essentially an immutable map
// from a "tag" (that acts as the "key" for a client) and opaque values.
// Tags/keys and values are simply void* values. The typical way that clients
// generate unique tags are by taking the address of a static variable.
// Clients are responsible for ensuring that data values referred to by a
// the data pointer are immutable (and thus are essentially purely functional
// data).
//
// The templated methods below use the GRStateTrait<T> class
// to resolve keys into the GDM and to return data values to clients.
//
// Trait based GDM dispatch.
template <typename T>
const GRState* set(const GRState* st, typename GRStateTrait<T>::data_type D) {
return addGDM(st, GRStateTrait<T>::GDMIndex(),
GRStateTrait<T>::MakeVoidPtr(D));
}
template<typename T>
const GRState* set(const GRState* st,
typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::value_type V,
typename GRStateTrait<T>::context_type C) {
return addGDM(st, GRStateTrait<T>::GDMIndex(),
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Set(st->get<T>(), K, V, C)));
}
template <typename T>
const GRState* add(const GRState* st,
typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::context_type C) {
return addGDM(st, GRStateTrait<T>::GDMIndex(),
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Add(st->get<T>(), K, C)));
}
template <typename T>
const GRState* remove(const GRState* st,
typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::context_type C) {
return addGDM(st, GRStateTrait<T>::GDMIndex(),
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Remove(st->get<T>(), K, C)));
}
template <typename T>
const GRState *remove(const GRState *st) {
return removeGDM(st, GRStateTrait<T>::GDMIndex());
}
void* FindGDMContext(void* index,
void* (*CreateContext)(llvm::BumpPtrAllocator&),
void (*DeleteContext)(void*));
template <typename T>
typename GRStateTrait<T>::context_type get_context() {
void* p = FindGDMContext(GRStateTrait<T>::GDMIndex(),
GRStateTrait<T>::CreateContext,
GRStateTrait<T>::DeleteContext);
return GRStateTrait<T>::MakeContext(p);
}
const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) {
return ConstraintMgr->getSymVal(St, sym);
}
void EndPath(const GRState* St) {
ConstraintMgr->EndPath(St);
}
};
//===----------------------------------------------------------------------===//
// Out-of-line method definitions for GRState.
//===----------------------------------------------------------------------===//
inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) {
return getStateManager().getSymVal(this, sym);
}
inline const VarRegion* GRState::getRegion(const VarDecl *D,
const LocationContext *LC) const {
return getStateManager().getRegionManager().getVarRegion(D, LC);
}
inline const GRState *GRState::assume(DefinedOrUnknownSVal Cond,
bool Assumption) const {
if (Cond.isUnknown())
return this;
return getStateManager().ConstraintMgr->assume(this, cast<DefinedSVal>(Cond),
Assumption);
}
inline std::pair<const GRState*, const GRState*>
GRState::assume(DefinedOrUnknownSVal Cond) const {
if (Cond.isUnknown())
return std::make_pair(this, this);
return getStateManager().ConstraintMgr->assumeDual(this,
cast<DefinedSVal>(Cond));
}
inline const GRState *GRState::bindLoc(SVal LV, SVal V) const {
return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V);
}
inline Loc GRState::getLValue(const VarDecl* VD,
const LocationContext *LC) const {
return getStateManager().StoreMgr->getLValueVar(VD, LC);
}
inline Loc GRState::getLValue(const StringLiteral *literal) const {
return getStateManager().StoreMgr->getLValueString(literal);
}
inline Loc GRState::getLValue(const CompoundLiteralExpr *literal,
const LocationContext *LC) const {
return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC);
}
inline SVal GRState::getLValue(const ObjCIvarDecl *D, SVal Base) const {
return getStateManager().StoreMgr->getLValueIvar(D, Base);
}
inline SVal GRState::getLValue(const FieldDecl* D, SVal Base) const {
return getStateManager().StoreMgr->getLValueField(D, Base);
}
inline SVal GRState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{
if (NonLoc *N = dyn_cast<NonLoc>(&Idx))
return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base);
return UnknownVal();
}
inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const {
return getStateManager().getSymVal(this, sym);
}
inline SVal GRState::getSVal(const Stmt* Ex) const {
return Env.getSVal(Ex, *getStateManager().svalBuilder);
}
inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const {
if (const Expr *Ex = dyn_cast<Expr>(S)) {
QualType T = Ex->getType();
if (Loc::IsLocType(T) || T->isIntegerType())
return getSVal(S);
}
return UnknownVal();
}
inline SVal GRState::getRawSVal(Loc LV, QualType T) const {
return getStateManager().StoreMgr->Retrieve(St, LV, T);
}
inline SVal GRState::getSVal(const MemRegion* R) const {
return getStateManager().StoreMgr->Retrieve(St, loc::MemRegionVal(R));
}
inline BasicValueFactory &GRState::getBasicVals() const {
return getStateManager().getBasicVals();
}
inline SymbolManager &GRState::getSymbolManager() const {
return getStateManager().getSymbolManager();
}
template<typename T>
const GRState *GRState::add(typename GRStateTrait<T>::key_type K) const {
return getStateManager().add<T>(this, K, get_context<T>());
}
template <typename T>
typename GRStateTrait<T>::context_type GRState::get_context() const {
return getStateManager().get_context<T>();
}
template<typename T>
const GRState *GRState::remove(typename GRStateTrait<T>::key_type K) const {
return getStateManager().remove<T>(this, K, get_context<T>());
}
template<typename T>
const GRState *GRState::remove(typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::context_type C) const {
return getStateManager().remove<T>(this, K, C);
}
template <typename T>
const GRState *GRState::remove() const {
return getStateManager().remove<T>(this);
}
template<typename T>
const GRState *GRState::set(typename GRStateTrait<T>::data_type D) const {
return getStateManager().set<T>(this, D);
}
template<typename T>
const GRState *GRState::set(typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::value_type E) const {
return getStateManager().set<T>(this, K, E, get_context<T>());
}
template<typename T>
const GRState *GRState::set(typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::value_type E,
typename GRStateTrait<T>::context_type C) const {
return getStateManager().set<T>(this, K, E, C);
}
template <typename CB>
CB GRState::scanReachableSymbols(SVal val) const {
CB cb(this);
scanReachableSymbols(val, cb);
return cb;
}
template <typename CB>
CB GRState::scanReachableSymbols(const SVal *beg, const SVal *end) const {
CB cb(this);
scanReachableSymbols(beg, end, cb);
return cb;
}
template <typename CB>
CB GRState::scanReachableSymbols(const MemRegion * const *beg,
const MemRegion * const *end) const {
CB cb(this);
scanReachableSymbols(beg, end, cb);
return cb;
}
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,152 @@
//==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- C++ -*-//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines partial implementations of template specializations of
// the class GRStateTrait<>. GRStateTrait<> is used by GRState to implement
// set/get methods for mapulating a GRState's generic data map.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_GRSTATETRAIT_H
#define LLVM_CLANG_GR_GRSTATETRAIT_H
namespace llvm {
class BumpPtrAllocator;
template <typename K, typename D, typename I> class ImmutableMap;
template <typename K, typename I> class ImmutableSet;
template <typename T> class ImmutableList;
template <typename T> class ImmutableListImpl;
}
namespace clang {
namespace ento {
template <typename T> struct GRStatePartialTrait;
// Partial-specialization for ImmutableMap.
template <typename Key, typename Data, typename Info>
struct GRStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > {
typedef llvm::ImmutableMap<Key,Data,Info> data_type;
typedef typename data_type::Factory& context_type;
typedef Key key_type;
typedef Data value_type;
typedef const value_type* lookup_type;
static inline data_type MakeData(void* const* p) {
return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
}
static inline void* MakeVoidPtr(data_type B) {
return B.getRoot();
}
static lookup_type Lookup(data_type B, key_type K) {
return B.lookup(K);
}
static data_type Set(data_type B, key_type K, value_type E,context_type F){
return F.add(B, K, E);
}
static data_type Remove(data_type B, key_type K, context_type F) {
return F.remove(B, K);
}
static inline context_type MakeContext(void* p) {
return *((typename data_type::Factory*) p);
}
static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
return new typename data_type::Factory(Alloc);
}
static void DeleteContext(void* Ctx) {
delete (typename data_type::Factory*) Ctx;
}
};
// Partial-specialization for ImmutableSet.
template <typename Key, typename Info>
struct GRStatePartialTrait< llvm::ImmutableSet<Key,Info> > {
typedef llvm::ImmutableSet<Key,Info> data_type;
typedef typename data_type::Factory& context_type;
typedef Key key_type;
static inline data_type MakeData(void* const* p) {
return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
}
static inline void* MakeVoidPtr(data_type B) {
return B.getRoot();
}
static data_type Add(data_type B, key_type K, context_type F) {
return F.add(B, K);
}
static data_type Remove(data_type B, key_type K, context_type F) {
return F.remove(B, K);
}
static bool Contains(data_type B, key_type K) {
return B.contains(K);
}
static inline context_type MakeContext(void* p) {
return *((typename data_type::Factory*) p);
}
static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
return new typename data_type::Factory(Alloc);
}
static void DeleteContext(void* Ctx) {
delete (typename data_type::Factory*) Ctx;
}
};
// Partial-specialization for ImmutableList.
template <typename T>
struct GRStatePartialTrait< llvm::ImmutableList<T> > {
typedef llvm::ImmutableList<T> data_type;
typedef T key_type;
typedef typename data_type::Factory& context_type;
static data_type Add(data_type L, key_type K, context_type F) {
return F.add(K, L);
}
static inline data_type MakeData(void* const* p) {
return p ? data_type((const llvm::ImmutableListImpl<T>*) *p)
: data_type(0);
}
static inline void* MakeVoidPtr(data_type D) {
return (void*) D.getInternalPointer();
}
static inline context_type MakeContext(void* p) {
return *((typename data_type::Factory*) p);
}
static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
return new typename data_type::Factory(Alloc);
}
static void DeleteContext(void* Ctx) {
delete (typename data_type::Factory*) Ctx;
}
};
} // end GR namespace
} // end clang namespace
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,259 @@
// SValBuilder.h - Construction of SVals from evaluating expressions -*- C++ -*-
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines SValBuilder, a class that defines the interface for
// "symbolical evaluators" which construct an SVal from an expression.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_SVALBUILDER
#define LLVM_CLANG_GR_SVALBUILDER
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/PathSensitive/BasicValueFactory.h"
#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
namespace clang {
namespace ento {
class GRState;
class SValBuilder {
protected:
ASTContext &Context;
/// Manager of APSInt values.
BasicValueFactory BasicVals;
/// Manages the creation of symbols.
SymbolManager SymMgr;
/// Manages the creation of memory regions.
MemRegionManager MemMgr;
GRStateManager &StateMgr;
/// The scalar type to use for array indices.
const QualType ArrayIndexTy;
/// The width of the scalar type used for array indices.
const unsigned ArrayIndexWidth;
public:
// FIXME: Make these protected again one RegionStoreManager correctly
// handles loads from differening bound value types.
virtual SVal evalCastNL(NonLoc val, QualType castTy) = 0;
virtual SVal evalCastL(Loc val, QualType castTy) = 0;
public:
SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
GRStateManager &stateMgr)
: Context(context), BasicVals(context, alloc),
SymMgr(context, BasicVals, alloc),
MemMgr(context, alloc),
StateMgr(stateMgr),
ArrayIndexTy(context.IntTy),
ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {}
virtual ~SValBuilder() {}
SVal evalCast(SVal V, QualType castTy, QualType originalType);
virtual SVal evalMinus(NonLoc val) = 0;
virtual SVal evalComplement(NonLoc val) = 0;
virtual SVal evalBinOpNN(const GRState *state, BinaryOperator::Opcode Op,
NonLoc lhs, NonLoc rhs, QualType resultTy) = 0;
virtual SVal evalBinOpLL(const GRState *state, BinaryOperator::Opcode Op,
Loc lhs, Loc rhs, QualType resultTy) = 0;
virtual SVal evalBinOpLN(const GRState *state, BinaryOperator::Opcode Op,
Loc lhs, NonLoc rhs, QualType resultTy) = 0;
/// getKnownValue - evaluates a given SVal. If the SVal has only one possible
/// (integer) value, that value is returned. Otherwise, returns NULL.
virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal V) = 0;
SVal evalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
SVal L, SVal R, QualType T);
DefinedOrUnknownSVal evalEQ(const GRState *ST, DefinedOrUnknownSVal L,
DefinedOrUnknownSVal R);
ASTContext &getContext() { return Context; }
const ASTContext &getContext() const { return Context; }
GRStateManager &getStateManager() { return StateMgr; }
QualType getConditionType() const {
return getContext().IntTy;
}
QualType getArrayIndexType() const {
return ArrayIndexTy;
}
BasicValueFactory &getBasicValueFactory() { return BasicVals; }
const BasicValueFactory &getBasicValueFactory() const { return BasicVals; }
SymbolManager &getSymbolManager() { return SymMgr; }
const SymbolManager &getSymbolManager() const { return SymMgr; }
MemRegionManager &getRegionManager() { return MemMgr; }
const MemRegionManager &getRegionManager() const { return MemMgr; }
// Forwarding methods to SymbolManager.
const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T,
unsigned VisitCount,
const void* SymbolTag = 0) {
return SymMgr.getConjuredSymbol(E, T, VisitCount, SymbolTag);
}
const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount,
const void* SymbolTag = 0) {
return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag);
}
/// makeZeroVal - Construct an SVal representing '0' for the specified type.
DefinedOrUnknownSVal makeZeroVal(QualType T);
/// getRegionValueSymbolVal - make a unique symbol for value of R.
DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedRegion *R);
DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag,
const Expr *E, unsigned Count);
DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag,
const Expr *E, QualType T,
unsigned Count);
DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
const TypedRegion *R);
DefinedSVal getMetadataSymbolVal(const void *SymbolTag, const MemRegion *MR,
const Expr *E, QualType T, unsigned Count);
DefinedSVal getFunctionPointer(const FunctionDecl *FD);
DefinedSVal getBlockPointer(const BlockDecl *BD, CanQualType locTy,
const LocationContext *LC);
NonLoc makeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals) {
return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals));
}
NonLoc makeLazyCompoundVal(const void *store, const TypedRegion *R) {
return nonloc::LazyCompoundVal(BasicVals.getLazyCompoundValData(store, R));
}
NonLoc makeZeroArrayIndex() {
return nonloc::ConcreteInt(BasicVals.getValue(0, ArrayIndexTy));
}
NonLoc makeArrayIndex(uint64_t idx) {
return nonloc::ConcreteInt(BasicVals.getValue(idx, ArrayIndexTy));
}
SVal convertToArrayIndex(SVal V);
nonloc::ConcreteInt makeIntVal(const IntegerLiteral* I) {
return nonloc::ConcreteInt(BasicVals.getValue(I->getValue(),
I->getType()->isUnsignedIntegerType()));
}
nonloc::ConcreteInt makeIntVal(const CXXBoolLiteralExpr *E) {
return E->getValue() ? nonloc::ConcreteInt(BasicVals.getValue(1, 1, true))
: nonloc::ConcreteInt(BasicVals.getValue(0, 1, true));
}
nonloc::ConcreteInt makeIntVal(const llvm::APSInt& V) {
return nonloc::ConcreteInt(BasicVals.getValue(V));
}
loc::ConcreteInt makeIntLocVal(const llvm::APSInt &v) {
return loc::ConcreteInt(BasicVals.getValue(v));
}
NonLoc makeIntVal(const llvm::APInt& V, bool isUnsigned) {
return nonloc::ConcreteInt(BasicVals.getValue(V, isUnsigned));
}
DefinedSVal makeIntVal(uint64_t X, QualType T) {
if (Loc::IsLocType(T))
return loc::ConcreteInt(BasicVals.getValue(X, T));
return nonloc::ConcreteInt(BasicVals.getValue(X, T));
}
NonLoc makeIntVal(uint64_t X, bool isUnsigned) {
return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned));
}
NonLoc makeIntValWithPtrWidth(uint64_t X, bool isUnsigned) {
return nonloc::ConcreteInt(BasicVals.getIntWithPtrWidth(X, isUnsigned));
}
NonLoc makeIntVal(uint64_t X, unsigned BitWidth, bool isUnsigned) {
return nonloc::ConcreteInt(BasicVals.getValue(X, BitWidth, isUnsigned));
}
NonLoc makeLocAsInteger(Loc V, unsigned Bits) {
return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(V, Bits));
}
NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
const llvm::APSInt& rhs, QualType T);
NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
const SymExpr *rhs, QualType T);
NonLoc makeTruthVal(bool b, QualType T) {
return nonloc::ConcreteInt(BasicVals.getTruthValue(b, T));
}
NonLoc makeTruthVal(bool b) {
return nonloc::ConcreteInt(BasicVals.getTruthValue(b));
}
Loc makeNull() {
return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth());
}
Loc makeLoc(SymbolRef Sym) {
return loc::MemRegionVal(MemMgr.getSymbolicRegion(Sym));
}
Loc makeLoc(const MemRegion* R) {
return loc::MemRegionVal(R);
}
Loc makeLoc(const AddrLabelExpr* E) {
return loc::GotoLabel(E->getLabel());
}
Loc makeLoc(const llvm::APSInt& V) {
return loc::ConcreteInt(BasicVals.getValue(V));
}
};
SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
ASTContext &context,
GRStateManager &stateMgr);
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,522 @@
//== SVals.h - Abstract Values for Static Analysis ---------*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines SVal, Loc, and NonLoc, classes that represent
// abstract r-values for use with path-sensitive value tracking.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_RVALUE_H
#define LLVM_CLANG_GR_RVALUE_H
#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/ImmutableList.h"
namespace llvm {
class raw_ostream;
}
//==------------------------------------------------------------------------==//
// Base SVal types.
//==------------------------------------------------------------------------==//
namespace clang {
namespace ento {
class CompoundValData;
class LazyCompoundValData;
class GRState;
class BasicValueFactory;
class MemRegion;
class TypedRegion;
class MemRegionManager;
class GRStateManager;
class SValBuilder;
/// SVal - This represents a symbolic expression, which can be either
/// an L-value or an R-value.
///
class SVal {
public:
enum BaseKind {
// The enumerators must be representable using 2 bits.
UndefinedKind = 0, // for subclass UndefinedVal (an uninitialized value)
UnknownKind = 1, // for subclass UnknownVal (a void value)
LocKind = 2, // for subclass Loc (an L-value)
NonLocKind = 3 // for subclass NonLoc (an R-value that's not
// an L-value)
};
enum { BaseBits = 2, BaseMask = 0x3 };
protected:
const void* Data;
/// The lowest 2 bits are a BaseKind (0 -- 3).
/// The higher bits are an unsigned "kind" value.
unsigned Kind;
protected:
explicit SVal(const void* d, bool isLoc, unsigned ValKind)
: Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {}
explicit SVal(BaseKind k, const void* D = NULL)
: Data(D), Kind(k) {}
public:
explicit SVal() : Data(0), Kind(0) {}
~SVal() {}
/// BufferTy - A temporary buffer to hold a set of SVals.
typedef llvm::SmallVector<SVal,5> BufferTy;
inline unsigned getRawKind() const { return Kind; }
inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
inline void Profile(llvm::FoldingSetNodeID& ID) const {
ID.AddInteger((unsigned) getRawKind());
ID.AddPointer(Data);
}
inline bool operator==(const SVal& R) const {
return getRawKind() == R.getRawKind() && Data == R.Data;
}
inline bool operator!=(const SVal& R) const {
return !(*this == R);
}
inline bool isUnknown() const {
return getRawKind() == UnknownKind;
}
inline bool isUndef() const {
return getRawKind() == UndefinedKind;
}
inline bool isUnknownOrUndef() const {
return getRawKind() <= UnknownKind;
}
inline bool isValid() const {
return getRawKind() > UnknownKind;
}
bool isConstant() const;
bool isConstant(int I) const;
bool isZeroConstant() const;
/// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true;
bool hasConjuredSymbol() const;
/// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a
/// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl.
/// Otherwise return 0.
const FunctionDecl* getAsFunctionDecl() const;
/// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
/// wraps a symbol, return that SymbolRef. Otherwise return NULL.
SymbolRef getAsLocSymbol() const;
/// Get the symbol in the SVal or its base region.
SymbolRef getLocSymbolInBase() const;
/// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
/// Otherwise return a SymbolRef where 'isValid()' returns false.
SymbolRef getAsSymbol() const;
/// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
/// return that expression. Otherwise return NULL.
const SymExpr *getAsSymbolicExpression() const;
const MemRegion *getAsRegion() const;
void dumpToStream(llvm::raw_ostream& OS) const;
void dump() const;
// Iterators.
class symbol_iterator {
llvm::SmallVector<const SymExpr*, 5> itr;
void expand();
public:
symbol_iterator() {}
symbol_iterator(const SymExpr* SE);
symbol_iterator& operator++();
SymbolRef operator*();
bool operator==(const symbol_iterator& X) const;
bool operator!=(const symbol_iterator& X) const;
};
symbol_iterator symbol_begin() const {
const SymExpr *SE = getAsSymbolicExpression();
if (SE)
return symbol_iterator(SE);
else
return symbol_iterator();
}
symbol_iterator symbol_end() const { return symbol_iterator(); }
// Implement isa<T> support.
static inline bool classof(const SVal*) { return true; }
};
class UndefinedVal : public SVal {
public:
UndefinedVal() : SVal(UndefinedKind) {}
UndefinedVal(const void* D) : SVal(UndefinedKind, D) {}
static inline bool classof(const SVal* V) {
return V->getBaseKind() == UndefinedKind;
}
const void* getData() const { return Data; }
};
class DefinedOrUnknownSVal : public SVal {
private:
// Do not implement. We want calling these methods to be a compiler
// error since they are tautologically false.
bool isUndef() const;
bool isValid() const;
protected:
explicit DefinedOrUnknownSVal(const void* d, bool isLoc, unsigned ValKind)
: SVal(d, isLoc, ValKind) {}
explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL)
: SVal(k, D) {}
public:
// Implement isa<T> support.
static inline bool classof(const SVal *V) {
return !V->isUndef();
}
};
class UnknownVal : public DefinedOrUnknownSVal {
public:
explicit UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {}
static inline bool classof(const SVal *V) {
return V->getBaseKind() == UnknownKind;
}
};
class DefinedSVal : public DefinedOrUnknownSVal {
private:
// Do not implement. We want calling these methods to be a compiler
// error since they are tautologically true/false.
bool isUnknown() const;
bool isUnknownOrUndef() const;
bool isValid() const;
protected:
explicit DefinedSVal(const void* d, bool isLoc, unsigned ValKind)
: DefinedOrUnknownSVal(d, isLoc, ValKind) {}
public:
// Implement isa<T> support.
static inline bool classof(const SVal *V) {
return !V->isUnknownOrUndef();
}
};
class NonLoc : public DefinedSVal {
protected:
explicit NonLoc(unsigned SubKind, const void* d)
: DefinedSVal(d, false, SubKind) {}
public:
void dumpToStream(llvm::raw_ostream& Out) const;
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind;
}
};
class Loc : public DefinedSVal {
protected:
explicit Loc(unsigned SubKind, const void* D)
: DefinedSVal(const_cast<void*>(D), true, SubKind) {}
public:
void dumpToStream(llvm::raw_ostream& Out) const;
Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {}
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == LocKind;
}
static inline bool IsLocType(QualType T) {
return T->isAnyPointerType() || T->isBlockPointerType() ||
T->isReferenceType();
}
};
//==------------------------------------------------------------------------==//
// Subclasses of NonLoc.
//==------------------------------------------------------------------------==//
namespace nonloc {
enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind,
LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };
class SymbolVal : public NonLoc {
public:
SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {}
SymbolRef getSymbol() const {
return (const SymbolData*) Data;
}
static inline bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind &&
V->getSubKind() == SymbolValKind;
}
static inline bool classof(const NonLoc* V) {
return V->getSubKind() == SymbolValKind;
}
};
class SymExprVal : public NonLoc {
public:
explicit SymExprVal(const SymExpr *SE)
: NonLoc(SymExprValKind, reinterpret_cast<const void*>(SE)) {}
const SymExpr *getSymbolicExpression() const {
return reinterpret_cast<const SymExpr*>(Data);
}
static inline bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind &&
V->getSubKind() == SymExprValKind;
}
static inline bool classof(const NonLoc* V) {
return V->getSubKind() == SymExprValKind;
}
};
class ConcreteInt : public NonLoc {
public:
explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
const llvm::APSInt& getValue() const {
return *static_cast<const llvm::APSInt*>(Data);
}
// Transfer functions for binary/unary operations on ConcreteInts.
SVal evalBinOp(SValBuilder &svalBuilder, BinaryOperator::Opcode Op,
const ConcreteInt& R) const;
ConcreteInt evalComplement(SValBuilder &svalBuilder) const;
ConcreteInt evalMinus(SValBuilder &svalBuilder) const;
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind &&
V->getSubKind() == ConcreteIntKind;
}
static inline bool classof(const NonLoc* V) {
return V->getSubKind() == ConcreteIntKind;
}
};
class LocAsInteger : public NonLoc {
friend class ento::SValBuilder;
explicit LocAsInteger(const std::pair<SVal, uintptr_t>& data) :
NonLoc(LocAsIntegerKind, &data) {
assert (isa<Loc>(data.first));
}
public:
Loc getLoc() const {
return cast<Loc>(((std::pair<SVal, uintptr_t>*) Data)->first);
}
const Loc& getPersistentLoc() const {
const SVal& V = ((std::pair<SVal, uintptr_t>*) Data)->first;
return cast<Loc>(V);
}
unsigned getNumBits() const {
return ((std::pair<SVal, unsigned>*) Data)->second;
}
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind &&
V->getSubKind() == LocAsIntegerKind;
}
static inline bool classof(const NonLoc* V) {
return V->getSubKind() == LocAsIntegerKind;
}
};
class CompoundVal : public NonLoc {
friend class ento::SValBuilder;
explicit CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {}
public:
const CompoundValData* getValue() const {
return static_cast<const CompoundValData*>(Data);
}
typedef llvm::ImmutableList<SVal>::iterator iterator;
iterator begin() const;
iterator end() const;
static bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind;
}
static bool classof(const NonLoc* V) {
return V->getSubKind() == CompoundValKind;
}
};
class LazyCompoundVal : public NonLoc {
friend class ento::SValBuilder;
explicit LazyCompoundVal(const LazyCompoundValData *D)
: NonLoc(LazyCompoundValKind, D) {}
public:
const LazyCompoundValData *getCVData() const {
return static_cast<const LazyCompoundValData*>(Data);
}
const void *getStore() const;
const TypedRegion *getRegion() const;
static bool classof(const SVal *V) {
return V->getBaseKind() == NonLocKind &&
V->getSubKind() == LazyCompoundValKind;
}
static bool classof(const NonLoc *V) {
return V->getSubKind() == LazyCompoundValKind;
}
};
} // end namespace ento::nonloc
//==------------------------------------------------------------------------==//
// Subclasses of Loc.
//==------------------------------------------------------------------------==//
namespace loc {
enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind };
class GotoLabel : public Loc {
public:
explicit GotoLabel(LabelStmt* Label) : Loc(GotoLabelKind, Label) {}
const LabelStmt* getLabel() const {
return static_cast<const LabelStmt*>(Data);
}
static inline bool classof(const SVal* V) {
return V->getBaseKind() == LocKind &&
V->getSubKind() == GotoLabelKind;
}
static inline bool classof(const Loc* V) {
return V->getSubKind() == GotoLabelKind;
}
};
class MemRegionVal : public Loc {
public:
explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {}
const MemRegion* getRegion() const {
return static_cast<const MemRegion*>(Data);
}
const MemRegion* StripCasts() const;
template <typename REGION>
const REGION* getRegionAs() const {
return llvm::dyn_cast<REGION>(getRegion());
}
inline bool operator==(const MemRegionVal& R) const {
return getRegion() == R.getRegion();
}
inline bool operator!=(const MemRegionVal& R) const {
return getRegion() != R.getRegion();
}
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == LocKind &&
V->getSubKind() == MemRegionKind;
}
static inline bool classof(const Loc* V) {
return V->getSubKind() == MemRegionKind;
}
};
class ConcreteInt : public Loc {
public:
explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {}
const llvm::APSInt& getValue() const {
return *static_cast<const llvm::APSInt*>(Data);
}
// Transfer functions for binary/unary operations on ConcreteInts.
SVal evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
const ConcreteInt& R) const;
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == LocKind &&
V->getSubKind() == ConcreteIntKind;
}
static inline bool classof(const Loc* V) {
return V->getSubKind() == ConcreteIntKind;
}
};
} // end ento::loc namespace
} // end GR namespace
} // end clang namespace
namespace llvm {
static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os,
clang::ento::SVal V) {
V.dumpToStream(os);
return os;
}
} // end llvm namespace
#endif

View File

@ -0,0 +1,259 @@
//== Store.h - Interface for maps from Locations to Values ------*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defined the types Store and StoreManager.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_STORE_H
#define LLVM_CLANG_GR_STORE_H
#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Optional.h"
namespace clang {
class Stmt;
class Expr;
class ObjCIvarDecl;
class StackFrameContext;
namespace ento {
/// Store - This opaque type encapsulates an immutable mapping from
/// locations to values. At a high-level, it represents the symbolic
/// memory model. Different subclasses of StoreManager may choose
/// different types to represent the locations and values.
typedef const void* Store;
class GRState;
class GRStateManager;
class SubRegionMap;
class StoreManager {
protected:
SValBuilder &svalBuilder;
GRStateManager &StateMgr;
/// MRMgr - Manages region objects associated with this StoreManager.
MemRegionManager &MRMgr;
ASTContext &Ctx;
StoreManager(GRStateManager &stateMgr);
public:
virtual ~StoreManager() {}
/// Return the value bound to specified location in a given state.
/// \param[in] state The analysis state.
/// \param[in] loc The symbolic memory location.
/// \param[in] T An optional type that provides a hint indicating the
/// expected type of the returned value. This is used if the value is
/// lazily computed.
/// \return The value bound to the location \c loc.
virtual SVal Retrieve(Store store, Loc loc, QualType T = QualType()) = 0;
/// Return a state with the specified value bound to the given location.
/// \param[in] state The analysis state.
/// \param[in] loc The symbolic memory location.
/// \param[in] val The value to bind to location \c loc.
/// \return A pointer to a GRState object that contains the same bindings as
/// \c state with the addition of having the value specified by \c val bound
/// to the location given for \c loc.
virtual Store Bind(Store store, Loc loc, SVal val) = 0;
virtual Store BindDefault(Store store, const MemRegion *R, SVal V) {
return store;
}
virtual Store Remove(Store St, Loc L) = 0;
/// BindCompoundLiteral - Return the store that has the bindings currently
/// in 'store' plus the bindings for the CompoundLiteral. 'R' is the region
/// for the compound literal and 'BegInit' and 'EndInit' represent an
/// array of initializer values.
virtual Store BindCompoundLiteral(Store store,
const CompoundLiteralExpr* cl,
const LocationContext *LC, SVal v) = 0;
/// getInitialStore - Returns the initial "empty" store representing the
/// value bindings upon entry to an analyzed function.
virtual Store getInitialStore(const LocationContext *InitLoc) = 0;
/// getRegionManager - Returns the internal RegionManager object that is
/// used to query and manipulate MemRegion objects.
MemRegionManager& getRegionManager() { return MRMgr; }
/// getSubRegionMap - Returns an opaque map object that clients can query
/// to get the subregions of a given MemRegion object. It is the
// caller's responsibility to 'delete' the returned map.
virtual SubRegionMap *getSubRegionMap(Store store) = 0;
virtual Loc getLValueVar(const VarDecl *VD, const LocationContext *LC) {
return svalBuilder.makeLoc(MRMgr.getVarRegion(VD, LC));
}
virtual Loc getLValueString(const StringLiteral* S) {
return svalBuilder.makeLoc(MRMgr.getStringRegion(S));
}
Loc getLValueCompoundLiteral(const CompoundLiteralExpr* CL,
const LocationContext *LC) {
return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
}
virtual SVal getLValueIvar(const ObjCIvarDecl* decl, SVal base) {
return getLValueFieldOrIvar(decl, base);
}
virtual SVal getLValueField(const FieldDecl* D, SVal Base) {
return getLValueFieldOrIvar(D, Base);
}
virtual SVal getLValueElement(QualType elementType, NonLoc offset, SVal Base);
// FIXME: This should soon be eliminated altogether; clients should deal with
// region extents directly.
virtual DefinedOrUnknownSVal getSizeInElements(const GRState *state,
const MemRegion *region,
QualType EleTy) {
return UnknownVal();
}
/// ArrayToPointer - Used by ExprEngine::VistCast to handle implicit
/// conversions between arrays and pointers.
virtual SVal ArrayToPointer(Loc Array) = 0;
/// Evaluates DerivedToBase casts.
virtual SVal evalDerivedToBase(SVal derived, QualType basePtrType) {
return UnknownVal();
}
class CastResult {
const GRState *state;
const MemRegion *region;
public:
const GRState *getState() const { return state; }
const MemRegion* getRegion() const { return region; }
CastResult(const GRState *s, const MemRegion* r = 0) : state(s), region(r){}
};
const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
/// CastRegion - Used by ExprEngine::VisitCast to handle casts from
/// a MemRegion* to a specific location type. 'R' is the region being
/// casted and 'CastToTy' the result type of the cast.
const MemRegion *CastRegion(const MemRegion *region, QualType CastToTy);
/// evalBinOp - Perform pointer arithmetic.
virtual SVal evalBinOp(BinaryOperator::Opcode Op,
Loc lhs, NonLoc rhs, QualType resultTy) {
return UnknownVal();
}
virtual Store RemoveDeadBindings(Store store, const StackFrameContext *LCtx,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0;
virtual Store BindDecl(Store store, const VarRegion *VR, SVal initVal) = 0;
virtual Store BindDeclWithNoInit(Store store, const VarRegion *VR) = 0;
typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
typedef llvm::SmallVector<const MemRegion *, 8> InvalidatedRegions;
/// InvalidateRegions - Clears out the specified regions from the store,
/// marking their values as unknown. Depending on the store, this may also
/// invalidate additional regions that may have changed based on accessing
/// the given regions. Optionally, invalidates non-static globals as well.
/// \param[in] store The initial store
/// \param[in] Begin A pointer to the first region to invalidate.
/// \param[in] End A pointer just past the last region to invalidate.
/// \param[in] E The current statement being evaluated. Used to conjure
/// symbols to mark the values of invalidated regions.
/// \param[in] Count The current block count. Used to conjure
/// symbols to mark the values of invalidated regions.
/// \param[in,out] IS A set to fill with any symbols that are no longer
/// accessible. Pass \c NULL if this information will not be used.
/// \param[in] invalidateGlobals If \c true, any non-static global regions
/// are invalidated as well.
/// \param[in,out] Regions A vector to fill with any regions being
/// invalidated. This should include any regions explicitly invalidated
/// even if they do not currently have bindings. Pass \c NULL if this
/// information will not be used.
virtual Store InvalidateRegions(Store store,
const MemRegion * const *Begin,
const MemRegion * const *End,
const Expr *E, unsigned Count,
InvalidatedSymbols *IS,
bool invalidateGlobals,
InvalidatedRegions *Regions) = 0;
/// EnterStackFrame - Let the StoreManager to do something when execution
/// engine is about to execute into a callee.
virtual Store EnterStackFrame(const GRState *state,
const StackFrameContext *frame);
virtual void print(Store store, llvm::raw_ostream& Out,
const char* nl, const char *sep) = 0;
class BindingsHandler {
public:
virtual ~BindingsHandler();
virtual bool HandleBinding(StoreManager& SMgr, Store store,
const MemRegion *region, SVal val) = 0;
};
/// iterBindings - Iterate over the bindings in the Store.
virtual void iterBindings(Store store, BindingsHandler& f) = 0;
protected:
const MemRegion *MakeElementRegion(const MemRegion *baseRegion,
QualType pointeeTy, uint64_t index = 0);
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
/// as another region.
SVal CastRetrievedVal(SVal val, const TypedRegion *region, QualType castTy,
bool performTestOnly = true);
private:
SVal getLValueFieldOrIvar(const Decl* decl, SVal base);
};
// FIXME: Do we still need this?
/// SubRegionMap - An abstract interface that represents a queryable map
/// between MemRegion objects and their subregions.
class SubRegionMap {
public:
virtual ~SubRegionMap() {}
class Visitor {
public:
virtual ~Visitor() {}
virtual bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) = 0;
};
virtual bool iterSubRegions(const MemRegion *region, Visitor& V) const = 0;
};
// FIXME: Do we need to pass GRStateManager anymore?
StoreManager *CreateBasicStoreManager(GRStateManager& StMgr);
StoreManager *CreateRegionStoreManager(GRStateManager& StMgr);
StoreManager *CreateFieldsOnlyRegionStoreManager(GRStateManager& StMgr);
StoreManager *CreateFlatStoreManager(GRStateManager &StMgr);
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,113 @@
//== SubEngine.h - Interface of the subengine of CoreEngine --------*- C++ -*-//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interface of a subengine of the CoreEngine.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_SUBENGINE_H
#define LLVM_CLANG_GR_SUBENGINE_H
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
namespace clang {
class CFGBlock;
class CFGElement;
class LocationContext;
class Stmt;
namespace ento {
class AnalysisManager;
class ExplodedNode;
class GRState;
class GRStateManager;
class BlockCounter;
class StmtNodeBuilder;
class BranchNodeBuilder;
class IndirectGotoNodeBuilder;
class SwitchNodeBuilder;
class EndPathNodeBuilder;
class CallEnterNodeBuilder;
class CallExitNodeBuilder;
class MemRegion;
class SubEngine {
public:
virtual ~SubEngine() {}
virtual const GRState* getInitialState(const LocationContext *InitLoc) = 0;
virtual AnalysisManager &getAnalysisManager() = 0;
virtual GRStateManager &getStateManager() = 0;
/// Called by CoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a block-level statement.
virtual void ProcessElement(const CFGElement E, StmtNodeBuilder& builder)=0;
/// Called by CoreEngine when start processing
/// a CFGBlock. This method returns true if the analysis should continue
/// exploring the given path, and false otherwise.
virtual bool ProcessBlockEntrance(const CFGBlock* B, const ExplodedNode *Pred,
BlockCounter BC) = 0;
/// Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
virtual void ProcessBranch(const Stmt* Condition, const Stmt* Term,
BranchNodeBuilder& builder) = 0;
/// Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
virtual void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder) = 0;
/// Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a switch statement.
virtual void ProcessSwitch(SwitchNodeBuilder& builder) = 0;
/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
virtual void ProcessEndPath(EndPathNodeBuilder& builder) = 0;
// Generate the entry node of the callee.
virtual void ProcessCallEnter(CallEnterNodeBuilder &builder) = 0;
// Generate the first post callsite node.
virtual void ProcessCallExit(CallExitNodeBuilder &builder) = 0;
/// Called by ConstraintManager. Used to call checker-specific
/// logic for handling assumptions on symbolic values.
virtual const GRState* ProcessAssume(const GRState *state,
SVal cond, bool assumption) = 0;
/// WantsRegionChangeUpdate - Called by GRStateManager to determine if a
/// region change should trigger a ProcessRegionChanges update.
virtual bool WantsRegionChangeUpdate(const GRState* state) = 0;
/// ProcessRegionChanges - Called by GRStateManager whenever a change is made
/// to the store. Used to update checkers that track region values.
virtual const GRState* ProcessRegionChanges(const GRState* state,
const MemRegion* const *Begin,
const MemRegion* const *End) = 0;
inline const GRState* ProcessRegionChange(const GRState* state,
const MemRegion* MR) {
return ProcessRegionChanges(state, &MR, &MR+1);
}
/// Called by CoreEngine when the analysis worklist is either empty or the
// maximum number of analysis steps have been reached.
virtual void ProcessEndWorklist(bool hasWorkRemaining) = 0;
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,61 @@
//== SummaryManager.h - Generic handling of function summaries --*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines SummaryManager and related classes, which provides
// a generic mechanism for managing function summaries.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_SUMMARY
#define LLVM_CLANG_GR_SUMMARY
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/Allocator.h"
namespace clang {
namespace ento {
namespace summMgr {
/* Key kinds:
- C functions
- C++ functions (name + parameter types)
- ObjC methods:
- Class, selector (class method)
- Class, selector (instance method)
- Category, selector (instance method)
- Protocol, selector (instance method)
- C++ methods
- Class, function name + parameter types + const
*/
class SummaryKey {
};
} // end namespace clang::summMgr
class SummaryManagerImpl {
};
template <typename T>
class SummaryManager : SummaryManagerImpl {
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,489 @@
//== SymbolManager.h - Management of Symbolic Values ------------*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines SymbolManager, a class that manages symbolic values
// created for use by ExprEngine and related classes.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_SYMMGR_H
#define LLVM_CLANG_GR_SYMMGR_H
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/Analysis/AnalysisContext.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/DenseSet.h"
namespace llvm {
class BumpPtrAllocator;
class raw_ostream;
}
namespace clang {
class ASTContext;
class StackFrameContext;
namespace ento {
class BasicValueFactory;
class MemRegion;
class SubRegion;
class TypedRegion;
class VarRegion;
class SymExpr : public llvm::FoldingSetNode {
public:
enum Kind { BEGIN_SYMBOLS,
RegionValueKind, ConjuredKind, DerivedKind, ExtentKind,
MetadataKind,
END_SYMBOLS,
SymIntKind, SymSymKind };
private:
Kind K;
protected:
SymExpr(Kind k) : K(k) {}
public:
virtual ~SymExpr() {}
Kind getKind() const { return K; }
void dump() const;
virtual void dumpToStream(llvm::raw_ostream &os) const = 0;
virtual QualType getType(ASTContext&) const = 0;
virtual void Profile(llvm::FoldingSetNodeID& profile) = 0;
// Implement isa<T> support.
static inline bool classof(const SymExpr*) { return true; }
};
typedef unsigned SymbolID;
class SymbolData : public SymExpr {
private:
const SymbolID Sym;
protected:
SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {}
public:
virtual ~SymbolData() {}
SymbolID getSymbolID() const { return Sym; }
// Implement isa<T> support.
static inline bool classof(const SymExpr* SE) {
Kind k = SE->getKind();
return k > BEGIN_SYMBOLS && k < END_SYMBOLS;
}
};
typedef const SymbolData* SymbolRef;
// A symbol representing the value of a MemRegion.
class SymbolRegionValue : public SymbolData {
const TypedRegion *R;
public:
SymbolRegionValue(SymbolID sym, const TypedRegion *r)
: SymbolData(RegionValueKind, sym), R(r) {}
const TypedRegion* getRegion() const { return R; }
static void Profile(llvm::FoldingSetNodeID& profile, const TypedRegion* R) {
profile.AddInteger((unsigned) RegionValueKind);
profile.AddPointer(R);
}
virtual void Profile(llvm::FoldingSetNodeID& profile) {
Profile(profile, R);
}
void dumpToStream(llvm::raw_ostream &os) const;
QualType getType(ASTContext&) const;
// Implement isa<T> support.
static inline bool classof(const SymExpr* SE) {
return SE->getKind() == RegionValueKind;
}
};
// A symbol representing the result of an expression.
class SymbolConjured : public SymbolData {
const Stmt* S;
QualType T;
unsigned Count;
const void* SymbolTag;
public:
SymbolConjured(SymbolID sym, const Stmt* s, QualType t, unsigned count,
const void* symbolTag)
: SymbolData(ConjuredKind, sym), S(s), T(t), Count(count),
SymbolTag(symbolTag) {}
const Stmt* getStmt() const { return S; }
unsigned getCount() const { return Count; }
const void* getTag() const { return SymbolTag; }
QualType getType(ASTContext&) const;
void dumpToStream(llvm::raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& profile, const Stmt* S,
QualType T, unsigned Count, const void* SymbolTag) {
profile.AddInteger((unsigned) ConjuredKind);
profile.AddPointer(S);
profile.Add(T);
profile.AddInteger(Count);
profile.AddPointer(SymbolTag);
}
virtual void Profile(llvm::FoldingSetNodeID& profile) {
Profile(profile, S, T, Count, SymbolTag);
}
// Implement isa<T> support.
static inline bool classof(const SymExpr* SE) {
return SE->getKind() == ConjuredKind;
}
};
// A symbol representing the value of a MemRegion whose parent region has
// symbolic value.
class SymbolDerived : public SymbolData {
SymbolRef parentSymbol;
const TypedRegion *R;
public:
SymbolDerived(SymbolID sym, SymbolRef parent, const TypedRegion *r)
: SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {}
SymbolRef getParentSymbol() const { return parentSymbol; }
const TypedRegion *getRegion() const { return R; }
QualType getType(ASTContext&) const;
void dumpToStream(llvm::raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent,
const TypedRegion *r) {
profile.AddInteger((unsigned) DerivedKind);
profile.AddPointer(r);
profile.AddPointer(parent);
}
virtual void Profile(llvm::FoldingSetNodeID& profile) {
Profile(profile, parentSymbol, R);
}
// Implement isa<T> support.
static inline bool classof(const SymExpr* SE) {
return SE->getKind() == DerivedKind;
}
};
/// SymbolExtent - Represents the extent (size in bytes) of a bounded region.
/// Clients should not ask the SymbolManager for a region's extent. Always use
/// SubRegion::getExtent instead -- the value returned may not be a symbol.
class SymbolExtent : public SymbolData {
const SubRegion *R;
public:
SymbolExtent(SymbolID sym, const SubRegion *r)
: SymbolData(ExtentKind, sym), R(r) {}
const SubRegion *getRegion() const { return R; }
QualType getType(ASTContext&) const;
void dumpToStream(llvm::raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& profile, const SubRegion *R) {
profile.AddInteger((unsigned) ExtentKind);
profile.AddPointer(R);
}
virtual void Profile(llvm::FoldingSetNodeID& profile) {
Profile(profile, R);
}
// Implement isa<T> support.
static inline bool classof(const SymExpr* SE) {
return SE->getKind() == ExtentKind;
}
};
/// SymbolMetadata - Represents path-dependent metadata about a specific region.
/// Metadata symbols remain live as long as they are marked as in use before
/// dead-symbol sweeping AND their associated regions are still alive.
/// Intended for use by checkers.
class SymbolMetadata : public SymbolData {
const MemRegion* R;
const Stmt* S;
QualType T;
unsigned Count;
const void* Tag;
public:
SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt* s, QualType t,
unsigned count, const void* tag)
: SymbolData(MetadataKind, sym), R(r), S(s), T(t), Count(count), Tag(tag) {}
const MemRegion *getRegion() const { return R; }
const Stmt* getStmt() const { return S; }
unsigned getCount() const { return Count; }
const void* getTag() const { return Tag; }
QualType getType(ASTContext&) const;
void dumpToStream(llvm::raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion *R,
const Stmt *S, QualType T, unsigned Count,
const void *Tag) {
profile.AddInteger((unsigned) MetadataKind);
profile.AddPointer(R);
profile.AddPointer(S);
profile.Add(T);
profile.AddInteger(Count);
profile.AddPointer(Tag);
}
virtual void Profile(llvm::FoldingSetNodeID& profile) {
Profile(profile, R, S, T, Count, Tag);
}
// Implement isa<T> support.
static inline bool classof(const SymExpr* SE) {
return SE->getKind() == MetadataKind;
}
};
// SymIntExpr - Represents symbolic expression like 'x' + 3.
class SymIntExpr : public SymExpr {
const SymExpr *LHS;
BinaryOperator::Opcode Op;
const llvm::APSInt& RHS;
QualType T;
public:
SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
const llvm::APSInt& rhs, QualType t)
: SymExpr(SymIntKind), LHS(lhs), Op(op), RHS(rhs), T(t) {}
// FIXME: We probably need to make this out-of-line to avoid redundant
// generation of virtual functions.
QualType getType(ASTContext& C) const { return T; }
BinaryOperator::Opcode getOpcode() const { return Op; }
void dumpToStream(llvm::raw_ostream &os) const;
const SymExpr *getLHS() const { return LHS; }
const llvm::APSInt &getRHS() const { return RHS; }
static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
BinaryOperator::Opcode op, const llvm::APSInt& rhs,
QualType t) {
ID.AddInteger((unsigned) SymIntKind);
ID.AddPointer(lhs);
ID.AddInteger(op);
ID.AddPointer(&rhs);
ID.Add(t);
}
void Profile(llvm::FoldingSetNodeID& ID) {
Profile(ID, LHS, Op, RHS, T);
}
// Implement isa<T> support.
static inline bool classof(const SymExpr* SE) {
return SE->getKind() == SymIntKind;
}
};
// SymSymExpr - Represents symbolic expression like 'x' + 'y'.
class SymSymExpr : public SymExpr {
const SymExpr *LHS;
BinaryOperator::Opcode Op;
const SymExpr *RHS;
QualType T;
public:
SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs,
QualType t)
: SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {}
BinaryOperator::Opcode getOpcode() const { return Op; }
const SymExpr *getLHS() const { return LHS; }
const SymExpr *getRHS() const { return RHS; }
// FIXME: We probably need to make this out-of-line to avoid redundant
// generation of virtual functions.
QualType getType(ASTContext& C) const { return T; }
void dumpToStream(llvm::raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) {
ID.AddInteger((unsigned) SymSymKind);
ID.AddPointer(lhs);
ID.AddInteger(op);
ID.AddPointer(rhs);
ID.Add(t);
}
void Profile(llvm::FoldingSetNodeID& ID) {
Profile(ID, LHS, Op, RHS, T);
}
// Implement isa<T> support.
static inline bool classof(const SymExpr* SE) {
return SE->getKind() == SymSymKind;
}
};
class SymbolManager {
typedef llvm::FoldingSet<SymExpr> DataSetTy;
DataSetTy DataSet;
unsigned SymbolCounter;
llvm::BumpPtrAllocator& BPAlloc;
BasicValueFactory &BV;
ASTContext& Ctx;
public:
SymbolManager(ASTContext& ctx, BasicValueFactory &bv,
llvm::BumpPtrAllocator& bpalloc)
: SymbolCounter(0), BPAlloc(bpalloc), BV(bv), Ctx(ctx) {}
~SymbolManager();
static bool canSymbolicate(QualType T);
/// Make a unique symbol for MemRegion R according to its kind.
const SymbolRegionValue* getRegionValueSymbol(const TypedRegion* R);
const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T,
unsigned VisitCount,
const void* SymbolTag = 0);
const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount,
const void* SymbolTag = 0) {
return getConjuredSymbol(E, E->getType(), VisitCount, SymbolTag);
}
const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol,
const TypedRegion *R);
const SymbolExtent *getExtentSymbol(const SubRegion *R);
const SymbolMetadata* getMetadataSymbol(const MemRegion* R, const Stmt* S,
QualType T, unsigned VisitCount,
const void* SymbolTag = 0);
const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
const llvm::APSInt& rhs, QualType t);
const SymIntExpr *getSymIntExpr(const SymExpr &lhs, BinaryOperator::Opcode op,
const llvm::APSInt& rhs, QualType t) {
return getSymIntExpr(&lhs, op, rhs, t);
}
const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
const SymExpr *rhs, QualType t);
QualType getType(const SymExpr *SE) const {
return SE->getType(Ctx);
}
ASTContext &getContext() { return Ctx; }
BasicValueFactory &getBasicVals() { return BV; }
};
class SymbolReaper {
typedef llvm::DenseSet<SymbolRef> SetTy;
SetTy TheLiving;
SetTy MetadataInUse;
SetTy TheDead;
const LocationContext *LCtx;
const Stmt *Loc;
SymbolManager& SymMgr;
public:
SymbolReaper(const LocationContext *ctx, const Stmt *s, SymbolManager& symmgr)
: LCtx(ctx), Loc(s), SymMgr(symmgr) {}
~SymbolReaper() {}
const LocationContext *getLocationContext() const { return LCtx; }
const Stmt *getCurrentStatement() const { return Loc; }
bool isLive(SymbolRef sym);
bool isLive(const Stmt *ExprVal) const;
bool isLive(const VarRegion *VR) const;
// markLive - Unconditionally marks a symbol as live. This should never be
// used by checkers, only by the state infrastructure such as the store and
// environment. Checkers should instead use metadata symbols and markInUse.
void markLive(SymbolRef sym);
// markInUse - Marks a symbol as important to a checker. For metadata symbols,
// this will keep the symbol alive as long as its associated region is also
// live. For other symbols, this has no effect; checkers are not permitted
// to influence the life of other symbols. This should be used before any
// symbol marking has occurred, i.e. in the MarkLiveSymbols callback.
void markInUse(SymbolRef sym);
// maybeDead - If a symbol is known to be live, marks the symbol as live.
// Otherwise, if the symbol cannot be proven live, it is marked as dead.
// Returns true if the symbol is dead, false if live.
bool maybeDead(SymbolRef sym);
typedef SetTy::const_iterator dead_iterator;
dead_iterator dead_begin() const { return TheDead.begin(); }
dead_iterator dead_end() const { return TheDead.end(); }
bool hasDeadSymbols() const {
return !TheDead.empty();
}
/// isDead - Returns whether or not a symbol has been confirmed dead. This
/// should only be called once all marking of dead symbols has completed.
/// (For checkers, this means only in the evalDeadSymbols callback.)
bool isDead(SymbolRef sym) const {
return TheDead.count(sym);
}
};
class SymbolVisitor {
public:
// VisitSymbol - A visitor method invoked by
// GRStateManager::scanReachableSymbols. The method returns \c true if
// symbols should continue be scanned and \c false otherwise.
virtual bool VisitSymbol(SymbolRef sym) = 0;
virtual ~SymbolVisitor();
};
} // end GR namespace
} // end clang namespace
namespace llvm {
static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os,
const clang::ento::SymExpr *SE) {
SE->dumpToStream(os);
return os;
}
} // end llvm namespace
#endif

View File

@ -0,0 +1,92 @@
//== TransferFuncs.h - Path-Sens. Transfer Functions Interface ---*- C++ -*--=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines TransferFuncs, which provides a base-class that
// defines an interface for transfer functions used by ExprEngine.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_TRANSFERFUNCS
#define LLVM_CLANG_GR_TRANSFERFUNCS
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
#include <vector>
namespace clang {
class ObjCMessageExpr;
namespace ento {
class ExplodedNode;
class ExplodedNodeSet;
class EndPathNodeBuilder;
class ExprEngine;
class StmtNodeBuilder;
class StmtNodeBuilderRef;
class TransferFuncs {
public:
TransferFuncs() {}
virtual ~TransferFuncs() {}
virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {}
virtual void RegisterChecks(ExprEngine& Eng) {}
// Calls.
virtual void evalCall(ExplodedNodeSet& Dst,
ExprEngine& Engine,
StmtNodeBuilder& Builder,
const CallExpr* CE, SVal L,
ExplodedNode* Pred) {}
virtual void evalObjCMessageExpr(ExplodedNodeSet& Dst,
ExprEngine& Engine,
StmtNodeBuilder& Builder,
const ObjCMessageExpr* ME,
ExplodedNode* Pred,
const GRState *state) {}
// Stores.
virtual void evalBind(StmtNodeBuilderRef& B, SVal location, SVal val) {}
// End-of-path and dead symbol notification.
virtual void evalEndPath(ExprEngine& Engine,
EndPathNodeBuilder& Builder) {}
virtual void evalDeadSymbols(ExplodedNodeSet& Dst,
ExprEngine& Engine,
StmtNodeBuilder& Builder,
ExplodedNode* Pred,
const GRState* state,
SymbolReaper& SymReaper) {}
// Return statements.
virtual void evalReturn(ExplodedNodeSet& Dst,
ExprEngine& Engine,
StmtNodeBuilder& Builder,
const ReturnStmt* S,
ExplodedNode* Pred) {}
// Assumptions.
virtual const GRState* evalAssume(const GRState *state,
SVal Cond, bool Assumption) {
return state;
}
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -0,0 +1,94 @@
//==- WorkList.h - Worklist class used by CoreEngine ---------------*- C++ -*-//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines WorkList, a pure virtual class that represents an opaque
// worklist used by CoreEngine to explore the reachability state space.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_WORKLIST
#define LLVM_CLANG_GR_WORKLIST
#include "clang/StaticAnalyzer/PathSensitive/BlockCounter.h"
#include <cstddef>
namespace clang {
class CFGBlock;
namespace ento {
class ExplodedNode;
class ExplodedNodeImpl;
class WorkListUnit {
ExplodedNode* Node;
BlockCounter Counter;
const CFGBlock* Block;
unsigned BlockIdx; // This is the index of the next statement.
public:
WorkListUnit(ExplodedNode* N, BlockCounter C,
const CFGBlock* B, unsigned idx)
: Node(N),
Counter(C),
Block(B),
BlockIdx(idx) {}
explicit WorkListUnit(ExplodedNode* N, BlockCounter C)
: Node(N),
Counter(C),
Block(NULL),
BlockIdx(0) {}
ExplodedNode* getNode() const { return Node; }
BlockCounter getBlockCounter() const { return Counter; }
const CFGBlock* getBlock() const { return Block; }
unsigned getIndex() const { return BlockIdx; }
};
class WorkList {
BlockCounter CurrentCounter;
public:
virtual ~WorkList();
virtual bool hasWork() const = 0;
virtual void Enqueue(const WorkListUnit& U) = 0;
void Enqueue(ExplodedNode* N, const CFGBlock* B, unsigned idx) {
Enqueue(WorkListUnit(N, CurrentCounter, B, idx));
}
void Enqueue(ExplodedNode* N) {
Enqueue(WorkListUnit(N, CurrentCounter));
}
virtual WorkListUnit Dequeue() = 0;
void setBlockCounter(BlockCounter C) { CurrentCounter = C; }
BlockCounter getBlockCounter() const { return CurrentCounter; }
class Visitor {
public:
Visitor() {}
virtual ~Visitor();
virtual bool Visit(const WorkListUnit &U) = 0;
};
virtual bool VisitItemsInWorkList(Visitor &V) = 0;
static WorkList *MakeDFS();
static WorkList *MakeBFS();
static WorkList *MakeBFSBlockDFSContents();
};
} // end GR namespace
} // end clang namespace
#endif

View File

@ -12,5 +12,5 @@ add_subdirectory(Serialization)
add_subdirectory(Frontend)
add_subdirectory(FrontendTool)
add_subdirectory(Index)
add_subdirectory(EntoSA)
add_subdirectory(EntoSA/Checkers)
add_subdirectory(StaticAnalyzer)
add_subdirectory(StaticAnalyzer/Checkers)

View File

@ -1,7 +1,7 @@
set(LLVM_NO_RTTI 1)
set(LLVM_USED_LIBS clangDriver clangFrontend clangRewrite clangCodeGen
clangEntoCheckers clangEntoCore)
clangStaticAnalyzerCheckers clangStaticAnalyzerCore)
add_clang_library(clangFrontendTool
ExecuteCompilerInvocation.cpp

View File

@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/FrontendTool/Utils.h"
#include "clang/EntoSA/FrontendActions.h"
#include "clang/StaticAnalyzer/FrontendActions.h"
#include "clang/CodeGen/CodeGenAction.h"
#include "clang/Driver/CC1Options.h"
#include "clang/Driver/OptTable.h"

View File

@ -9,7 +9,7 @@
CLANG_LEVEL := ..
PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \
EntoSA Rewrite Serialization Frontend FrontendTool Index Driver
StaticAnalyzer Rewrite Serialization Frontend FrontendTool Index Driver
include $(CLANG_LEVEL)/Makefile

View File

@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
#include "clang/AST/StmtVisitor.h"
using namespace clang;

View File

@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/EntoSA/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
#include "clang/Index/Entity.h"
#include "clang/Index/Indexer.h"

View File

@ -9,9 +9,9 @@
// This file reports various statistics about analyzer visitation.
//===----------------------------------------------------------------------===//
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
#include "clang/EntoSA/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
// FIXME: Restructure checker registration.
#include "Checkers/ExprEngineExperimentalChecks.h"

View File

@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "SimpleConstraintManager.h"
#include "clang/EntoSA/PathSensitive/GRState.h"
#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
#include "clang/EntoSA/PathSensitive/TransferFuncs.h"
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;

View File

@ -15,7 +15,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/EntoSA/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
#include "llvm/ADT/ImmutableMap.h"
using namespace clang;

View File

@ -13,7 +13,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/EntoSA/PathSensitive/BasicValueFactory.h"
#include "clang/StaticAnalyzer/PathSensitive/BasicValueFactory.h"
using namespace clang;
using namespace ento;

View File

@ -13,7 +13,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/EntoSA/PathSensitive/BlockCounter.h"
#include "clang/StaticAnalyzer/PathSensitive/BlockCounter.h"
#include "llvm/ADT/ImmutableMap.h"
using namespace clang;

View File

@ -12,9 +12,9 @@
//
//===----------------------------------------------------------------------===//
#include "clang/EntoSA/BugReporter/BugReporter.h"
#include "clang/EntoSA/BugReporter/BugType.h"
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/AST/Expr.h"
@ -22,7 +22,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"

View File

@ -14,10 +14,10 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/EntoSA/BugReporter/BugReporter.h"
#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
#include "clang/EntoSA/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
using namespace clang;
using namespace ento;

View File

@ -16,15 +16,15 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/EntoSA/BugReporter/BugType.h"
#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
#include "clang/EntoSA/Checkers/LocalCheckers.h"
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
#include "clang/EntoSA/PathSensitive/ExprEngineBuilders.h"
#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
#include "clang/EntoSA/PathSensitive/TransferFuncs.h"
#include "clang/EntoSA/PathSensitive/SymbolManager.h"
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/PathSensitive/ExprEngineBuilders.h"
#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"

View File

@ -2,7 +2,7 @@ set(LLVM_NO_RTTI 1)
set(LLVM_USED_LIBS clangBasic clangLex clangAST clangFrontend clangRewrite)
add_clang_library(clangEntoCore
add_clang_library(clangStaticAnalyzerCore
AggExprVisitor.cpp
AnalysisManager.cpp
AnalyzerStatsChecker.cpp
@ -37,5 +37,5 @@ add_clang_library(clangEntoCore
TextPathDiagnostics.cpp
)
add_dependencies(clangEntoCore ClangAttrClasses ClangAttrList ClangDeclNodes
add_dependencies(clangStaticAnalyzerCore ClangAttrClasses ClangAttrList ClangDeclNodes
ClangStmtNodes)

View File

@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
#include "clang/EntoSA/PathSensitive/AnalysisManager.h"
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
#include "clang/AST/DeclCXX.h"
using namespace clang;

View File

@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/EntoSA/PathSensitive/Checker.h"
#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
using namespace clang;
using namespace ento;

View File

@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/EntoSA/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/PathSensitive/CheckerHelpers.h"
#include "clang/AST/Expr.h"
// Recursively find any substatements containing macros

View File

@ -14,9 +14,9 @@
//===----------------------------------------------------------------------===//
#include "ExprEngineInternalChecks.h"
#include "clang/EntoSA/BugReporter/BugReporter.h"
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;

View File

@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/EntoSA/AnalysisConsumer.h"
#include "clang/StaticAnalyzer/AnalysisConsumer.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
@ -20,14 +20,14 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
#include "clang/Analysis/CFG.h"
#include "clang/EntoSA/Checkers/LocalCheckers.h"
#include "clang/EntoSA/ManagerRegistry.h"
#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
#include "clang/EntoSA/PathSensitive/AnalysisManager.h"
#include "clang/EntoSA/BugReporter/BugReporter.h"
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
#include "clang/EntoSA/PathSensitive/TransferFuncs.h"
#include "clang/EntoSA/PathDiagnosticClients.h"
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
#include "clang/StaticAnalyzer/ManagerRegistry.h"
#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
#include "clang/StaticAnalyzer/PathDiagnosticClients.h"
// FIXME: Restructure checker registration.
#include "ExprEngineExperimentalChecks.h"

View File

@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "ExprEngineInternalChecks.h"
#include "clang/EntoSA/BugReporter/BugType.h"
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
using namespace clang;
using namespace ento;

View File

@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "ExprEngineInternalChecks.h"
#include "clang/EntoSA/BugReporter/BugType.h"
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
#include "clang/AST/CharUnits.h"
using namespace clang;

View File

@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "ExprEngineInternalChecks.h"
#include "clang/EntoSA/BugReporter/BugType.h"
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;

View File

@ -15,14 +15,14 @@
#include "BasicObjCFoundationChecks.h"
#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
#include "clang/EntoSA/PathSensitive/GRState.h"
#include "clang/EntoSA/BugReporter/BugType.h"
#include "clang/EntoSA/PathSensitive/MemRegion.h"
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
#include "clang/EntoSA/Checkers/LocalCheckers.h"
#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"

View File

@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "ExprEngineInternalChecks.h"
#include "clang/EntoSA/PathSensitive/Checker.h"
#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
#include "clang/Basic/Builtins.h"
using namespace clang;

View File

@ -1,4 +1,4 @@
add_clang_library(clangEntoCheckers
add_clang_library(clangStaticAnalyzerCheckers
AdjustedReturnValueChecker.cpp
AnalysisConsumer.cpp
ArrayBoundChecker.cpp
@ -49,5 +49,5 @@ add_clang_library(clangEntoCheckers
VLASizeChecker.cpp
)
add_dependencies(clangEntoCore ClangAttrClasses ClangAttrList ClangDeclNodes
add_dependencies(clangStaticAnalyzerCore ClangAttrClasses ClangAttrList ClangDeclNodes
ClangStmtNodes)

View File

@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "ExprEngineExperimentalChecks.h"
#include "clang/EntoSA/BugReporter/BugType.h"
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;

View File

@ -15,8 +15,8 @@
#include "ExprEngineInternalChecks.h"
#include "clang/AST/ParentMap.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/EntoSA/BugReporter/BugType.h"
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;

Some files were not shown because too many files have changed in this diff Show More