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* 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();
|
||||
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]; }
|
||||
|
@ -201,14 +203,14 @@ public:
|
|||
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;
|
||||
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;
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St));
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, isLoad));
|
||||
}
|
||||
|
||||
GRBlockCounter getBlockCounter() const {
|
||||
|
|
|
@ -425,10 +425,6 @@ protected:
|
|||
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) {
|
||||
return NonLVal::MakeVal(BasicVals, X, Ex->getType());
|
||||
}
|
||||
|
@ -474,11 +470,7 @@ protected:
|
|||
assert (Builder && "GRStmtNodeBuilder not present.");
|
||||
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
|
||||
/// other functions that handle specific kinds of statements.
|
||||
void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst);
|
||||
|
@ -520,7 +512,8 @@ protected:
|
|||
void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// 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.
|
||||
void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst);
|
||||
|
@ -528,12 +521,6 @@ protected:
|
|||
void VisitDeclStmtAux(DeclStmt* DS, ScopedDecl* D,
|
||||
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
|
||||
void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
|
@ -543,10 +530,6 @@ protected:
|
|||
/// VisitMemberExpr - Transfer function for member expressions.
|
||||
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.
|
||||
void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
|
@ -564,15 +547,12 @@ protected:
|
|||
/// VisitSizeOfAlignOfTypeExpr - Transfer function for sizeof(type).
|
||||
void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex, NodeTy* Pred,
|
||||
NodeSet& Dst);
|
||||
|
||||
// VisitSizeOfExpr - Transfer function for sizeof(expr).
|
||||
void VisitSizeOfExpr(UnaryOperator* U, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
|
||||
/// 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) {
|
||||
if (X.isUnknownOrUndef())
|
||||
|
@ -584,8 +564,6 @@ protected:
|
|||
return TF->EvalCast(*this, cast<NonLVal>(X), CastT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
RVal EvalMinus(UnaryOperator* U, RVal X) {
|
||||
return X.isValid() ? TF->EvalMinus(*this, U, cast<NonLVal>(X)) : X;
|
||||
}
|
||||
|
@ -603,27 +581,27 @@ protected:
|
|||
}
|
||||
|
||||
RVal EvalBinOp(BinaryOperator::Opcode Op, RVal L, RVal R) {
|
||||
|
||||
|
||||
if (L.isUndef() || R.isUndef())
|
||||
return UndefinedVal();
|
||||
|
||||
|
||||
if (L.isUnknown() || R.isUnknown())
|
||||
return UnknownVal();
|
||||
|
||||
|
||||
if (isa<LVal>(L)) {
|
||||
if (isa<LVal>(R))
|
||||
return TF->EvalBinOp(*this, Op, cast<LVal>(L), cast<LVal>(R));
|
||||
else
|
||||
return TF->EvalBinOp(*this, Op, cast<LVal>(L), cast<NonLVal>(R));
|
||||
}
|
||||
|
||||
|
||||
if (isa<LVal>(R)) {
|
||||
// Support pointer arithmetic where the increment/decrement operand
|
||||
// is on the left and the pointer on the right.
|
||||
|
||||
|
||||
assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub);
|
||||
|
||||
// Commute the operands.
|
||||
// Commute the operands.
|
||||
return TF->EvalBinOp(*this, Op, cast<LVal>(R), cast<NonLVal>(L));
|
||||
}
|
||||
else
|
||||
|
@ -631,11 +609,11 @@ protected:
|
|||
}
|
||||
|
||||
void EvalCall(NodeSet& Dst, CallExpr* CE, RVal L, NodeTy* Pred) {
|
||||
assert (Builder && "GRStmtNodeBuilder must be defined.");
|
||||
assert (Builder && "GRStmtNodeBuilder must be defined.");
|
||||
TF->EvalCall(Dst, *this, *Builder, CE, L, Pred);
|
||||
}
|
||||
|
||||
void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) {
|
||||
void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) {
|
||||
assert (Builder && "GRStmtNodeBuilder must be defined.");
|
||||
TF->EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred);
|
||||
}
|
||||
|
@ -643,7 +621,16 @@ protected:
|
|||
void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, ValueState* St,
|
||||
RVal TargetLV, RVal Val);
|
||||
|
||||
void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred);
|
||||
// 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);
|
||||
|
||||
ValueState* MarkBranch(ValueState* St, Stmt* Terminator, bool branchTaken);
|
||||
};
|
||||
|
|
|
@ -242,7 +242,6 @@ public:
|
|||
|
||||
RVal GetRVal(ValueState* St, Expr* E);
|
||||
RVal GetRVal(ValueState* St, LVal LV, QualType T = QualType());
|
||||
RVal GetLVal(ValueState* St, Expr* E);
|
||||
|
||||
RVal GetBlkExprRVal(ValueState* St, Expr* Ex);
|
||||
|
||||
|
|
|
@ -25,8 +25,9 @@ namespace clang {
|
|||
|
||||
class ProgramPoint {
|
||||
public:
|
||||
enum Kind { BlockEntranceKind=0, PostStmtKind=1, BlockExitKind=2,
|
||||
BlockEdgeSrcKind=3, BlockEdgeDstKind=4, BlockEdgeAuxKind=5 };
|
||||
enum Kind { BlockEntranceKind=0, PostStmtKind=1, PostLoadKind=2,
|
||||
BlockExitKind=3, BlockEdgeSrcKind=4, BlockEdgeDstKind=5,
|
||||
BlockEdgeAuxKind=6 };
|
||||
protected:
|
||||
uintptr_t Data;
|
||||
|
||||
|
@ -100,13 +101,25 @@ public:
|
|||
|
||||
|
||||
class PostStmt : public ProgramPoint {
|
||||
protected:
|
||||
PostStmt(const Stmt* S, Kind k) : ProgramPoint(S, k) {}
|
||||
public:
|
||||
PostStmt(const Stmt* S) : ProgramPoint(S, PostStmtKind) {}
|
||||
|
||||
|
||||
Stmt* getStmt() const { return (Stmt*) getRawPtr(); }
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -102,7 +102,8 @@ bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) {
|
|||
case ProgramPoint::BlockExitKind:
|
||||
assert (false && "BlockExit location never occur in forward analysis.");
|
||||
break;
|
||||
|
||||
|
||||
case ProgramPoint::PostLoadKind:
|
||||
case ProgramPoint::PostStmtKind:
|
||||
HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(),
|
||||
WU.getIndex(), Node);
|
||||
|
@ -316,11 +317,13 @@ void GRStmtNodeBuilderImpl::GenerateAutoTransition(ExplodedNodeImpl* N) {
|
|||
Eng.WList->Enqueue(Succ, B, Idx+1);
|
||||
}
|
||||
|
||||
ExplodedNodeImpl* GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, void* State,
|
||||
ExplodedNodeImpl* Pred) {
|
||||
ExplodedNodeImpl*
|
||||
GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, void* State,
|
||||
ExplodedNodeImpl* Pred, bool isLoad) {
|
||||
|
||||
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);
|
||||
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();
|
||||
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: {
|
||||
CharacterLiteral* C = cast<CharacterLiteral>(E);
|
||||
return NonLVal::MakeVal(BasicVals, C->getValue(), C->getType());
|
||||
|
@ -326,18 +310,6 @@ RVal ValueStateManager::GetRVal(ValueState* St, Expr* E) {
|
|||
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.
|
||||
|
||||
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*
|
||||
ValueStateManager::SetRVal(ValueState* St, Expr* E, RVal V,
|
||||
bool isBlkExpr, bool Invalidate) {
|
||||
|
|
Loading…
Reference in New Issue