Fixed: <rdar://problem/5881148>

Problem:

In the recently refactored VisitDeref (which processes dereferences), we
were incorrectly skipping the node just generated for the subexpression
of the dereference.  This was a horrible regression.

llvm-svn: 50176
This commit is contained in:
Ted Kremenek 2008-04-23 20:12:28 +00:00
parent 6e9185093d
commit dd43aeee54
6 changed files with 61 additions and 87 deletions

View File

@ -626,7 +626,7 @@ protected:
return TF->EvalBinOp(*this, Op, cast<NonLVal>(L), cast<NonLVal>(R));
}
void EvalCall(NodeSet& Dst, CallExpr* CE, LVal L, NodeTy* Pred) {
void EvalCall(NodeSet& Dst, CallExpr* CE, RVal L, NodeTy* Pred) {
assert (Builder && "GRStmtNodeBuilder must be defined.");
TF->EvalCall(Dst, *this, *Builder, CE, L, Pred);
}

View File

@ -63,7 +63,7 @@ public:
virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
GRExprEngine& Engine,
GRStmtNodeBuilder<ValueState>& Builder,
CallExpr* CE, LVal L,
CallExpr* CE, RVal L,
ExplodedNode<ValueState>* Pred) {}
virtual void EvalObjCMessageExpr(ExplodedNodeSet<ValueState>& Dst,

View File

@ -659,7 +659,7 @@ public:
virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
GRExprEngine& Eng,
GRStmtNodeBuilder<ValueState>& Builder,
CallExpr* CE, LVal L,
CallExpr* CE, RVal L,
ExplodedNode<ValueState>* Pred);
virtual void EvalObjCMessageExpr(ExplodedNodeSet<ValueState>& Dst,
@ -769,7 +769,7 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet<ValueState>& Dst,
void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
GRExprEngine& Eng,
GRStmtNodeBuilder<ValueState>& Builder,
CallExpr* CE, LVal L,
CallExpr* CE, RVal L,
ExplodedNode<ValueState>* Pred) {
ValueStateManager& StateMgr = Eng.getStateManager();

View File

@ -78,6 +78,18 @@ struct VISIBILITY_HIDDEN SaveAndRestore {
T old_value;
};
// SaveOr - Similar to SaveAndRestore. Operates only on bools; the old
// value of a variable is saved, and during the dstor the old value is
// or'ed with the new value.
struct VISIBILITY_HIDDEN SaveOr {
SaveOr(bool& x) : X(x), old_value(x) { x = false; }
~SaveOr() { X |= old_value; }
bool& X;
bool old_value;
};
void GRExprEngine::EmitWarnings(Diagnostic& Diag, PathDiagnosticClient* PD) {
for (bug_type_iterator I = bug_types_begin(), E = bug_types_end(); I!=E; ++I){
BugReporter BR(Diag, PD, getContext(), *this);
@ -784,11 +796,9 @@ void GRExprEngine::EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred,
unsigned size = Dst.size();
SaveAndRestore<bool> OldSink(Builder->BuildSinks),
OldHasGen(Builder->HasGeneratedNode);
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
Builder->HasGeneratedNode = false;
assert (!TargetLV.isUndef());
TF->EvalStore(Dst, *this, *Builder, E, Pred, St, TargetLV, Val);
@ -828,13 +838,10 @@ void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred,
// the callee expression.
NodeSet DstTmp;
Expr* Callee = CE->getCallee()->IgnoreParenCasts();
Expr* Callee = CE->getCallee()->IgnoreParens();
VisitLVal(Callee, Pred, DstTmp);
if (DstTmp.empty())
DstTmp.Add(Pred);
// Finally, evaluate the function call.
for (NodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI!=DE; ++DI) {
@ -903,19 +910,12 @@ void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred,
}
// Evaluate the call.
bool invalidateArgs = false;
if (L.isUnknown()) {
// Check for an "unknown" callee.
invalidateArgs = true;
}
else if (isa<lval::FuncVal>(L)) {
if (isa<lval::FuncVal>(L)) {
IdentifierInfo* Info = cast<lval::FuncVal>(L).getDecl()->getIdentifier();
if (unsigned id = Info->getBuiltinID()) {
if (unsigned id = Info->getBuiltinID())
switch (id) {
case Builtin::BI__builtin_expect: {
// For __builtin_expect, just return the value of the subexpression.
@ -926,67 +926,45 @@ void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred,
}
default:
invalidateArgs = true;
break;
}
}
}
if (invalidateArgs) {
// Invalidate all arguments passed in by reference (LVals).
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
I != E; ++I) {
RVal V = GetRVal(St, *I);
if (isa<LVal>(V))
St = SetRVal(St, cast<LVal>(V), UnknownVal());
}
// Check any arguments passed-by-value against being undefined.
bool badArg = false;
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
I != E; ++I) {
if (GetRVal(GetState(*DI), *I).isUndef()) {
NodeTy* N = Builder->generateNode(CE, GetState(*DI), *DI);
MakeNode(Dst, CE, *DI, St);
}
else {
// Check any arguments passed-by-value against being undefined.
bool badArg = false;
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
I != E; ++I) {
if (GetRVal(GetState(*DI), *I).isUndef()) {
NodeTy* N = Builder->generateNode(CE, GetState(*DI), *DI);
if (N) {
N->markAsSink();
UndefArgs[N] = *I;
}
badArg = true;
break;
if (N) {
N->markAsSink();
UndefArgs[N] = *I;
}
}
if (badArg)
continue;
// Dispatch to the plug-in transfer function.
unsigned size = Dst.size();
SaveAndRestore<bool> OldSink(Builder->BuildSinks),
OldHasGen(Builder->HasGeneratedNode);
Builder->HasGeneratedNode = false;
EvalCall(Dst, CE, cast<LVal>(L), *DI);
// Handle the case where no nodes where generated. Auto-generate that
// contains the updated state if we aren't generating sinks.
if (!Builder->BuildSinks && Dst.size() == size &&
!Builder->HasGeneratedNode)
MakeNode(Dst, CE, *DI, St);
badArg = true;
break;
}
}
if (badArg)
continue;
// Dispatch to the plug-in transfer function.
unsigned size = Dst.size();
SaveOr OldHasGen(Builder->HasGeneratedNode);
EvalCall(Dst, CE, L, *DI);
// Handle the case where no nodes where generated. Auto-generate that
// contains the updated state if we aren't generating sinks.
if (!Builder->BuildSinks && Dst.size() == size &&
!Builder->HasGeneratedNode)
MakeNode(Dst, CE, *DI, St);
}
}
@ -1081,10 +1059,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
unsigned size = Dst.size();
SaveAndRestore<bool> OldSink(Builder->BuildSinks),
OldHasGen(Builder->HasGeneratedNode);
Builder->HasGeneratedNode = false;
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
EvalObjCMessageExpr(Dst, ME, Pred);
@ -1312,9 +1288,9 @@ void GRExprEngine::VisitDeref(UnaryOperator* U, NodeTy* Pred,
Visit(Ex, Pred, DstTmp);
for (NodeSet::iterator I = DstTmp.begin(), DE = DstTmp.end(); I != DE; ++I) {
ValueState* St = GetState(Pred);
ValueState* St = GetState(*I);
RVal V = GetRVal(St, Ex);
VisitDeref(U, V, St, Pred, Dst, GetLVal);
VisitDeref(U, V, St, *I, Dst, GetLVal);
}
}
@ -1641,10 +1617,8 @@ void GRExprEngine::EvalReturn(NodeSet& Dst, ReturnStmt* S, NodeTy* Pred) {
unsigned size = Dst.size();
SaveAndRestore<bool> OldSink(Builder->BuildSinks),
OldHasGen(Builder->HasGeneratedNode);
Builder->HasGeneratedNode = false;
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
TF->EvalReturn(Dst, *this, *Builder, S, Pred);

View File

@ -557,7 +557,7 @@ RVal GRSimpleVals::EvalNE(GRExprEngine& Eng, LVal L, LVal R) {
void GRSimpleVals::EvalCall(ExplodedNodeSet<ValueState>& Dst,
GRExprEngine& Eng,
GRStmtNodeBuilder<ValueState>& Builder,
CallExpr* CE, LVal L,
CallExpr* CE, RVal L,
ExplodedNode<ValueState>* Pred) {
ValueStateManager& StateMgr = Eng.getStateManager();

View File

@ -60,7 +60,7 @@ public:
virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
GRExprEngine& Engine,
GRStmtNodeBuilder<ValueState>& Builder,
CallExpr* CE, LVal L,
CallExpr* CE, RVal L,
ExplodedNode<ValueState>* Pred);
virtual void EvalObjCMessageExpr(ExplodedNodeSet<ValueState>& Dst,