diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer')
43 files changed, 126 insertions, 102 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp index 45706c2f2f6..c092610afe2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp @@ -62,7 +62,7 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS, ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true); ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { - ExplodedNode *N = C.generateSink(StOutBound); + ExplodedNode *N = C.generateErrorNode(StOutBound); if (!N) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp index bc790d4584f..f4de733bd79 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp @@ -182,7 +182,7 @@ void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext, ProgramStateRef errorState, OOB_Kind kind) const { - ExplodedNode *errorNode = checkerContext.generateSink(errorState); + ExplodedNode *errorNode = checkerContext.generateErrorNode(errorState); if (!errorNode) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 6adf39f3755..e157478433c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -140,7 +140,7 @@ void NilArgChecker::warnIfNilExpr(const Expr *E, ProgramStateRef State = C.getState(); if (State->isNull(C.getSVal(E)).isConstrainedTrue()) { - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { generateBugReport(N, Msg, E->getSourceRange(), E, C); } @@ -157,7 +157,7 @@ void NilArgChecker::warnIfNilArg(CheckerContext &C, if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue()) return; - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); @@ -489,14 +489,15 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, if (SourceSize == TargetSize) return; - // Generate an error. Only generate a sink if 'SourceSize < TargetSize'; - // otherwise generate a regular node. + // Generate an error. Only generate a sink error node + // if 'SourceSize < TargetSize'; otherwise generate a non-fatal error node. // // FIXME: We can actually create an abstract "CFNumber" object that has // the bits initialized to the provided values. // - if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink() - : C.addTransition()) { + ExplodedNode *N = SourceSize < TargetSize ? C.generateErrorNode() + : C.generateNonFatalErrorNode(); + if (N) { SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); @@ -589,7 +590,7 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE, std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull); if (stateTrue && !stateFalse) { - ExplodedNode *N = C.generateSink(stateTrue); + ExplodedNode *N = C.generateErrorNode(stateTrue); if (!N) return; @@ -656,7 +657,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg, if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) return; - if (ExplodedNode *N = C.addTransition()) { + if (ExplodedNode *N = C.generateNonFatalErrorNode()) { SmallString<200> buf; llvm::raw_svector_ostream os(buf); @@ -800,7 +801,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg, // Generate only one error node to use for all bug reports. if (!errorNode.hasValue()) - errorNode = C.addTransition(); + errorNode = C.generateNonFatalErrorNode(); if (!errorNode.getValue()) continue; @@ -1025,7 +1026,7 @@ void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS, } if (!State) - C.generateSink(); + C.generateSink(C.getState(), C.getPredecessor()); else if (State != C.getState()) C.addTransition(State); } diff --git a/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp index b4ac316fdce..f26f73129e7 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp @@ -32,7 +32,7 @@ namespace { void BoolAssignmentChecker::emitReport(ProgramStateRef state, CheckerContext &C) const { - if (ExplodedNode *N = C.addTransition(state)) { + if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) { if (!BT) BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value")); C.emitReport(llvm::make_unique<BugReport>(*BT, BT->getDescription(), N)); diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 477bea74d8c..07c341400e7 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -229,7 +229,7 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, if (!Filter.CheckCStringNullArg) return nullptr; - ExplodedNode *N = C.generateSink(stateNull); + ExplodedNode *N = C.generateErrorNode(stateNull); if (!N) return nullptr; @@ -292,7 +292,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, ProgramStateRef StInBound = state->assumeInBound(Idx, Size, true); ProgramStateRef StOutBound = state->assumeInBound(Idx, Size, false); if (StOutBound && !StInBound) { - ExplodedNode *N = C.generateSink(StOutBound); + ExplodedNode *N = C.generateErrorNode(StOutBound); if (!N) return nullptr; @@ -525,7 +525,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C, void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state, const Stmt *First, const Stmt *Second) const { - ExplodedNode *N = C.generateSink(state); + ExplodedNode *N = C.generateErrorNode(state); if (!N) return; @@ -585,7 +585,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C, if (stateOverflow && !stateOkay) { // We have an overflow. Emit a bug report. - ExplodedNode *N = C.generateSink(stateOverflow); + ExplodedNode *N = C.generateErrorNode(stateOverflow); if (!N) return nullptr; @@ -706,7 +706,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, if (!Filter.CheckCStringNotNullTerm) return UndefinedVal(); - if (ExplodedNode *N = C.addTransition(state)) { + if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) { if (!BT_NotCString) BT_NotCString.reset(new BuiltinBug( Filter.CheckNameCStringNotNullTerm, categories::UnixAPI, @@ -766,7 +766,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, if (!Filter.CheckCStringNotNullTerm) return UndefinedVal(); - if (ExplodedNode *N = C.addTransition(state)) { + if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) { if (!BT_NotCString) BT_NotCString.reset(new BuiltinBug( Filter.CheckNameCStringNotNullTerm, categories::UnixAPI, diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 33a24d816c5..750cbda4597 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -97,7 +97,7 @@ private: void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE) { - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; @@ -169,7 +169,7 @@ bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C, const ProgramStateRef State = C.getState(); const SVal PSV = State->getSVal(SValMemRegion); if (PSV.isUndef()) { - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { LazyInit_BT(BD, BT); auto R = llvm::make_unique<BugReport>(*BT, Message, N); R->addRange(ArgRange); @@ -200,7 +200,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, return true; if (V.isUndef()) { - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { LazyInit_BT(BD, BT); // Generate a report for this bug. @@ -265,7 +265,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, D->getStore()); if (F.Find(D->getRegion())) { - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { LazyInit_BT(BD, BT); SmallString<512> Str; llvm::raw_svector_ostream os(Str); @@ -338,7 +338,7 @@ void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE, SVal Arg = C.getSVal(DE->getArgument()); if (Arg.isUndef()) { StringRef Desc; - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; if (!BT_cxx_delete_undef) @@ -395,7 +395,7 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call, // the function. unsigned Params = FD->getNumParams(); if (Call.getNumArgs() < Params) { - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; @@ -443,7 +443,7 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const { SVal recVal = msg.getReceiverSVal(); if (recVal.isUndef()) { - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { BugType *BT = nullptr; switch (msg.getMessageKind()) { case OCM_Message: @@ -559,7 +559,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, Ctx.LongDoubleTy == CanRetTy || Ctx.LongLongTy == CanRetTy || Ctx.UnsignedLongLongTy == CanRetTy)))) { - if (ExplodedNode *N = C.generateSink(state, nullptr, &Tag)) + if (ExplodedNode *N = C.generateErrorNode(state, &Tag)) emitNilReceiverBug(C, Msg, N); return; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp index 0d683f96df0..a5ed64d160a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp @@ -131,7 +131,7 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const { if (evenFlexibleArraySize(Ctx, regionSize, typeSize, ToPointeeTy)) return; - if (ExplodedNode *errorNode = C.generateSink()) { + if (ExplodedNode *errorNode = C.generateErrorNode()) { if (!BT) BT.reset(new BuiltinBug(this, "Cast region with wrong size.", "Cast a region whose size is not a multiple" diff --git a/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp index ba3024d78a1..fa7841356ef 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp @@ -56,7 +56,7 @@ void CastToStructChecker::checkPreStmt(const CastExpr *CE, // Now the cast-to-type is struct pointer, the original type is not void*. if (!OrigPointeeTy->isRecordType()) { - if (ExplodedNode *N = C.addTransition()) { + if (ExplodedNode *N = C.generateNonFatalErrorNode()) { if (!BT) BT.reset( new BuiltinBug(this, "Cast from non-struct type to struct type", diff --git a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp index cefdb064534..3ad1996db89 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp @@ -140,7 +140,7 @@ void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { void *const* k = C.getState()->FindGDM(ChrootChecker::getTag()); if (k) if (isRootChanged((intptr_t) *k)) - if (ExplodedNode *N = C.addTransition()) { + if (ExplodedNode *N = C.generateNonFatalErrorNode()) { if (!BT_BreakJail) BT_BreakJail.reset(new BuiltinBug( this, "Break out of jail", "No call of chdir(\"/\") immediately " diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index 0df31860906..8d41a25c281 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -91,7 +91,7 @@ DereferenceChecker::AddDerefSource(raw_ostream &os, void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C, bool IsBind) const { // Generate an error node. - ExplodedNode *N = C.generateSink(State); + ExplodedNode *N = C.generateErrorNode(State); if (!N) return; @@ -184,7 +184,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, CheckerContext &C) const { // Check for dereference of an undefined value. if (l.isUndef()) { - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_undef) BT_undef.reset( new BuiltinBug(this, "Dereference of undefined pointer value")); @@ -219,7 +219,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, 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.generateSink(nullState)) { + if (ExplodedNode *N = C.generateSink(nullState, C.getPredecessor())) { ImplicitNullDerefEvent event = {l, isLoad, N, &C.getBugReporter(), /*IsDirectDereference=*/false}; dispatchEvent(event); @@ -257,7 +257,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, // At this point the value could be either null or non-null. // Record this as an "implicit" null dereference. - if (ExplodedNode *N = C.generateSink(StNull)) { + if (ExplodedNode *N = C.generateSink(StNull, C.getPredecessor())) { ImplicitNullDerefEvent event = {V, /*isLoad=*/true, N, &C.getBugReporter(), /*IsDirectDereference=*/false}; diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index 211a1c1d0cf..59850230563 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -35,7 +35,7 @@ public: void DivZeroChecker::reportBug(const char *Msg, ProgramStateRef StateZero, CheckerContext &C) const { - if (ExplodedNode *N = C.generateSink(StateZero)) { + if (ExplodedNode *N = C.generateErrorNode(StateZero)) { if (!BT) BT.reset(new BuiltinBug(this, "Division by zero")); diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp index 7dc0a874595..60c6aa534d1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -86,8 +86,7 @@ static const char *getArgumentValueString(const CallExpr *CE, void ExprInspectionChecker::analyzerEval(const CallExpr *CE, CheckerContext &C) const { - ExplodedNode *N = C.getPredecessor(); - const LocationContext *LC = N->getLocationContext(); + const LocationContext *LC = C.getPredecessor()->getLocationContext(); // A specific instantiation of an inlined function may have more constrained // values than can generally be assumed. Skip the check. @@ -97,24 +96,28 @@ void ExprInspectionChecker::analyzerEval(const CallExpr *CE, if (!BT) BT.reset(new BugType(this, "Checking analyzer assumptions", "debug")); + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) + return; C.emitReport( llvm::make_unique<BugReport>(*BT, getArgumentValueString(CE, C), N)); } void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const { - ExplodedNode *N = C.getPredecessor(); if (!BT) BT.reset(new BugType(this, "Checking analyzer assumptions", "debug")); + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) + return; C.emitReport(llvm::make_unique<BugReport>(*BT, "REACHABLE", N)); } void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const { - ExplodedNode *N = C.getPredecessor(); - const LocationContext *LC = N->getLocationContext(); + const LocationContext *LC = C.getPredecessor()->getLocationContext(); // An inlined function could conceivably also be analyzed as a top-level // function. We ignore this case and only emit a message (TRUE or FALSE) @@ -127,6 +130,9 @@ void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE, if (!BT) BT.reset(new BugType(this, "Checking analyzer assumptions", "debug")); + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) + return; C.emitReport( llvm::make_unique<BugReport>(*BT, getArgumentValueString(CE, C), N)); } diff --git a/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp index ae226f727c7..3fe89f96a43 100644 --- a/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp @@ -50,7 +50,7 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B, if (!RV.isConstant() || RV.isZeroConstant()) return; - if (ExplodedNode *N = C.addTransition()) { + if (ExplodedNode *N = C.generateNonFatalErrorNode()) { if (!BT) BT.reset( new BuiltinBug(this, "Use fixed address", diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp index cb2bf108ef7..1d8085108c0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp @@ -640,7 +640,7 @@ bool GenericTaintChecker::generateReportIfTainted(const Expr *E, return false; // Generate diagnostic. - if (ExplodedNode *N = C.addTransition()) { + if (ExplodedNode *N = C.generateNonFatalErrorNode()) { initBugType(); auto report = llvm::make_unique<BugReport>(*BT, Msg, N); report->addRange(E->getSourceRange()); diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp index 932d3d6ffff..547aa7540d9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp @@ -255,7 +255,7 @@ void MacOSKeychainAPIChecker:: CheckerContext &C) const { ProgramStateRef State = C.getState(); State = State->remove<AllocatedData>(AP.first); - ExplodedNode *N = C.addTransition(State); + ExplodedNode *N = C.generateNonFatalErrorNode(State); if (!N) return; @@ -301,7 +301,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, // Remove the value from the state. The new symbol will be added for // tracking when the second allocator is processed in checkPostStmt(). State = State->remove<AllocatedData>(V); - ExplodedNode *N = C.addTransition(State); + ExplodedNode *N = C.generateNonFatalErrorNode(State); if (!N) return; initBugType(); @@ -364,7 +364,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, if (isEnclosingFunctionParam(ArgExpr)) return; - ExplodedNode *N = C.addTransition(State); + ExplodedNode *N = C.generateNonFatalErrorNode(State); if (!N) return; initBugType(); @@ -430,7 +430,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, // report a bad call to free. if (State->assume(ArgSVal.castAs<DefinedSVal>(), false) && !definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) { - ExplodedNode *N = C.addTransition(State); + ExplodedNode *N = C.generateNonFatalErrorNode(State); if (!N) return; initBugType(); @@ -584,7 +584,9 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR, } static CheckerProgramPointTag Tag(this, "DeadSymbolsLeak"); - ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag); + ExplodedNode *N = C.generateNonFatalErrorNode(C.getState(), &Tag); + if (!N) + return; // Generate the error reports. for (const auto P : Errors) diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp index 4ce936aa0fe..4cbe97b2607 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp @@ -62,7 +62,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) return; - ExplodedNode *N = C.generateSink(state); + ExplodedNode *N = C.generateErrorNode(state); if (!N) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index c95b2fd7f4b..d5c5cc1dbae 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1592,7 +1592,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, if (!CheckKind.hasValue()) return; - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_BadFree[*CheckKind]) BT_BadFree[*CheckKind].reset( new BugType(CheckNames[*CheckKind], "Bad free", "Memory Error")); @@ -1637,7 +1637,7 @@ void MallocChecker::ReportFreeAlloca(CheckerContext &C, SVal ArgVal, else return; - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_FreeAlloca[*CheckKind]) BT_FreeAlloca[*CheckKind].reset( new BugType(CheckNames[*CheckKind], "Free alloca()", "Memory Error")); @@ -1661,7 +1661,7 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C, if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) return; - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_MismatchedDealloc) BT_MismatchedDealloc.reset( new BugType(CheckNames[CK_MismatchedDeallocatorChecker], @@ -1720,7 +1720,7 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal, if (!CheckKind.hasValue()) return; - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; @@ -1774,7 +1774,7 @@ void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range, if (!CheckKind.hasValue()) return; - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_UseFree[*CheckKind]) BT_UseFree[*CheckKind].reset(new BugType( CheckNames[*CheckKind], "Use-after-free", "Memory Error")); @@ -1801,7 +1801,7 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range, if (!CheckKind.hasValue()) return; - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_DoubleFree[*CheckKind]) BT_DoubleFree[*CheckKind].reset( new BugType(CheckNames[*CheckKind], "Double free", "Memory Error")); @@ -1829,7 +1829,7 @@ void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const { if (!CheckKind.hasValue()) return; - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_DoubleDelete) BT_DoubleDelete.reset(new BugType(CheckNames[CK_NewDeleteChecker], "Double delete", "Memory Error")); @@ -1856,7 +1856,7 @@ void MallocChecker::ReportUseZeroAllocated(CheckerContext &C, if (!CheckKind.hasValue()) return; - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_UseZerroAllocated[*CheckKind]) BT_UseZerroAllocated[*CheckKind].reset(new BugType( CheckNames[*CheckKind], "Use of zero allocated", "Memory Error")); @@ -2150,10 +2150,12 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, ExplodedNode *N = C.getPredecessor(); if (!Errors.empty()) { static CheckerProgramPointTag Tag("MallocChecker", "DeadSymbolsLeak"); - N = C.addTransition(C.getState(), C.getPredecessor(), &Tag); - for (SmallVectorImpl<SymbolRef>::iterator + N = C.generateNonFatalErrorNode(C.getState(), &Tag); + if (N) { + for (SmallVectorImpl<SymbolRef>::iterator I = Errors.begin(), E = Errors.end(); I != E; ++I) { - reportLeak(*I, N, C); + reportLeak(*I, N, C); + } } } diff --git a/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp index 5d9b32fa911..0e7894788c8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp @@ -62,7 +62,7 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg, BT.reset(new BugType(this, "Use -drain instead of -release", "API Upgrade (Apple)")); - ExplodedNode *N = C.addTransition(); + ExplodedNode *N = C.generateNonFatalErrorNode(); if (!N) { assert(0); return; diff --git a/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp index ba82d1d1d41..8d0a060fc45 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp @@ -81,7 +81,7 @@ void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE, } if (BuildSinks) - C.generateSink(); + C.generateSink(C.getState(), C.getPredecessor()); } void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg, @@ -90,7 +90,7 @@ void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg, if (const ObjCMethodDecl *MD = Msg.getDecl()) { MD = MD->getCanonicalDecl(); if (MD->hasAttr<AnalyzerNoReturnAttr>()) { - C.generateSink(); + C.generateSink(C.getState(), C.getPredecessor()); return; } } @@ -136,7 +136,7 @@ void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg, } // If we got here, it's one of the messages we care about. - C.generateSink(); + C.generateSink(C.getState(), C.getPredecessor()); } void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) { diff --git a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp index a7586c412af..1f82ab94af8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp @@ -143,7 +143,7 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call, if (!stateNotNull) { // Generate an error node. Check for a null node in case // we cache out. - if (ExplodedNode *errorNode = C.generateSink(stateNull)) { + if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) { std::unique_ptr<BugReport> R; if (haveAttrNonNull) @@ -161,7 +161,7 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call, // Always return. Either we cached out or we just emitted an error. return; } - if (ExplodedNode *N = C.generateSink(stateNull)) { + if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) { ImplicitNullDerefEvent event = { V, false, N, &C.getBugReporter(), /*IsDirectDereference=*/haveRefTypeParam}; diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp index 74a7e38e944..137dedbf4ce 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp @@ -499,7 +499,9 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S, Nullness == NullConstraint::IsNull && StaticNullability == Nullability::Nonnull) { static CheckerProgramPointTag Tag(this, "NullReturnedFromNonnull"); - ExplodedNode *N = C.generateSink(State, C.getPredecessor(), &Tag); + ExplodedNode *N = C.generateErrorNode(State, &Tag); + if (!N) + return; reportBugIfPreconditionHolds(ErrorKind::NilReturnedToNonnull, N, nullptr, C, RetExpr); return; @@ -569,7 +571,9 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call, if (Filter.CheckNullPassedToNonnull && Nullness == NullConstraint::IsNull && ArgStaticNullability != Nullability::Nonnull && ParamNullability == Nullability::Nonnull) { - ExplodedNode *N = C.generateSink(State); + ExplodedNode *N = C.generateErrorNode(State); + if (!N) + return; reportBugIfPreconditionHolds(ErrorKind::NilPassedToNonnull, N, nullptr, C, ArgExpr); return; @@ -891,7 +895,9 @@ void NullabilityChecker::checkBind(SVal L, SVal V, const Stmt *S, ValNullability != Nullability::Nonnull && LocNullability == Nullability::Nonnull) { static CheckerProgramPointTag Tag(this, "NullPassedToNonnull"); - ExplodedNode *N = C.generateSink(State, C.getPredecessor(), &Tag); + ExplodedNode *N = C.generateErrorNode(State, &Tag); + if (!N) + return; reportBugIfPreconditionHolds(ErrorKind::NilAssignedToNonnull, N, nullptr, C, S); return; diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp index a7b92b4c67f..cbaa5c23592 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp @@ -43,7 +43,7 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, // Uninitialized value used for the mutex? if (V.getAs<UndefinedVal>()) { - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_undef) BT_undef.reset(new BuiltinBug(this, "Uninitialized value used as mutex " "for @synchronized")); @@ -66,7 +66,7 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, if (!notNullState) { // Generate an error node. This isn't a sink since // a null mutex just means no synchronization occurs. - if (ExplodedNode *N = C.addTransition(nullState)) { + if (ExplodedNode *N = C.generateNonFatalErrorNode(nullState)) { if (!BT_null) BT_null.reset(new BuiltinBug( this, "Nil value used as mutex for @synchronized() " diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp index 14f4969c444..0203d79cd00 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp @@ -139,7 +139,7 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE, ProgramStateRef StInBound = State->assumeInBound(Idx, *Size, true, T); ProgramStateRef StOutBound = State->assumeInBound(Idx, *Size, false, T); if (StOutBound && !StInBound) { - ExplodedNode *N = C.generateSink(StOutBound); + ExplodedNode *N = C.generateErrorNode(StOutBound); if (!N) return; initBugType(); diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp index 193f515d1ca..f344dd09c7a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp @@ -153,7 +153,7 @@ void ObjCSelfInitChecker::checkForInvalidSelf(const Expr *E, CheckerContext &C, return; // Generate an error node. - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp index 313fe7c43e0..e3369677af7 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp @@ -51,7 +51,7 @@ void PointerArithChecker::checkPreStmt(const BinaryOperator *B, if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) || isa<CompoundLiteralRegion>(LR)) { - if (ExplodedNode *N = C.addTransition()) { + if (ExplodedNode *N = C.generateNonFatalErrorNode()) { if (!BT) BT.reset( new BuiltinBug(this, "Dangerous pointer arithmetic", diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp index a3b02d99741..2d33ebc2610 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp @@ -60,7 +60,7 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B, if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR)) return; - if (ExplodedNode *N = C.addTransition()) { + if (ExplodedNode *N = C.generateNonFatalErrorNode()) { if (!BT) BT.reset( new BuiltinBug(this, "Pointer subtraction", diff --git a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp index 4b8c0b7a98e..426c97dbd4c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp @@ -142,7 +142,7 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE, if (!BT_doublelock) BT_doublelock.reset(new BugType(this, "Double locking", "Lock checker")); - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; auto report = llvm::make_unique<BugReport>( @@ -204,7 +204,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE, if (!BT_doubleunlock) BT_doubleunlock.reset(new BugType(this, "Double unlocking", "Lock checker")); - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; auto Report = llvm::make_unique<BugReport>( @@ -227,7 +227,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE, if (firstLockR != lockR) { if (!BT_lor) BT_lor.reset(new BugType(this, "Lock order reversal", "Lock checker")); - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; auto report = llvm::make_unique<BugReport>( @@ -272,7 +272,7 @@ void PthreadLockChecker::DestroyLock(CheckerContext &C, const CallExpr *CE, if (!BT_destroylock) BT_destroylock.reset(new BugType(this, "Destroy invalid lock", "Lock checker")); - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; auto Report = llvm::make_unique<BugReport>(*BT_destroylock, Message, N); @@ -307,7 +307,7 @@ void PthreadLockChecker::InitLock(CheckerContext &C, const CallExpr *CE, if (!BT_initlock) BT_initlock.reset(new BugType(this, "Init invalid lock", "Lock checker")); - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; auto Report = llvm::make_unique<BugReport>(*BT_initlock, Message, N); @@ -320,7 +320,7 @@ void PthreadLockChecker::reportUseDestroyedBug(CheckerContext &C, if (!BT_destroylock) BT_destroylock.reset(new BugType(this, "Use destroyed lock", "Lock checker")); - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; auto Report = llvm::make_unique<BugReport>( diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 490a242191b..0610beb7bf3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -3306,7 +3306,7 @@ void RetainCountChecker::processNonLeakError(ProgramStateRef St, if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None) return; - ExplodedNode *N = C.generateSink(St); + ExplodedNode *N = C.generateErrorNode(St); if (!N) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp index d94299c050d..19fa0fb193c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp @@ -62,7 +62,7 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS, ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true); ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { - ExplodedNode *N = C.generateSink(StOutBound); + ExplodedNode *N = C.generateErrorNode(StOutBound); if (!N) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp index 2668ac1e1ec..c5e826a84b8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp @@ -80,7 +80,7 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS, static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE, const Expr *TrackingE = nullptr) { - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp index e1b2eaf46d8..7026a2ec16a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp @@ -200,7 +200,9 @@ void SimpleStreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, State = State->remove<StreamMap>(Sym); } - ExplodedNode *N = C.addTransition(State); + ExplodedNode *N = C.generateNonFatalErrorNode(State); + if (!N) + return; reportLeaks(LeakedStreams, C, N); } @@ -208,7 +210,7 @@ void SimpleStreamChecker::reportDoubleClose(SymbolRef FileDescSym, const CallEvent &Call, CheckerContext &C) const { // We reached a bug, stop exploring the path here by generating a sink. - ExplodedNode *ErrNode = C.generateSink(); + ExplodedNode *ErrNode = C.generateErrorNode(); // If we've already reached this node on another path, return. if (!ErrNode) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp index f57cd70fd44..2eefb93e23a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -94,7 +94,7 @@ SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R, void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE) const { - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; @@ -211,7 +211,7 @@ void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const { return; // Generate an error node. - ExplodedNode *N = Ctx.addTransition(state); + ExplodedNode *N = Ctx.generateNonFatalErrorNode(state); if (!N) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index f9dfd38e1f8..82b01fe814d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -271,7 +271,7 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const { if (x >= 0 && x <= 2) return; - if (ExplodedNode *N = C.addTransition(state)) { + if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) { if (!BT_illegalwhence) BT_illegalwhence.reset( new BuiltinBug(this, "Illegal whence argument", @@ -349,7 +349,7 @@ ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state, std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); if (!stateNotNull && stateNull) { - if (ExplodedNode *N = C.generateSink(stateNull)) { + if (ExplodedNode *N = C.generateErrorNode(stateNull)) { if (!BT_nullfp) BT_nullfp.reset(new BuiltinBug(this, "NULL stream pointer", "Stream pointer might be NULL.")); @@ -378,7 +378,7 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE, // Check: Double close a File Descriptor could cause undefined behaviour. // Conforming to man-pages if (SS->isClosed()) { - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (N) { if (!BT_doubleclose) BT_doubleclose.reset(new BuiltinBug( @@ -406,7 +406,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, continue; if (SS->isOpened()) { - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (N) { if (!BT_ResourceLeak) BT_ResourceLeak.reset(new BuiltinBug( diff --git a/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp index 6e2477579f5..2e0529015ca 100644 --- a/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp @@ -48,7 +48,7 @@ void TaintTesterChecker::checkPostStmt(const Expr *E, return; if (State->isTainted(E, C.getLocationContext())) { - if (ExplodedNode *N = C.addTransition()) { + if (ExplodedNode *N = C.generateNonFatalErrorNode()) { initBugType(); auto report = llvm::make_unique<BugReport>(*BT, "tainted",N); report->addRange(E->getSourceRange()); diff --git a/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp index 638701da8a0..b794d2f86bb 100644 --- a/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp @@ -167,7 +167,7 @@ bool TestAfterDivZeroChecker::hasDivZeroMap(SVal Var, } void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const { - if (ExplodedNode *N = C.generateSink(C.getState())) { + if (ExplodedNode *N = C.generateErrorNode(C.getState())) { if (!DivZeroBug) DivZeroBug.reset(new BuiltinBug(this, "Division by zero")); diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp index 268e957ea5b..ed17610e411 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp @@ -62,7 +62,7 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition, if (X.isUndef()) { // Generate a sink node, which implicitly marks both outgoing branches as // infeasible. - ExplodedNode *N = Ctx.generateSink(); + ExplodedNode *N = Ctx.generateErrorNode(); if (N) { if (!BT) BT.reset(new BuiltinBug( diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp index 0f426b5d54e..17fe8610da0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp @@ -74,7 +74,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE, // Get the VarRegion associated with VD in the local stack frame. if (Optional<UndefinedVal> V = state->getSVal(I.getOriginalRegion()).getAs<UndefinedVal>()) { - if (ExplodedNode *N = C.generateSink()) { + if (ExplodedNode *N = C.generateErrorNode()) { if (!BT) BT.reset( new BuiltinBug(this, "uninitialized variable captured by block")); diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp index 8ae8694ca70..38d2aa6d8f9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp @@ -50,7 +50,7 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B, return; // Generate an error node. - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp index c80732f2741..fe07eafd281 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp @@ -46,7 +46,7 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A, if (Ctor->isDefaulted()) return; - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; if (!BT) diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp index 81c96c4860b..7a31efc8cef 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp @@ -46,7 +46,7 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, if (C.getCalleeName(EnclosingFunctionDecl) == "swap") return; - ExplodedNode *N = C.generateSink(); + ExplodedNode *N = C.generateErrorNode(); if (!N) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp index cf580ad4654..4b78c205834 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp @@ -77,7 +77,7 @@ void UnixAPIChecker::ReportOpenBug(CheckerContext &C, ProgramStateRef State, const char *Msg, SourceRange SR) const { - ExplodedNode *N = C.generateSink(State); + ExplodedNode *N = C.generateErrorNode(State); if (!N) return; @@ -182,7 +182,7 @@ void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C, if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) return; - ExplodedNode *N = C.generateSink(state); + ExplodedNode *N = C.generateErrorNode(state); if (!N) return; @@ -231,7 +231,7 @@ bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C, ProgramStateRef falseState, const Expr *arg, const char *fn_name) const { - ExplodedNode *N = C.generateSink(falseState); + ExplodedNode *N = C.generateErrorNode(falseState); if (!N) return false; diff --git a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp index 8cd3aac7476..e3b2ed22236 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp @@ -46,7 +46,7 @@ void VLASizeChecker::reportBug(VLASize_Kind Kind, ProgramStateRef State, CheckerContext &C) const { // Generate an error node. - ExplodedNode *N = C.generateSink(State); + ExplodedNode *N = C.generateErrorNode(State); if (!N) return; diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index a3abb1887ef..f70a7d04ae9 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -3224,6 +3224,11 @@ void BugReporter::Register(BugType *BT) { void BugReporter::emitReport(std::unique_ptr<BugReport> R) { if (const ExplodedNode *E = R->getErrorNode()) { + // An error node must either be a sink or have a tag, otherwise + // it could get reclaimed before the path diagnostic is created. + assert((E->isSink() || E->getLocation().getTag()) && + "Error node must either be a sink or have a tag"); + const AnalysisDeclContext *DeclCtx = E->getLocationContext()->getAnalysisDeclContext(); // The source of autosynthesized body can be handcrafted AST or a model |