diff options
20 files changed, 113 insertions, 70 deletions
diff --git a/clang/include/clang/Analysis/PathSensitive/Checker.h b/clang/include/clang/Analysis/PathSensitive/Checker.h index 1fb92a61dea..e94096ba4f2 100644 --- a/clang/include/clang/Analysis/PathSensitive/Checker.h +++ b/clang/include/clang/Analysis/PathSensitive/Checker.h @@ -40,24 +40,22 @@ class CheckerContext { SaveAndRestore<ProgramPoint::Kind> OldPointKind; SaveOr OldHasGen; const GRState *state; - + const Stmt *statement; + const unsigned size; public: CheckerContext(ExplodedNodeSet &dst, GRStmtNodeBuilder &builder, GRExprEngine &eng, ExplodedNode *pred, const void *tag, ProgramPoint::Kind K, - const GRState *st = 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), - state(st) {} - - ~CheckerContext() { - if (!B.BuildSinks && !B.HasGeneratedNode) - Dst.Add(Pred); - } + state(st), statement(stmt), size(Dst.size()) {} + ~CheckerContext(); + ConstraintManager &getConstraintManager() { return Eng.getConstraintManager(); } @@ -83,27 +81,66 @@ public: return getBugReporter().getSourceManager(); } - ExplodedNode *GenerateNode(const Stmt *S, bool markAsSink = false) { - return GenerateNode(S, getState(), markAsSink); + 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 Stmt* S, const GRState *state, - bool markAsSink = false) { - ExplodedNode *node = B.generateNode(S, state, Pred); - - if (markAsSink && node) - node->markAsSink(); + 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; + } - return node; + 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() || + (state && state != 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; + } + }; class Checker { @@ -118,7 +155,7 @@ private: ExplodedNode *Pred, void *tag, bool isPrevisit) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind); + ProgramPoint::PostStmtKind, S); if (isPrevisit) _PreVisit(C, S); else @@ -134,7 +171,7 @@ private: bool isPrevisit) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind); + ProgramPoint::PostStmtKind, StoreE); assert(isPrevisit && "Only previsit supported for now."); PreVisitBind(C, AssignE, StoreE, location, val); } @@ -149,7 +186,7 @@ private: void *tag, bool isLoad) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isLoad ? ProgramPoint::PreLoadKind : - ProgramPoint::PreStoreKind, state); + ProgramPoint::PreStoreKind, S, state); VisitLocation(C, S, location); } @@ -157,7 +194,7 @@ private: GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, SymbolReaper &SymReaper, void *tag) { CheckerContext C(Dst, Builder, Eng, Pred, tag, - ProgramPoint::PostPurgeDeadSymbolsKind); + ProgramPoint::PostPurgeDeadSymbolsKind, S); EvalDeadSymbols(C, S, SymReaper); } diff --git a/clang/lib/Analysis/ArrayBoundChecker.cpp b/clang/lib/Analysis/ArrayBoundChecker.cpp index 549a22bec17..3d8b3b3d1b1 100644 --- a/clang/lib/Analysis/ArrayBoundChecker.cpp +++ b/clang/lib/Analysis/ArrayBoundChecker.cpp @@ -62,8 +62,7 @@ void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){ const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { - ExplodedNode *N = C.GenerateNode(S, StOutBound, true); - + ExplodedNode *N = C.GenerateSink(StOutBound); if (!N) return; @@ -80,7 +79,6 @@ void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){ new RangedBugReport(*BT, BT->getDescription(), N); report->addRange(S->getSourceRange()); - C.EmitReport(report); } } diff --git a/clang/lib/Analysis/AttrNonNullChecker.cpp b/clang/lib/Analysis/AttrNonNullChecker.cpp index 01e1a1fcf69..8668c75c754 100644 --- a/clang/lib/Analysis/AttrNonNullChecker.cpp +++ b/clang/lib/Analysis/AttrNonNullChecker.cpp @@ -39,7 +39,6 @@ void clang::RegisterAttrNonNullChecker(GRExprEngine &Eng) { void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { const GRState *state = C.getState(); - const GRState *originalState = state; // Check if the callee has a 'nonnull' attribute. SVal X = state->getSVal(CE->getCallee()); @@ -74,7 +73,7 @@ void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, if (stateNull && !stateNotNull) { // Generate an error node. Check for a null node in case // we cache out. - if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) { + if (ExplodedNode *errorNode = C.GenerateSink(stateNull)) { // Lazily allocate the BugType object if it hasn't already been // created. Ownership is transferred to the BugReporter object once @@ -109,6 +108,5 @@ void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, // If we reach here all of the arguments passed the nonnull check. // If 'state' has been updated generated a new node. - if (state != originalState) - C.addTransition(C.GenerateNode(CE, state)); + C.addTransition(state); } diff --git a/clang/lib/Analysis/BasicObjCFoundationChecks.cpp b/clang/lib/Analysis/BasicObjCFoundationChecks.cpp index 5a88a7af935..424a0b3b254 100644 --- a/clang/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/clang/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -563,12 +563,11 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, BT = new APIMisuse("message incorrectly sent to class instead of class " "instance"); - ExplodedNode *N = C.GenerateNode(ME, C.getState(), false); + ExplodedNode *N = C.GenerateNode(); + if (!N) return; - C.addTransition(N); - llvm::SmallString<200> buf; llvm::raw_svector_ostream os(buf); diff --git a/clang/lib/Analysis/CastToStructChecker.cpp b/clang/lib/Analysis/CastToStructChecker.cpp index ccd4a3333e2..7c6fc7ed3f4 100644 --- a/clang/lib/Analysis/CastToStructChecker.cpp +++ b/clang/lib/Analysis/CastToStructChecker.cpp @@ -59,7 +59,7 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C, // Now the cast-to-type is struct pointer, the original type is not void*. if (!OrigPointeeTy->isRecordType()) { - if (ExplodedNode *N = C.GenerateNode(CE)) { + if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Cast from non-struct type to struct type", "Casting a non-structure type to a structure type " diff --git a/clang/lib/Analysis/Checker.cpp b/clang/lib/Analysis/Checker.cpp index 985b1e0a1d7..0d907e50168 100644 --- a/clang/lib/Analysis/Checker.cpp +++ b/clang/lib/Analysis/Checker.cpp @@ -16,3 +16,20 @@ using namespace clang; Checker::~Checker() {} + +CheckerContext::~CheckerContext() { + // Do we need to autotransition? 'Dst' can get populated in a variety of + // ways, including 'addTransition()' adding the predecessor node to Dst + // without actually generated a new node. We also shouldn't autotransition + // if we are building sinks or we generated a node and decided to not + // add it as a transition. + if (Dst.size() == size && !B.BuildSinks && !B.HasGeneratedNode) { + if (state && state != B.GetState(Pred)) { + static int autoTransitionTag = 0; + B.Tag = &autoTransitionTag; + addTransition(state); + } + else + Dst.Add(Pred); + } +} diff --git a/clang/lib/Analysis/DereferenceChecker.cpp b/clang/lib/Analysis/DereferenceChecker.cpp index a8f5af34a72..4c4091cbc28 100644 --- a/clang/lib/Analysis/DereferenceChecker.cpp +++ b/clang/lib/Analysis/DereferenceChecker.cpp @@ -56,8 +56,7 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l) { // Check for dereference of an undefined value. if (l.isUndef()) { - ExplodedNode *N = C.GenerateNode(S, true); - if (N) { + if (ExplodedNode *N = C.GenerateSink()) { if (!BT_undef) BT_undef = new BuiltinBug("Dereference of undefined pointer value"); @@ -84,7 +83,7 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, if (nullState) { if (!notNullState) { // Generate an error node. - ExplodedNode *N = C.GenerateNode(S, nullState, true); + ExplodedNode *N = C.GenerateSink(nullState); if (!N) return; @@ -106,13 +105,11 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, // Otherwise, we have the case where the location could either be // null or not-null. Record the error node as an "implicit" null // dereference. - if (ExplodedNode *N = C.GenerateNode(S, nullState, true)) + if (ExplodedNode *N = C.GenerateSink(nullState)) ImplicitNullDerefNodes.push_back(N); } } // From this point forward, we know that the location is not null. - assert(notNullState); - C.addTransition(state != nullState ? C.GenerateNode(S, notNullState) : - C.getPredecessor()); + C.addTransition(notNullState); } diff --git a/clang/lib/Analysis/DivZeroChecker.cpp b/clang/lib/Analysis/DivZeroChecker.cpp index a8630f10088..4052637043f 100644 --- a/clang/lib/Analysis/DivZeroChecker.cpp +++ b/clang/lib/Analysis/DivZeroChecker.cpp @@ -63,7 +63,7 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C, llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV); if (stateZero && !stateNotZero) { - if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) { + if (ExplodedNode *N = C.GenerateSink(stateZero)) { if (!BT) BT = new BuiltinBug("Division by zero"); @@ -80,6 +80,5 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C, // If we get here, then the denom should not be zero. We abandon the implicit // zero denom case for now. - if (stateNotZero != C.getState()) - C.addTransition(C.GenerateNode(B, stateNotZero)); + C.addTransition(stateNotZero); } diff --git a/clang/lib/Analysis/FixedAddressChecker.cpp b/clang/lib/Analysis/FixedAddressChecker.cpp index 80096dcb70d..d8adaafa605 100644 --- a/clang/lib/Analysis/FixedAddressChecker.cpp +++ b/clang/lib/Analysis/FixedAddressChecker.cpp @@ -53,7 +53,7 @@ void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C, if (!RV.isConstant() || RV.isZeroConstant()) return; - if (ExplodedNode *N = C.GenerateNode(B)) { + if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Use fixed address", "Using a fixed address is not portable because that " diff --git a/clang/lib/Analysis/GRExprEngine.cpp b/clang/lib/Analysis/GRExprEngine.cpp index 4f3440d88a0..f657aebdf6d 100644 --- a/clang/lib/Analysis/GRExprEngine.cpp +++ b/clang/lib/Analysis/GRExprEngine.cpp @@ -1292,9 +1292,13 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, Checker *checker = I->second; for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) - checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI, state, + NI != NE; ++NI) { + // Use the 'state' argument only when the predecessor node is the + // same as Pred. This allows us to catch updates to the state. + checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI, + *NI == Pred ? state : GetState(*NI), location, tag, isLoad); + } // Update which NodeSet is the current one. PrevSet = CurrSet; diff --git a/clang/lib/Analysis/MallocChecker.cpp b/clang/lib/Analysis/MallocChecker.cpp index 995720b1f8f..a16125df77e 100644 --- a/clang/lib/Analysis/MallocChecker.cpp +++ b/clang/lib/Analysis/MallocChecker.cpp @@ -112,9 +112,7 @@ void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) { SymbolRef Sym = CallVal.getAsLocSymbol(); assert(Sym); // Set the symbol's state to Allocated. - const GRState *AllocState - = state->set<RegionState>(Sym, RefState::getAllocated(CE)); - C.addTransition(C.GenerateNode(CE, AllocState)); + C.addTransition(state->set<RegionState>(Sym, RefState::getAllocated(CE))); } void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { @@ -128,7 +126,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { // Check double free. if (RS->isReleased()) { - ExplodedNode *N = C.GenerateNode(CE, true); + ExplodedNode *N = C.GenerateSink(); if (N) { if (!BT_DoubleFree) BT_DoubleFree = new BuiltinBug("Double free", @@ -144,7 +142,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { // Normal free. const GRState *FreedState = state->set<RegionState>(Sym, RefState::getReleased(CE)); - C.addTransition(C.GenerateNode(CE, FreedState)); + C.addTransition(FreedState); } void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S, @@ -158,7 +156,7 @@ void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S, return; if (RS->isAllocated()) { - ExplodedNode *N = C.GenerateNode(S, true); + ExplodedNode *N = C.GenerateSink(); if (N) { if (!BT_Leak) BT_Leak = new BuiltinBug("Memory leak", @@ -213,7 +211,5 @@ void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) { if (RS->isAllocated()) state = state->set<RegionState>(Sym, RefState::getEscaped(S)); - ExplodedNode *N = C.GenerateNode(S, state); - if (N) - C.addTransition(N); + C.addTransition(state); } diff --git a/clang/lib/Analysis/PointerArithChecker.cpp b/clang/lib/Analysis/PointerArithChecker.cpp index 93823484e1d..6bf1a3fc5da 100644 --- a/clang/lib/Analysis/PointerArithChecker.cpp +++ b/clang/lib/Analysis/PointerArithChecker.cpp @@ -53,7 +53,7 @@ void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C, if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) || isa<CompoundLiteralRegion>(LR)) { - if (ExplodedNode *N = C.GenerateNode(B)) { + if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Dangerous pointer arithmetic", "Pointer arithmetic done on non-array variables " diff --git a/clang/lib/Analysis/PointerSubChecker.cpp b/clang/lib/Analysis/PointerSubChecker.cpp index 4c7906f4beb..50f502507db 100644 --- a/clang/lib/Analysis/PointerSubChecker.cpp +++ b/clang/lib/Analysis/PointerSubChecker.cpp @@ -61,7 +61,7 @@ void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C, if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR)) return; - if (ExplodedNode *N = C.GenerateNode(B)) { + if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Pointer subtraction", "Subtraction of two pointers that do not point to " diff --git a/clang/lib/Analysis/ReturnPointerRangeChecker.cpp b/clang/lib/Analysis/ReturnPointerRangeChecker.cpp index 44887b2625d..8a1929464e9 100644 --- a/clang/lib/Analysis/ReturnPointerRangeChecker.cpp +++ b/clang/lib/Analysis/ReturnPointerRangeChecker.cpp @@ -70,7 +70,7 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C, const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { - ExplodedNode *N = C.GenerateNode(RS, StOutBound, true); + ExplodedNode *N = C.GenerateSink(StOutBound); if (!N) return; @@ -91,7 +91,6 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C, new RangedBugReport(*BT, BT->getDescription(), N); report->addRange(RetE->getSourceRange()); - C.EmitReport(report); } } diff --git a/clang/lib/Analysis/ReturnStackAddressChecker.cpp b/clang/lib/Analysis/ReturnStackAddressChecker.cpp index e4be8712d09..e8a014af291 100644 --- a/clang/lib/Analysis/ReturnStackAddressChecker.cpp +++ b/clang/lib/Analysis/ReturnStackAddressChecker.cpp @@ -53,7 +53,7 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C, if (!R || !R->hasStackStorage()) return; - ExplodedNode *N = C.GenerateNode(RS, C.getState(), true); + ExplodedNode *N = C.GenerateSink(); if (!N) return; diff --git a/clang/lib/Analysis/ReturnUndefChecker.cpp b/clang/lib/Analysis/ReturnUndefChecker.cpp index 796c7608c86..48163b4d86e 100644 --- a/clang/lib/Analysis/ReturnUndefChecker.cpp +++ b/clang/lib/Analysis/ReturnUndefChecker.cpp @@ -50,7 +50,7 @@ void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C, if (!C.getState()->getSVal(RetE).isUndef()) return; - ExplodedNode *N = C.GenerateNode(RS, C.getState(), true); + ExplodedNode *N = C.GenerateSink(); if (!N) return; diff --git a/clang/lib/Analysis/UndefinedArgChecker.cpp b/clang/lib/Analysis/UndefinedArgChecker.cpp index ea7d971fdb8..e717f6bfe21 100644 --- a/clang/lib/Analysis/UndefinedArgChecker.cpp +++ b/clang/lib/Analysis/UndefinedArgChecker.cpp @@ -47,7 +47,7 @@ void clang::RegisterUndefinedArgChecker(GRExprEngine &Eng) { void UndefinedArgChecker::EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE) { - ExplodedNode *N = C.GenerateNode(CE, true); + ExplodedNode *N = C.GenerateSink(); if (!N) return; @@ -81,7 +81,7 @@ void UndefinedArgChecker::PreVisitCallExpr(CheckerContext &C, for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { if (C.getState()->getSVal(*I).isUndef()) { - if (ExplodedNode *N = C.GenerateNode(CE, true)) { + if (ExplodedNode *N = C.GenerateSink()) { if (!BT_call_arg) BT_call_arg = new BuiltinBug("Pass-by-value argument in function call" " is undefined"); @@ -104,7 +104,7 @@ void UndefinedArgChecker::PreVisitObjCMessageExpr(CheckerContext &C, if (const Expr *receiver = ME->getReceiver()) if (state->getSVal(receiver).isUndef()) { - if (ExplodedNode *N = C.GenerateNode(ME, true)) { + if (ExplodedNode *N = C.GenerateSink()) { if (!BT_msg_undef) BT_msg_undef = new BuiltinBug("Receiver in message expression is a garbage value"); @@ -122,7 +122,7 @@ void UndefinedArgChecker::PreVisitObjCMessageExpr(CheckerContext &C, for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(), E = ME->arg_end(); I != E; ++I) { if (state->getSVal(*I).isUndef()) { - if (ExplodedNode *N = C.GenerateNode(ME, true)) { + if (ExplodedNode *N = C.GenerateSink()) { if (!BT_msg_arg) BT_msg_arg = new BuiltinBug("Pass-by-value argument in message expression" diff --git a/clang/lib/Analysis/UndefinedArraySubscriptChecker.cpp b/clang/lib/Analysis/UndefinedArraySubscriptChecker.cpp index 887c7755fe4..3ae0c579e91 100644 --- a/clang/lib/Analysis/UndefinedArraySubscriptChecker.cpp +++ b/clang/lib/Analysis/UndefinedArraySubscriptChecker.cpp @@ -41,7 +41,7 @@ void UndefinedArraySubscriptChecker::PreVisitArraySubscriptExpr(CheckerContext &C, const ArraySubscriptExpr *A) { if (C.getState()->getSVal(A->getIdx()).isUndef()) { - if (ExplodedNode *N = C.GenerateNode(A, true)) { + if (ExplodedNode *N = C.GenerateSink()) { if (!BT) BT = new BuiltinBug("Array subscript is undefined"); diff --git a/clang/lib/Analysis/UndefinedAssignmentChecker.cpp b/clang/lib/Analysis/UndefinedAssignmentChecker.cpp index 0e911ffab08..1c5b25cd8e1 100644 --- a/clang/lib/Analysis/UndefinedAssignmentChecker.cpp +++ b/clang/lib/Analysis/UndefinedAssignmentChecker.cpp @@ -48,7 +48,7 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, if (!val.isUndef()) return; - ExplodedNode *N = C.GenerateNode(StoreE, true); + ExplodedNode *N = C.GenerateSink(); if (!N) return; diff --git a/clang/lib/Analysis/VLASizeChecker.cpp b/clang/lib/Analysis/VLASizeChecker.cpp index 799a73e293c..9a3436c4c96 100644 --- a/clang/lib/Analysis/VLASizeChecker.cpp +++ b/clang/lib/Analysis/VLASizeChecker.cpp @@ -55,7 +55,7 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) { if (sizeV.isUndef()) { // Generate an error node. - ExplodedNode *N = C.GenerateNode(DS, true); + ExplodedNode *N = C.GenerateSink(); if (!N) return; @@ -78,7 +78,7 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) { llvm::tie(stateNotZero, stateZero) = state->Assume(sizeD); if (stateZero && !stateNotZero) { - ExplodedNode* N = C.GenerateNode(DS, stateZero, true); + ExplodedNode* N = C.GenerateSink(stateZero); if (!BT_zero) BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero " "size"); @@ -92,6 +92,5 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) { } // From this point on, assume that the size is not zero. - if (state != stateNotZero) - C.addTransition(C.GenerateNode(DS, stateNotZero)); + C.addTransition(stateNotZero); } |