mirror of
https://github.com/opnsense/src.git
synced 2026-02-24 18:30:55 -05:00
281 lines
9.2 KiB
C++
281 lines
9.2 KiB
C++
//== 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_ANALYSIS_CHECKER
|
|
#define LLVM_CLANG_ANALYSIS_CHECKER
|
|
#include "clang/Analysis/Support/SaveAndRestore.h"
|
|
#include "clang/Checker/PathSensitive/GRCoreEngine.h"
|
|
#include "clang/Checker/PathSensitive/GRState.h"
|
|
#include "clang/Checker/PathSensitive/GRExprEngine.h"
|
|
#include "clang/AST/ExprCXX.h"
|
|
#include "clang/AST/ExprObjC.h"
|
|
#include "clang/AST/StmtCXX.h"
|
|
#include "clang/AST/StmtObjC.h"
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Checker interface.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace clang {
|
|
class GRExprEngine;
|
|
|
|
class CheckerContext {
|
|
ExplodedNodeSet &Dst;
|
|
GRStmtNodeBuilder &B;
|
|
GRExprEngine &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;
|
|
bool DoneEvaluating; // FIXME: This is not a permanent API change.
|
|
public:
|
|
CheckerContext(ExplodedNodeSet &dst, GRStmtNodeBuilder &builder,
|
|
GRExprEngine &eng, ExplodedNode *pred,
|
|
const void *tag, ProgramPoint::Kind K,
|
|
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()) {}
|
|
|
|
~CheckerContext();
|
|
|
|
GRExprEngine &getEngine() {
|
|
return Eng;
|
|
}
|
|
|
|
AnalysisManager &getAnalysisManager() {
|
|
return Eng.getAnalysisManager();
|
|
}
|
|
|
|
ConstraintManager &getConstraintManager() {
|
|
return Eng.getConstraintManager();
|
|
}
|
|
|
|
StoreManager &getStoreManager() {
|
|
return Eng.getStoreManager();
|
|
}
|
|
|
|
ExplodedNodeSet &getNodeSet() { return Dst; }
|
|
GRStmtNodeBuilder &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();
|
|
}
|
|
|
|
ValueManager &getValueManager() {
|
|
return Eng.getValueManager();
|
|
}
|
|
|
|
SValuator &getSValuator() {
|
|
return Eng.getSValuator();
|
|
}
|
|
|
|
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 (state != getState() || (ST && ST != B.GetState(Pred)))
|
|
GenerateNode(state, true);
|
|
else
|
|
Dst.Add(Pred);
|
|
}
|
|
|
|
void EmitReport(BugReport *R) {
|
|
Eng.getBugReporter().EmitReport(R);
|
|
}
|
|
|
|
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 GRExprEngine;
|
|
|
|
// FIXME: Remove the 'tag' option.
|
|
void GR_Visit(ExplodedNodeSet &Dst,
|
|
GRStmtNodeBuilder &Builder,
|
|
GRExprEngine &Eng,
|
|
const Stmt *S,
|
|
ExplodedNode *Pred, void *tag, bool isPrevisit) {
|
|
CheckerContext C(Dst, Builder, Eng, Pred, tag,
|
|
isPrevisit ? ProgramPoint::PreStmtKind :
|
|
ProgramPoint::PostStmtKind, S);
|
|
if (isPrevisit)
|
|
_PreVisit(C, S);
|
|
else
|
|
_PostVisit(C, S);
|
|
}
|
|
|
|
bool GR_EvalNilReceiver(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder,
|
|
GRExprEngine &Eng, const ObjCMessageExpr *ME,
|
|
ExplodedNode *Pred, const GRState *state, void *tag) {
|
|
CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
|
|
ME, state);
|
|
return EvalNilReceiver(C, ME);
|
|
}
|
|
|
|
bool GR_EvalCallExpr(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder,
|
|
GRExprEngine &Eng, const CallExpr *CE,
|
|
ExplodedNode *Pred, void *tag) {
|
|
CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
|
|
CE);
|
|
return EvalCallExpr(C, CE);
|
|
}
|
|
|
|
// FIXME: Remove the 'tag' option.
|
|
void GR_VisitBind(ExplodedNodeSet &Dst,
|
|
GRStmtNodeBuilder &Builder, GRExprEngine &Eng,
|
|
const Stmt *AssignE,
|
|
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, StoreE);
|
|
assert(isPrevisit && "Only previsit supported for now.");
|
|
PreVisitBind(C, AssignE, StoreE, location, val);
|
|
}
|
|
|
|
// FIXME: Remove the 'tag' option.
|
|
void GR_VisitLocation(ExplodedNodeSet &Dst,
|
|
GRStmtNodeBuilder &Builder,
|
|
GRExprEngine &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, S, state);
|
|
VisitLocation(C, S, location);
|
|
}
|
|
|
|
void GR_EvalDeadSymbols(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder,
|
|
GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred,
|
|
SymbolReaper &SymReaper, void *tag) {
|
|
CheckerContext C(Dst, Builder, Eng, Pred, tag,
|
|
ProgramPoint::PostPurgeDeadSymbolsKind, S);
|
|
EvalDeadSymbols(C, S, 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 *AssignE,
|
|
const Stmt *StoreE, SVal location, SVal val) {}
|
|
virtual void EvalDeadSymbols(CheckerContext &C, const Stmt *S,
|
|
SymbolReaper &SymReaper) {}
|
|
virtual void EvalEndPath(GREndPathNodeBuilder &B, void *tag,
|
|
GRExprEngine &Eng) {}
|
|
|
|
virtual void VisitBranchCondition(GRBranchNodeBuilder &Builder,
|
|
GRExprEngine &Eng,
|
|
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) {
|
|
return state;
|
|
}
|
|
};
|
|
} // end clang namespace
|
|
|
|
#endif
|
|
|