diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -452,23 +452,26 @@ const Summary &Summary = *FoundSummary; ProgramStateRef State = C.getState(); + ProgramStateRef NewState = State; for (const ValueConstraintPtr& VC : Summary.ArgConstraints) { - ProgramStateRef SuccessSt = VC->apply(State, Call, Summary); - ProgramStateRef FailureSt = VC->negate()->apply(State, Call, Summary); + ProgramStateRef SuccessSt = VC->apply(NewState, Call, Summary); + ProgramStateRef FailureSt = VC->negate()->apply(NewState, Call, Summary); // The argument constraint is not satisfied. if (FailureSt && !SuccessSt) { - if (ExplodedNode *N = C.generateErrorNode(State)) + if (ExplodedNode *N = C.generateErrorNode(NewState)) reportBug(Call, N, C); break; } else { - // Apply the constraint even if we cannot reason about the argument. This - // means both SuccessSt and FailureSt can be true. If we weren't applying - // the constraint that would mean that symbolic execution continues on a - // code whose behaviour is undefined. + // We will apply the constraint even if we cannot reason about the + // argument. This means both SuccessSt and FailureSt can be true. If we + // weren't applying the constraint that would mean that symbolic + // execution continues on a code whose behaviour is undefined. assert(SuccessSt); - C.addTransition(SuccessSt); + NewState = SuccessSt; } } + if (NewState && NewState != State) + C.addTransition(NewState); } void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,