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:
@@ -10,8 +10,8 @@ set( LLVM_USED_LIBS
|
|||||||
clangCodeGen
|
clangCodeGen
|
||||||
clangParse
|
clangParse
|
||||||
clangSema
|
clangSema
|
||||||
clangEntoCheckers
|
clangStaticAnalyzerCheckers
|
||||||
clangEntoCore
|
clangStaticAnalyzerCore
|
||||||
clangAnalysis
|
clangAnalysis
|
||||||
clangIndex
|
clangIndex
|
||||||
clangRewrite
|
clangRewrite
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ set(LLVM_USED_LIBS
|
|||||||
clangDriver
|
clangDriver
|
||||||
clangCodeGen
|
clangCodeGen
|
||||||
clangSema
|
clangSema
|
||||||
clangEntoCheckers
|
clangStaticAnalyzerCheckers
|
||||||
clangEntoCore
|
clangStaticAnalyzerCore
|
||||||
clangIndex
|
clangIndex
|
||||||
clangAnalysis
|
clangAnalysis
|
||||||
clangRewrite
|
clangRewrite
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ TOOL_NO_EXPORTS = 1
|
|||||||
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
|
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
|
||||||
selectiondag asmparser
|
selectiondag asmparser
|
||||||
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
|
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
|
clangAST.a clangParse.a clangLex.a clangBasic.a
|
||||||
|
|
||||||
include $(CLANG_LEVEL)/Makefile
|
include $(CLANG_LEVEL)/Makefile
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ set(LLVM_USED_LIBS
|
|||||||
clangSema
|
clangSema
|
||||||
clangAnalysis
|
clangAnalysis
|
||||||
clangSerialization
|
clangSerialization
|
||||||
clangEntoCheckers
|
clangStaticAnalyzerCheckers
|
||||||
clangEntoCore
|
clangStaticAnalyzerCore
|
||||||
clangRewrite
|
clangRewrite
|
||||||
clangAST
|
clangAST
|
||||||
clangParse
|
clangParse
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ NO_INSTALL = 1
|
|||||||
TOOL_NO_EXPORTS = 1
|
TOOL_NO_EXPORTS = 1
|
||||||
|
|
||||||
LINK_COMPONENTS := asmparser bitreader mc core
|
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 \
|
clangSema.a clangAnalysis.a clangSerialization.a \
|
||||||
clangAST.a clangParse.a clangLex.a clangBasic.a
|
clangAST.a clangParse.a clangLex.a clangBasic.a
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
#define LLVM_CLANG_GR_BUGREPORTER
|
#define LLVM_CLANG_GR_BUGREPORTER
|
||||||
|
|
||||||
#include "clang/Basic/SourceLocation.h"
|
#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/FoldingSet.h"
|
||||||
#include "llvm/ADT/ImmutableList.h"
|
#include "llvm/ADT/ImmutableList.h"
|
||||||
#include "llvm/ADT/ImmutableSet.h"
|
#include "llvm/ADT/ImmutableSet.h"
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
|
#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
|
||||||
#define 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 "llvm/ADT/FoldingSet.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
39
clang/include/clang/StaticAnalyzer/EntoSA/AnalysisConsumer.h
Normal file
39
clang/include/clang/StaticAnalyzer/EntoSA/AnalysisConsumer.h
Normal 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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
#ifndef LLVM_CLANG_GR_MANAGER_REGISTRY_H
|
#ifndef LLVM_CLANG_GR_MANAGER_REGISTRY_H
|
||||||
#define 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 {
|
namespace clang {
|
||||||
|
|
||||||
@@ -16,8 +16,8 @@
|
|||||||
#define LLVM_CLANG_GR_ANALYSISMANAGER_H
|
#define LLVM_CLANG_GR_ANALYSISMANAGER_H
|
||||||
|
|
||||||
#include "clang/Analysis/AnalysisContext.h"
|
#include "clang/Analysis/AnalysisContext.h"
|
||||||
#include "clang/EntoSA/BugReporter/BugReporter.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
|
||||||
#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
|
#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
#ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H
|
#ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H
|
||||||
#define 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 "clang/AST/ASTContext.h"
|
||||||
#include "llvm/ADT/FoldingSet.h"
|
#include "llvm/ADT/FoldingSet.h"
|
||||||
#include "llvm/ADT/APSInt.h"
|
#include "llvm/ADT/APSInt.h"
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
#define LLVM_CLANG_GR_CHECKER
|
#define LLVM_CLANG_GR_CHECKER
|
||||||
|
|
||||||
#include "clang/Analysis/Support/SaveAndRestore.h"
|
#include "clang/Analysis/Support/SaveAndRestore.h"
|
||||||
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Checker interface.
|
// Checker interface.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#ifndef LLVM_CLANG_GR_CHECKERVISITOR
|
#ifndef LLVM_CLANG_GR_CHECKERVISITOR
|
||||||
#define LLVM_CLANG_GR_CHECKERVISITOR
|
#define LLVM_CLANG_GR_CHECKERVISITOR
|
||||||
#include "clang/EntoSA/PathSensitive/Checker.h"
|
#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ public:
|
|||||||
case Stmt::NAME ## Class:\
|
case Stmt::NAME ## Class:\
|
||||||
static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\
|
static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\
|
||||||
break;
|
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)->\
|
static_cast<ImplClass*>(this)->\
|
||||||
PostVisit ## NAME(C,static_cast<const NAME*>(S));\
|
PostVisit ## NAME(C,static_cast<const NAME*>(S));\
|
||||||
break;
|
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) {\
|
void PostVisit ## NAME(CheckerContext &C, const NAME* S) {\
|
||||||
static_cast<ImplClass*>(this)->PostVisit ## FALLBACK(C, S);\
|
static_cast<ImplClass*>(this)->PostVisit ## FALLBACK(C, S);\
|
||||||
}
|
}
|
||||||
#include "clang/EntoSA/PathSensitive/CheckerVisitor.def"
|
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def"
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end GR namespace
|
} // end GR namespace
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
#define LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
|
#define LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
|
||||||
|
|
||||||
// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place.
|
// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place.
|
||||||
#include "clang/EntoSA/PathSensitive/Store.h"
|
#include "clang/StaticAnalyzer/PathSensitive/Store.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class APSInt;
|
class APSInt;
|
||||||
@@ -16,10 +16,10 @@
|
|||||||
#define LLVM_CLANG_GR_COREENGINE
|
#define LLVM_CLANG_GR_COREENGINE
|
||||||
|
|
||||||
#include "clang/AST/Expr.h"
|
#include "clang/AST/Expr.h"
|
||||||
#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
|
||||||
#include "clang/EntoSA/PathSensitive/WorkList.h"
|
#include "clang/StaticAnalyzer/PathSensitive/WorkList.h"
|
||||||
#include "clang/EntoSA/PathSensitive/BlockCounter.h"
|
#include "clang/StaticAnalyzer/PathSensitive/BlockCounter.h"
|
||||||
#include "clang/EntoSA/PathSensitive/SubEngine.h"
|
#include "clang/StaticAnalyzer/PathSensitive/SubEngine.h"
|
||||||
#include "llvm/ADT/OwningPtr.h"
|
#include "llvm/ADT/OwningPtr.h"
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
#ifndef LLVM_CLANG_GR_ENVIRONMENT_H
|
#ifndef LLVM_CLANG_GR_ENVIRONMENT_H
|
||||||
#define LLVM_CLANG_GR_ENVIRONMENT_H
|
#define LLVM_CLANG_GR_ENVIRONMENT_H
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/Store.h"
|
#include "clang/StaticAnalyzer/PathSensitive/Store.h"
|
||||||
#include "clang/EntoSA/PathSensitive/SVals.h"
|
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
|
||||||
#include "llvm/ADT/ImmutableMap.h"
|
#include "llvm/ADT/ImmutableMap.h"
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
@@ -16,12 +16,12 @@
|
|||||||
#ifndef LLVM_CLANG_GR_EXPRENGINE
|
#ifndef LLVM_CLANG_GR_EXPRENGINE
|
||||||
#define LLVM_CLANG_GR_EXPRENGINE
|
#define LLVM_CLANG_GR_EXPRENGINE
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/AnalysisManager.h"
|
#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
|
||||||
#include "clang/EntoSA/PathSensitive/SubEngine.h"
|
#include "clang/StaticAnalyzer/PathSensitive/SubEngine.h"
|
||||||
#include "clang/EntoSA/PathSensitive/CoreEngine.h"
|
#include "clang/StaticAnalyzer/PathSensitive/CoreEngine.h"
|
||||||
#include "clang/EntoSA/PathSensitive/GRState.h"
|
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
|
||||||
#include "clang/EntoSA/PathSensitive/TransferFuncs.h"
|
#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
|
||||||
#include "clang/EntoSA/BugReporter/BugReporter.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
|
||||||
#include "clang/AST/Type.h"
|
#include "clang/AST/Type.h"
|
||||||
#include "clang/AST/ExprObjC.h"
|
#include "clang/AST/ExprObjC.h"
|
||||||
#include "clang/AST/ExprCXX.h"
|
#include "clang/AST/ExprCXX.h"
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
#ifndef LLVM_CLANG_GR_EXPRENGINE_BUILDERS
|
#ifndef LLVM_CLANG_GR_EXPRENGINE_BUILDERS
|
||||||
#define 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"
|
#include "clang/Analysis/Support/SaveAndRestore.h"
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
@@ -14,10 +14,10 @@
|
|||||||
#ifndef LLVM_CLANG_GR_VALUESTATE_H
|
#ifndef LLVM_CLANG_GR_VALUESTATE_H
|
||||||
#define LLVM_CLANG_GR_VALUESTATE_H
|
#define LLVM_CLANG_GR_VALUESTATE_H
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/ConstraintManager.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ConstraintManager.h"
|
||||||
#include "clang/EntoSA/PathSensitive/Environment.h"
|
#include "clang/StaticAnalyzer/PathSensitive/Environment.h"
|
||||||
#include "clang/EntoSA/PathSensitive/Store.h"
|
#include "clang/StaticAnalyzer/PathSensitive/Store.h"
|
||||||
#include "clang/EntoSA/PathSensitive/SValBuilder.h"
|
#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
|
||||||
#include "llvm/ADT/FoldingSet.h"
|
#include "llvm/ADT/FoldingSet.h"
|
||||||
#include "llvm/ADT/ImmutableMap.h"
|
#include "llvm/ADT/ImmutableMap.h"
|
||||||
#include "llvm/Support/Casting.h"
|
#include "llvm/Support/Casting.h"
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#include "clang/AST/Decl.h"
|
#include "clang/AST/Decl.h"
|
||||||
#include "clang/AST/DeclObjC.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/Casting.h"
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
#include "llvm/ADT/FoldingSet.h"
|
#include "llvm/ADT/FoldingSet.h"
|
||||||
@@ -17,9 +17,9 @@
|
|||||||
|
|
||||||
#include "clang/AST/Expr.h"
|
#include "clang/AST/Expr.h"
|
||||||
#include "clang/AST/ExprCXX.h"
|
#include "clang/AST/ExprCXX.h"
|
||||||
#include "clang/EntoSA/PathSensitive/SVals.h"
|
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
|
||||||
#include "clang/EntoSA/PathSensitive/BasicValueFactory.h"
|
#include "clang/StaticAnalyzer/PathSensitive/BasicValueFactory.h"
|
||||||
#include "clang/EntoSA/PathSensitive/MemRegion.h"
|
#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
#ifndef LLVM_CLANG_GR_RVALUE_H
|
#ifndef LLVM_CLANG_GR_RVALUE_H
|
||||||
#define 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/Support/Casting.h"
|
||||||
#include "llvm/ADT/ImmutableList.h"
|
#include "llvm/ADT/ImmutableList.h"
|
||||||
|
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
#ifndef LLVM_CLANG_GR_STORE_H
|
#ifndef LLVM_CLANG_GR_STORE_H
|
||||||
#define LLVM_CLANG_GR_STORE_H
|
#define LLVM_CLANG_GR_STORE_H
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/MemRegion.h"
|
#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
|
||||||
#include "clang/EntoSA/PathSensitive/SValBuilder.h"
|
#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
|
||||||
#include "llvm/ADT/DenseSet.h"
|
#include "llvm/ADT/DenseSet.h"
|
||||||
#include "llvm/ADT/Optional.h"
|
#include "llvm/ADT/Optional.h"
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
#ifndef LLVM_CLANG_GR_SUBENGINE_H
|
#ifndef LLVM_CLANG_GR_SUBENGINE_H
|
||||||
#define 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 {
|
namespace clang {
|
||||||
|
|
||||||
@@ -15,8 +15,8 @@
|
|||||||
#ifndef LLVM_CLANG_GR_TRANSFERFUNCS
|
#ifndef LLVM_CLANG_GR_TRANSFERFUNCS
|
||||||
#define LLVM_CLANG_GR_TRANSFERFUNCS
|
#define LLVM_CLANG_GR_TRANSFERFUNCS
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/GRState.h"
|
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
|
||||||
#include "clang/EntoSA/PathSensitive/SVals.h"
|
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
#ifndef LLVM_CLANG_GR_WORKLIST
|
#ifndef LLVM_CLANG_GR_WORKLIST
|
||||||
#define LLVM_CLANG_GR_WORKLIST
|
#define LLVM_CLANG_GR_WORKLIST
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/BlockCounter.h"
|
#include "clang/StaticAnalyzer/PathSensitive/BlockCounter.h"
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
33
clang/include/clang/StaticAnalyzer/FrontendActions.h
Normal file
33
clang/include/clang/StaticAnalyzer/FrontendActions.h
Normal 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
|
||||||
58
clang/include/clang/StaticAnalyzer/ManagerRegistry.h
Normal file
58
clang/include/clang/StaticAnalyzer/ManagerRegistry.h
Normal 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
|
||||||
42
clang/include/clang/StaticAnalyzer/PathDiagnosticClients.h
Normal file
42
clang/include/clang/StaticAnalyzer/PathDiagnosticClients.h
Normal 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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
309
clang/include/clang/StaticAnalyzer/PathSensitive/Checker.h
Normal file
309
clang/include/clang/StaticAnalyzer/PathSensitive/Checker.h
Normal 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
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
542
clang/include/clang/StaticAnalyzer/PathSensitive/CoreEngine.h
Normal file
542
clang/include/clang/StaticAnalyzer/PathSensitive/CoreEngine.h
Normal 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
|
||||||
106
clang/include/clang/StaticAnalyzer/PathSensitive/Environment.h
Normal file
106
clang/include/clang/StaticAnalyzer/PathSensitive/Environment.h
Normal 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
|
||||||
435
clang/include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h
Normal file
435
clang/include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h
Normal 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
|
||||||
544
clang/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h
Normal file
544
clang/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h
Normal 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
|
||||||
@@ -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
|
||||||
760
clang/include/clang/StaticAnalyzer/PathSensitive/GRState.h
Normal file
760
clang/include/clang/StaticAnalyzer/PathSensitive/GRState.h
Normal 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
|
||||||
152
clang/include/clang/StaticAnalyzer/PathSensitive/GRStateTrait.h
Normal file
152
clang/include/clang/StaticAnalyzer/PathSensitive/GRStateTrait.h
Normal 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
|
||||||
1077
clang/include/clang/StaticAnalyzer/PathSensitive/MemRegion.h
Normal file
1077
clang/include/clang/StaticAnalyzer/PathSensitive/MemRegion.h
Normal file
File diff suppressed because it is too large
Load Diff
259
clang/include/clang/StaticAnalyzer/PathSensitive/SValBuilder.h
Normal file
259
clang/include/clang/StaticAnalyzer/PathSensitive/SValBuilder.h
Normal 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
|
||||||
522
clang/include/clang/StaticAnalyzer/PathSensitive/SVals.h
Normal file
522
clang/include/clang/StaticAnalyzer/PathSensitive/SVals.h
Normal 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
|
||||||
259
clang/include/clang/StaticAnalyzer/PathSensitive/Store.h
Normal file
259
clang/include/clang/StaticAnalyzer/PathSensitive/Store.h
Normal 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
|
||||||
113
clang/include/clang/StaticAnalyzer/PathSensitive/SubEngine.h
Normal file
113
clang/include/clang/StaticAnalyzer/PathSensitive/SubEngine.h
Normal 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
|
||||||
@@ -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
|
||||||
489
clang/include/clang/StaticAnalyzer/PathSensitive/SymbolManager.h
Normal file
489
clang/include/clang/StaticAnalyzer/PathSensitive/SymbolManager.h
Normal 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
|
||||||
@@ -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
|
||||||
94
clang/include/clang/StaticAnalyzer/PathSensitive/WorkList.h
Normal file
94
clang/include/clang/StaticAnalyzer/PathSensitive/WorkList.h
Normal 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
|
||||||
@@ -12,5 +12,5 @@ add_subdirectory(Serialization)
|
|||||||
add_subdirectory(Frontend)
|
add_subdirectory(Frontend)
|
||||||
add_subdirectory(FrontendTool)
|
add_subdirectory(FrontendTool)
|
||||||
add_subdirectory(Index)
|
add_subdirectory(Index)
|
||||||
add_subdirectory(EntoSA)
|
add_subdirectory(StaticAnalyzer)
|
||||||
add_subdirectory(EntoSA/Checkers)
|
add_subdirectory(StaticAnalyzer/Checkers)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
set(LLVM_NO_RTTI 1)
|
set(LLVM_NO_RTTI 1)
|
||||||
|
|
||||||
set(LLVM_USED_LIBS clangDriver clangFrontend clangRewrite clangCodeGen
|
set(LLVM_USED_LIBS clangDriver clangFrontend clangRewrite clangCodeGen
|
||||||
clangEntoCheckers clangEntoCore)
|
clangStaticAnalyzerCheckers clangStaticAnalyzerCore)
|
||||||
|
|
||||||
add_clang_library(clangFrontendTool
|
add_clang_library(clangFrontendTool
|
||||||
ExecuteCompilerInvocation.cpp
|
ExecuteCompilerInvocation.cpp
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "clang/FrontendTool/Utils.h"
|
#include "clang/FrontendTool/Utils.h"
|
||||||
#include "clang/EntoSA/FrontendActions.h"
|
#include "clang/StaticAnalyzer/FrontendActions.h"
|
||||||
#include "clang/CodeGen/CodeGenAction.h"
|
#include "clang/CodeGen/CodeGenAction.h"
|
||||||
#include "clang/Driver/CC1Options.h"
|
#include "clang/Driver/CC1Options.h"
|
||||||
#include "clang/Driver/OptTable.h"
|
#include "clang/Driver/OptTable.h"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
CLANG_LEVEL := ..
|
CLANG_LEVEL := ..
|
||||||
|
|
||||||
PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \
|
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
|
include $(CLANG_LEVEL)/Makefile
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
|
||||||
#include "clang/AST/StmtVisitor.h"
|
#include "clang/AST/StmtVisitor.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/AnalysisManager.h"
|
#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
|
||||||
#include "clang/Index/Entity.h"
|
#include "clang/Index/Entity.h"
|
||||||
#include "clang/Index/Indexer.h"
|
#include "clang/Index/Indexer.h"
|
||||||
|
|
||||||
@@ -9,9 +9,9 @@
|
|||||||
// This file reports various statistics about analyzer visitation.
|
// This file reports various statistics about analyzer visitation.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
|
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
|
||||||
#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
|
||||||
#include "clang/EntoSA/BugReporter/BugReporter.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
|
||||||
|
|
||||||
// FIXME: Restructure checker registration.
|
// FIXME: Restructure checker registration.
|
||||||
#include "Checkers/ExprEngineExperimentalChecks.h"
|
#include "Checkers/ExprEngineExperimentalChecks.h"
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "SimpleConstraintManager.h"
|
#include "SimpleConstraintManager.h"
|
||||||
#include "clang/EntoSA/PathSensitive/GRState.h"
|
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
|
||||||
#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
|
#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
|
||||||
#include "clang/EntoSA/PathSensitive/TransferFuncs.h"
|
#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
#include "clang/AST/ExprObjC.h"
|
#include "clang/AST/ExprObjC.h"
|
||||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||||
#include "clang/Analysis/AnalysisContext.h"
|
#include "clang/Analysis/AnalysisContext.h"
|
||||||
#include "clang/EntoSA/PathSensitive/GRState.h"
|
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
|
||||||
#include "llvm/ADT/ImmutableMap.h"
|
#include "llvm/ADT/ImmutableMap.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/BasicValueFactory.h"
|
#include "clang/StaticAnalyzer/PathSensitive/BasicValueFactory.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using namespace ento;
|
using namespace ento;
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/BlockCounter.h"
|
#include "clang/StaticAnalyzer/PathSensitive/BlockCounter.h"
|
||||||
#include "llvm/ADT/ImmutableMap.h"
|
#include "llvm/ADT/ImmutableMap.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
@@ -12,9 +12,9 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "clang/EntoSA/BugReporter/BugReporter.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
|
||||||
#include "clang/EntoSA/BugReporter/BugType.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
|
||||||
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
|
||||||
#include "clang/AST/ASTContext.h"
|
#include "clang/AST/ASTContext.h"
|
||||||
#include "clang/Analysis/CFG.h"
|
#include "clang/Analysis/CFG.h"
|
||||||
#include "clang/AST/Expr.h"
|
#include "clang/AST/Expr.h"
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
#include "clang/AST/StmtObjC.h"
|
#include "clang/AST/StmtObjC.h"
|
||||||
#include "clang/Basic/SourceManager.h"
|
#include "clang/Basic/SourceManager.h"
|
||||||
#include "clang/Analysis/ProgramPoint.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/Support/raw_ostream.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
@@ -14,10 +14,10 @@
|
|||||||
|
|
||||||
#include "clang/AST/Expr.h"
|
#include "clang/AST/Expr.h"
|
||||||
#include "clang/AST/ExprObjC.h"
|
#include "clang/AST/ExprObjC.h"
|
||||||
#include "clang/EntoSA/BugReporter/BugReporter.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
|
||||||
#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
|
#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
|
||||||
#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
|
||||||
#include "clang/EntoSA/PathSensitive/GRState.h"
|
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using namespace ento;
|
using namespace ento;
|
||||||
@@ -16,15 +16,15 @@
|
|||||||
#include "clang/AST/StmtVisitor.h"
|
#include "clang/AST/StmtVisitor.h"
|
||||||
#include "clang/Basic/LangOptions.h"
|
#include "clang/Basic/LangOptions.h"
|
||||||
#include "clang/Basic/SourceManager.h"
|
#include "clang/Basic/SourceManager.h"
|
||||||
#include "clang/EntoSA/BugReporter/BugType.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
|
||||||
#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
|
#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
|
||||||
#include "clang/EntoSA/Checkers/LocalCheckers.h"
|
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
|
||||||
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
|
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
|
||||||
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
|
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
|
||||||
#include "clang/EntoSA/PathSensitive/ExprEngineBuilders.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ExprEngineBuilders.h"
|
||||||
#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
|
#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
|
||||||
#include "clang/EntoSA/PathSensitive/TransferFuncs.h"
|
#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
|
||||||
#include "clang/EntoSA/PathSensitive/SymbolManager.h"
|
#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/FoldingSet.h"
|
#include "llvm/ADT/FoldingSet.h"
|
||||||
#include "llvm/ADT/ImmutableList.h"
|
#include "llvm/ADT/ImmutableList.h"
|
||||||
@@ -2,7 +2,7 @@ set(LLVM_NO_RTTI 1)
|
|||||||
|
|
||||||
set(LLVM_USED_LIBS clangBasic clangLex clangAST clangFrontend clangRewrite)
|
set(LLVM_USED_LIBS clangBasic clangLex clangAST clangFrontend clangRewrite)
|
||||||
|
|
||||||
add_clang_library(clangEntoCore
|
add_clang_library(clangStaticAnalyzerCore
|
||||||
AggExprVisitor.cpp
|
AggExprVisitor.cpp
|
||||||
AnalysisManager.cpp
|
AnalysisManager.cpp
|
||||||
AnalyzerStatsChecker.cpp
|
AnalyzerStatsChecker.cpp
|
||||||
@@ -37,5 +37,5 @@ add_clang_library(clangEntoCore
|
|||||||
TextPathDiagnostics.cpp
|
TextPathDiagnostics.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_dependencies(clangEntoCore ClangAttrClasses ClangAttrList ClangDeclNodes
|
add_dependencies(clangStaticAnalyzerCore ClangAttrClasses ClangAttrList ClangDeclNodes
|
||||||
ClangStmtNodes)
|
ClangStmtNodes)
|
||||||
@@ -11,8 +11,8 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/AnalysisManager.h"
|
#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
|
||||||
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
|
||||||
#include "clang/AST/DeclCXX.h"
|
#include "clang/AST/DeclCXX.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/Checker.h"
|
#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using namespace ento;
|
using namespace ento;
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/CheckerHelpers.h"
|
#include "clang/StaticAnalyzer/PathSensitive/CheckerHelpers.h"
|
||||||
#include "clang/AST/Expr.h"
|
#include "clang/AST/Expr.h"
|
||||||
|
|
||||||
// Recursively find any substatements containing macros
|
// Recursively find any substatements containing macros
|
||||||
@@ -14,9 +14,9 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "ExprEngineInternalChecks.h"
|
#include "ExprEngineInternalChecks.h"
|
||||||
#include "clang/EntoSA/BugReporter/BugReporter.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
|
||||||
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
|
||||||
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
|
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using namespace ento;
|
using namespace ento;
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "clang/EntoSA/AnalysisConsumer.h"
|
#include "clang/StaticAnalyzer/AnalysisConsumer.h"
|
||||||
#include "clang/AST/ASTConsumer.h"
|
#include "clang/AST/ASTConsumer.h"
|
||||||
#include "clang/AST/Decl.h"
|
#include "clang/AST/Decl.h"
|
||||||
#include "clang/AST/DeclCXX.h"
|
#include "clang/AST/DeclCXX.h"
|
||||||
@@ -20,14 +20,14 @@
|
|||||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||||
#include "clang/Analysis/Analyses/UninitializedValues.h"
|
#include "clang/Analysis/Analyses/UninitializedValues.h"
|
||||||
#include "clang/Analysis/CFG.h"
|
#include "clang/Analysis/CFG.h"
|
||||||
#include "clang/EntoSA/Checkers/LocalCheckers.h"
|
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
|
||||||
#include "clang/EntoSA/ManagerRegistry.h"
|
#include "clang/StaticAnalyzer/ManagerRegistry.h"
|
||||||
#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
|
#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
|
||||||
#include "clang/EntoSA/PathSensitive/AnalysisManager.h"
|
#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
|
||||||
#include "clang/EntoSA/BugReporter/BugReporter.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
|
||||||
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
|
||||||
#include "clang/EntoSA/PathSensitive/TransferFuncs.h"
|
#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
|
||||||
#include "clang/EntoSA/PathDiagnosticClients.h"
|
#include "clang/StaticAnalyzer/PathDiagnosticClients.h"
|
||||||
|
|
||||||
// FIXME: Restructure checker registration.
|
// FIXME: Restructure checker registration.
|
||||||
#include "ExprEngineExperimentalChecks.h"
|
#include "ExprEngineExperimentalChecks.h"
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "ExprEngineInternalChecks.h"
|
#include "ExprEngineInternalChecks.h"
|
||||||
#include "clang/EntoSA/BugReporter/BugType.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
|
||||||
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
|
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
|
||||||
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using namespace ento;
|
using namespace ento;
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "ExprEngineInternalChecks.h"
|
#include "ExprEngineInternalChecks.h"
|
||||||
#include "clang/EntoSA/BugReporter/BugType.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
|
||||||
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
|
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
|
||||||
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
|
||||||
#include "clang/AST/CharUnits.h"
|
#include "clang/AST/CharUnits.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "ExprEngineInternalChecks.h"
|
#include "ExprEngineInternalChecks.h"
|
||||||
#include "clang/EntoSA/BugReporter/BugType.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
|
||||||
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
|
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using namespace ento;
|
using namespace ento;
|
||||||
@@ -15,14 +15,14 @@
|
|||||||
|
|
||||||
#include "BasicObjCFoundationChecks.h"
|
#include "BasicObjCFoundationChecks.h"
|
||||||
|
|
||||||
#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
|
||||||
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
|
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
|
||||||
#include "clang/EntoSA/PathSensitive/ExprEngine.h"
|
#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
|
||||||
#include "clang/EntoSA/PathSensitive/GRState.h"
|
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
|
||||||
#include "clang/EntoSA/BugReporter/BugType.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
|
||||||
#include "clang/EntoSA/PathSensitive/MemRegion.h"
|
#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
|
||||||
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
|
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
|
||||||
#include "clang/EntoSA/Checkers/LocalCheckers.h"
|
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
|
||||||
#include "clang/AST/DeclObjC.h"
|
#include "clang/AST/DeclObjC.h"
|
||||||
#include "clang/AST/Expr.h"
|
#include "clang/AST/Expr.h"
|
||||||
#include "clang/AST/ExprObjC.h"
|
#include "clang/AST/ExprObjC.h"
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "ExprEngineInternalChecks.h"
|
#include "ExprEngineInternalChecks.h"
|
||||||
#include "clang/EntoSA/PathSensitive/Checker.h"
|
#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
|
||||||
#include "clang/Basic/Builtins.h"
|
#include "clang/Basic/Builtins.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
add_clang_library(clangEntoCheckers
|
add_clang_library(clangStaticAnalyzerCheckers
|
||||||
AdjustedReturnValueChecker.cpp
|
AdjustedReturnValueChecker.cpp
|
||||||
AnalysisConsumer.cpp
|
AnalysisConsumer.cpp
|
||||||
ArrayBoundChecker.cpp
|
ArrayBoundChecker.cpp
|
||||||
@@ -49,5 +49,5 @@ add_clang_library(clangEntoCheckers
|
|||||||
VLASizeChecker.cpp
|
VLASizeChecker.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_dependencies(clangEntoCore ClangAttrClasses ClangAttrList ClangDeclNodes
|
add_dependencies(clangStaticAnalyzerCore ClangAttrClasses ClangAttrList ClangDeclNodes
|
||||||
ClangStmtNodes)
|
ClangStmtNodes)
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "ExprEngineExperimentalChecks.h"
|
#include "ExprEngineExperimentalChecks.h"
|
||||||
#include "clang/EntoSA/BugReporter/BugType.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
|
||||||
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
|
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
|
||||||
#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
|
#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
|
||||||
#include "llvm/ADT/StringSwitch.h"
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
@@ -15,8 +15,8 @@
|
|||||||
#include "ExprEngineInternalChecks.h"
|
#include "ExprEngineInternalChecks.h"
|
||||||
#include "clang/AST/ParentMap.h"
|
#include "clang/AST/ParentMap.h"
|
||||||
#include "clang/Basic/TargetInfo.h"
|
#include "clang/Basic/TargetInfo.h"
|
||||||
#include "clang/EntoSA/BugReporter/BugType.h"
|
#include "clang/StaticAnalyzer/BugReporter/BugType.h"
|
||||||
#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
|
#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using namespace ento;
|
using namespace ento;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user