forked from OSchip/llvm-project
Major rewrite/refactoring of static analysis engine. We now use
EvalStore/EvalLoad to handle all loads/stores from symbolic memory, allowing us to do checks for null dereferences, etc., at any arbitrary load/store (these were missed checks before). This also resulted in some major cleanups, some conceptual, and others just in the structure of the code. This temporarily introduces a regression in the test suite (null-deref-ps.c) before I add a new LVal type for structure fields. llvm-svn: 50443
This commit is contained in:
parent
f07de734cf
commit
fa5a3d0fe7
|
@ -151,12 +151,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State,
|
ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State,
|
||||||
ExplodedNodeImpl* Pred);
|
ExplodedNodeImpl* Pred,
|
||||||
|
bool isLoad = false);
|
||||||
|
|
||||||
inline ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State) {
|
inline ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State,
|
||||||
|
bool isLoad = false) {
|
||||||
ExplodedNodeImpl* N = getLastNode();
|
ExplodedNodeImpl* N = getLastNode();
|
||||||
assert (N && "Predecessor of new node is infeasible.");
|
assert (N && "Predecessor of new node is infeasible.");
|
||||||
return generateNodeImpl(S, State, N);
|
return generateNodeImpl(S, State, N, isLoad);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt* getStmt() const { return B[Idx]; }
|
Stmt* getStmt() const { return B[Idx]; }
|
||||||
|
@ -201,14 +203,14 @@ public:
|
||||||
return static_cast<NodeTy*>(NB.getLastNode());
|
return static_cast<NodeTy*>(NB.getLastNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeTy* generateNode(Stmt* S, StateTy* St, NodeTy* Pred) {
|
NodeTy* generateNode(Stmt* S, StateTy* St, NodeTy* Pred, bool isLoad = false){
|
||||||
HasGeneratedNode = true;
|
HasGeneratedNode = true;
|
||||||
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred));
|
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, isLoad));
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeTy* generateNode(Stmt* S, StateTy* St) {
|
NodeTy* generateNode(Stmt* S, StateTy* St, bool isLoad = false) {
|
||||||
HasGeneratedNode = true;
|
HasGeneratedNode = true;
|
||||||
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St));
|
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, isLoad));
|
||||||
}
|
}
|
||||||
|
|
||||||
GRBlockCounter getBlockCounter() const {
|
GRBlockCounter getBlockCounter() const {
|
||||||
|
|
|
@ -425,10 +425,6 @@ protected:
|
||||||
return StateMgr.GetRVal(St, LV, T);
|
return StateMgr.GetRVal(St, LV, T);
|
||||||
}
|
}
|
||||||
|
|
||||||
RVal GetLVal(ValueState* St, Expr* Ex) {
|
|
||||||
return StateMgr.GetLVal(St, Ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline NonLVal MakeConstantVal(uint64_t X, Expr* Ex) {
|
inline NonLVal MakeConstantVal(uint64_t X, Expr* Ex) {
|
||||||
return NonLVal::MakeVal(BasicVals, X, Ex->getType());
|
return NonLVal::MakeVal(BasicVals, X, Ex->getType());
|
||||||
}
|
}
|
||||||
|
@ -475,10 +471,6 @@ protected:
|
||||||
return Builder->MakeNode(Dst, S, Pred, St);
|
return Builder->MakeNode(Dst, S, Pred, St);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// HandleUndefinedStore - Create the necessary sink node to represent
|
|
||||||
/// a store to an "undefined" LVal.
|
|
||||||
void HandleUndefinedStore(Stmt* S, NodeTy* Pred);
|
|
||||||
|
|
||||||
/// Visit - Transfer function logic for all statements. Dispatches to
|
/// Visit - Transfer function logic for all statements. Dispatches to
|
||||||
/// other functions that handle specific kinds of statements.
|
/// other functions that handle specific kinds of statements.
|
||||||
void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst);
|
void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst);
|
||||||
|
@ -520,7 +512,8 @@ protected:
|
||||||
void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst);
|
void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst);
|
||||||
|
|
||||||
/// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
|
/// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
|
||||||
void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst);
|
void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
|
||||||
|
bool asLval);
|
||||||
|
|
||||||
/// VisitDeclStmt - Transfer function logic for DeclStmts.
|
/// VisitDeclStmt - Transfer function logic for DeclStmts.
|
||||||
void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst);
|
void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst);
|
||||||
|
@ -528,12 +521,6 @@ protected:
|
||||||
void VisitDeclStmtAux(DeclStmt* DS, ScopedDecl* D,
|
void VisitDeclStmtAux(DeclStmt* DS, ScopedDecl* D,
|
||||||
NodeTy* Pred, NodeSet& Dst);
|
NodeTy* Pred, NodeSet& Dst);
|
||||||
|
|
||||||
void VisitDeref(UnaryOperator* U, NodeTy* Pred, NodeSet& Dst,
|
|
||||||
bool GetLVal = false);
|
|
||||||
|
|
||||||
void VisitDeref(Expr* Ex, RVal V, ValueState* St, NodeTy* Pred, NodeSet& Dst,
|
|
||||||
bool GetLVal);
|
|
||||||
|
|
||||||
/// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
|
/// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
|
||||||
void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst);
|
void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst);
|
||||||
|
|
||||||
|
@ -543,10 +530,6 @@ protected:
|
||||||
/// VisitMemberExpr - Transfer function for member expressions.
|
/// VisitMemberExpr - Transfer function for member expressions.
|
||||||
void VisitMemberExpr(MemberExpr* M, NodeTy* Pred, NodeSet& Dst, bool asLVal);
|
void VisitMemberExpr(MemberExpr* M, NodeTy* Pred, NodeSet& Dst, bool asLVal);
|
||||||
|
|
||||||
void VisitMemberExprField(MemberExpr* M, Expr* Base, NodeTy* Pred,
|
|
||||||
NodeSet& Dst, bool asLVal);
|
|
||||||
|
|
||||||
|
|
||||||
/// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
|
/// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
|
||||||
void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst);
|
void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst);
|
||||||
|
|
||||||
|
@ -565,14 +548,11 @@ protected:
|
||||||
void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex, NodeTy* Pred,
|
void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex, NodeTy* Pred,
|
||||||
NodeSet& Dst);
|
NodeSet& Dst);
|
||||||
|
|
||||||
// VisitSizeOfExpr - Transfer function for sizeof(expr).
|
|
||||||
void VisitSizeOfExpr(UnaryOperator* U, NodeTy* Pred, NodeSet& Dst);
|
|
||||||
|
|
||||||
/// VisitUnaryOperator - Transfer function logic for unary operators.
|
/// VisitUnaryOperator - Transfer function logic for unary operators.
|
||||||
void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst);
|
void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst,
|
||||||
|
bool asLVal);
|
||||||
|
|
||||||
|
|
||||||
|
bool CheckDivideZero(Expr* Ex, ValueState* St, NodeTy* Pred, RVal Denom);
|
||||||
|
|
||||||
RVal EvalCast(RVal X, QualType CastT) {
|
RVal EvalCast(RVal X, QualType CastT) {
|
||||||
if (X.isUnknownOrUndef())
|
if (X.isUnknownOrUndef())
|
||||||
|
@ -584,8 +564,6 @@ protected:
|
||||||
return TF->EvalCast(*this, cast<NonLVal>(X), CastT);
|
return TF->EvalCast(*this, cast<NonLVal>(X), CastT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
RVal EvalMinus(UnaryOperator* U, RVal X) {
|
RVal EvalMinus(UnaryOperator* U, RVal X) {
|
||||||
return X.isValid() ? TF->EvalMinus(*this, U, cast<NonLVal>(X)) : X;
|
return X.isValid() ? TF->EvalMinus(*this, U, cast<NonLVal>(X)) : X;
|
||||||
}
|
}
|
||||||
|
@ -643,6 +621,15 @@ protected:
|
||||||
void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, ValueState* St,
|
void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, ValueState* St,
|
||||||
RVal TargetLV, RVal Val);
|
RVal TargetLV, RVal Val);
|
||||||
|
|
||||||
|
// FIXME: The "CheckOnly" option exists only because Array and Field
|
||||||
|
// loads aren't fully implemented. Eventually this option will go away.
|
||||||
|
|
||||||
|
void EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
|
||||||
|
ValueState* St, RVal location, bool CheckOnly = false);
|
||||||
|
|
||||||
|
ValueState* EvalLocation(Expr* Ex, NodeTy* Pred,
|
||||||
|
ValueState* St, RVal location, bool isLoad = false);
|
||||||
|
|
||||||
void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred);
|
void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred);
|
||||||
|
|
||||||
ValueState* MarkBranch(ValueState* St, Stmt* Terminator, bool branchTaken);
|
ValueState* MarkBranch(ValueState* St, Stmt* Terminator, bool branchTaken);
|
||||||
|
|
|
@ -242,7 +242,6 @@ public:
|
||||||
|
|
||||||
RVal GetRVal(ValueState* St, Expr* E);
|
RVal GetRVal(ValueState* St, Expr* E);
|
||||||
RVal GetRVal(ValueState* St, LVal LV, QualType T = QualType());
|
RVal GetRVal(ValueState* St, LVal LV, QualType T = QualType());
|
||||||
RVal GetLVal(ValueState* St, Expr* E);
|
|
||||||
|
|
||||||
RVal GetBlkExprRVal(ValueState* St, Expr* Ex);
|
RVal GetBlkExprRVal(ValueState* St, Expr* Ex);
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,9 @@ namespace clang {
|
||||||
|
|
||||||
class ProgramPoint {
|
class ProgramPoint {
|
||||||
public:
|
public:
|
||||||
enum Kind { BlockEntranceKind=0, PostStmtKind=1, BlockExitKind=2,
|
enum Kind { BlockEntranceKind=0, PostStmtKind=1, PostLoadKind=2,
|
||||||
BlockEdgeSrcKind=3, BlockEdgeDstKind=4, BlockEdgeAuxKind=5 };
|
BlockExitKind=3, BlockEdgeSrcKind=4, BlockEdgeDstKind=5,
|
||||||
|
BlockEdgeAuxKind=6 };
|
||||||
protected:
|
protected:
|
||||||
uintptr_t Data;
|
uintptr_t Data;
|
||||||
|
|
||||||
|
@ -100,13 +101,25 @@ public:
|
||||||
|
|
||||||
|
|
||||||
class PostStmt : public ProgramPoint {
|
class PostStmt : public ProgramPoint {
|
||||||
|
protected:
|
||||||
|
PostStmt(const Stmt* S, Kind k) : ProgramPoint(S, k) {}
|
||||||
public:
|
public:
|
||||||
PostStmt(const Stmt* S) : ProgramPoint(S, PostStmtKind) {}
|
PostStmt(const Stmt* S) : ProgramPoint(S, PostStmtKind) {}
|
||||||
|
|
||||||
Stmt* getStmt() const { return (Stmt*) getRawPtr(); }
|
Stmt* getStmt() const { return (Stmt*) getRawPtr(); }
|
||||||
|
|
||||||
static bool classof(const ProgramPoint* Location) {
|
static bool classof(const ProgramPoint* Location) {
|
||||||
return Location->getKind() == PostStmtKind;
|
unsigned k = Location->getKind();
|
||||||
|
return k == PostStmtKind || k == PostLoadKind;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PostLoad : public PostStmt {
|
||||||
|
public:
|
||||||
|
PostLoad(const Stmt* S) : PostStmt(S, PostLoadKind) {}
|
||||||
|
|
||||||
|
static bool classof(const ProgramPoint* Location) {
|
||||||
|
return Location->getKind() == PostLoadKind;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,7 @@ bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) {
|
||||||
assert (false && "BlockExit location never occur in forward analysis.");
|
assert (false && "BlockExit location never occur in forward analysis.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ProgramPoint::PostLoadKind:
|
||||||
case ProgramPoint::PostStmtKind:
|
case ProgramPoint::PostStmtKind:
|
||||||
HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(),
|
HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(),
|
||||||
WU.getIndex(), Node);
|
WU.getIndex(), Node);
|
||||||
|
@ -316,11 +317,13 @@ void GRStmtNodeBuilderImpl::GenerateAutoTransition(ExplodedNodeImpl* N) {
|
||||||
Eng.WList->Enqueue(Succ, B, Idx+1);
|
Eng.WList->Enqueue(Succ, B, Idx+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExplodedNodeImpl* GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, void* State,
|
ExplodedNodeImpl*
|
||||||
ExplodedNodeImpl* Pred) {
|
GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, void* State,
|
||||||
|
ExplodedNodeImpl* Pred, bool isLoad) {
|
||||||
|
|
||||||
bool IsNew;
|
bool IsNew;
|
||||||
ExplodedNodeImpl* N = Eng.G->getNodeImpl(PostStmt(S), State, &IsNew);
|
ProgramPoint Loc = isLoad ? PostLoad(S) : PostStmt(S);
|
||||||
|
ExplodedNodeImpl* N = Eng.G->getNodeImpl(Loc, State, &IsNew);
|
||||||
N->addPredecessor(Pred);
|
N->addPredecessor(Pred);
|
||||||
Deferred.erase(Pred);
|
Deferred.erase(Pred);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -271,22 +271,6 @@ RVal ValueStateManager::GetRVal(ValueState* St, Expr* E) {
|
||||||
E = cast<ParenExpr>(E)->getSubExpr();
|
E = cast<ParenExpr>(E)->getSubExpr();
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// DeclRefExprs can either evaluate to an LVal or a Non-LVal
|
|
||||||
// (assuming an implicit "load") depending on the context. In this
|
|
||||||
// context we assume that we are retrieving the value contained
|
|
||||||
// within the referenced variables.
|
|
||||||
|
|
||||||
case Stmt::DeclRefExprClass: {
|
|
||||||
|
|
||||||
// Check if this expression is a block-level expression. If so,
|
|
||||||
// return its value.
|
|
||||||
ValueState::ExprBindingsTy::TreeTy* T=St->BlockExprBindings.SlimFind(E);
|
|
||||||
if (T) return T->getValue().second;
|
|
||||||
|
|
||||||
RVal X = RVal::MakeVal(BasicVals, cast<DeclRefExpr>(E));
|
|
||||||
return isa<lval::DeclVal>(X) ? GetRVal(St, cast<lval::DeclVal>(X)) : X;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Stmt::CharacterLiteralClass: {
|
case Stmt::CharacterLiteralClass: {
|
||||||
CharacterLiteral* C = cast<CharacterLiteral>(E);
|
CharacterLiteral* C = cast<CharacterLiteral>(E);
|
||||||
return NonLVal::MakeVal(BasicVals, C->getValue(), C->getType());
|
return NonLVal::MakeVal(BasicVals, C->getValue(), C->getType());
|
||||||
|
@ -326,18 +310,6 @@ RVal ValueStateManager::GetRVal(ValueState* St, Expr* E) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Stmt::UnaryOperatorClass: {
|
|
||||||
|
|
||||||
UnaryOperator* U = cast<UnaryOperator>(E);
|
|
||||||
|
|
||||||
if (U->getOpcode() == UnaryOperator::Plus) {
|
|
||||||
E = U->getSubExpr();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle all other Expr* using a lookup.
|
// Handle all other Expr* using a lookup.
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -377,34 +349,6 @@ RVal ValueStateManager::GetBlkExprRVal(ValueState* St, Expr* E) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RVal ValueStateManager::GetLVal(ValueState* St, Expr* E) {
|
|
||||||
|
|
||||||
E = E->IgnoreParens();
|
|
||||||
|
|
||||||
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E)) {
|
|
||||||
ValueDecl* VD = DR->getDecl();
|
|
||||||
|
|
||||||
if (FunctionDecl* FD = dyn_cast<FunctionDecl>(VD))
|
|
||||||
return lval::FuncVal(FD);
|
|
||||||
else
|
|
||||||
return lval::DeclVal(cast<VarDecl>(DR->getDecl()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UnaryOperator* U = dyn_cast<UnaryOperator>(E))
|
|
||||||
if (U->getOpcode() == UnaryOperator::Deref) {
|
|
||||||
E = U->getSubExpr()->IgnoreParens();
|
|
||||||
|
|
||||||
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E)) {
|
|
||||||
lval::DeclVal X(cast<VarDecl>(DR->getDecl()));
|
|
||||||
return GetRVal(St, X);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return GetRVal(St, E);
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetRVal(St, E);
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueState*
|
ValueState*
|
||||||
ValueStateManager::SetRVal(ValueState* St, Expr* E, RVal V,
|
ValueStateManager::SetRVal(ValueState* St, Expr* E, RVal V,
|
||||||
bool isBlkExpr, bool Invalidate) {
|
bool isBlkExpr, bool Invalidate) {
|
||||||
|
|
Loading…
Reference in New Issue