Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/Type.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "PrettyStackTraceLocationContext.h" #include "clang/AST/CXXInheritance.h" @@ -18,6 +19,8 @@ #include "clang/Analysis/ConstructionContext.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/SaveAndRestore.h" @@ -576,15 +579,14 @@ // Run any pre-call checks using the generic call interface. ExplodedNodeSet dstPreVisit; - getCheckerManager().runCheckersForPreCall(dstPreVisit, Pred, - Call, *this); + getCheckerManager().runCheckersForPreCall(dstPreVisit, Pred, Call, *this); // Actually evaluate the function call. We try each of the checkers // to see if the can evaluate the function call, and get a callback at // defaultEvalCall if all of them fail. ExplodedNodeSet dstCallEvaluated; - getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit, - Call, *this); + getCheckerManager().runCheckersForEvalCall( + dstCallEvaluated, dstPreVisit, Call, *this); // If there were other constructors called for object-type arguments // of this call, clean them up. @@ -592,9 +594,72 @@ for (auto I : dstCallEvaluated) finishArgumentConstruction(dstArgumentCleanup, I, Call); - // Finally, run any post-call checks. - getCheckerManager().runCheckersForPostCall(Dst, dstArgumentCleanup, + ExplodedNodeSet dstPostCall; + getCheckerManager().runCheckersForPostCall(dstPostCall, dstArgumentCleanup, Call, *this); + + // Escaping symbols conjured during invalidationg the regions above. + // Note that, for inlined calls the nodes were put back into the worklist, + // so we can assume that every node belongs to a conservative call at this + // point. + class CollectReachableSymbolsCallback final : public SymbolVisitor { + ProgramStateRef State; + InvalidatedSymbols &Symbols; + + public: + explicit CollectReachableSymbolsCallback(ProgramStateRef State, + InvalidatedSymbols &Symbols) + : State(State), Symbols(Symbols) {} + + bool VisitSymbol(SymbolRef Sym) override { return true; } + bool VisitMemRegion(const MemRegion *MR) override { + if (MR->hasStackStorage()) + return false; + QualType T; + if (const TypedRegion *TR = dyn_cast(MR)) + T = TR->getLocationType(); + else if (const SymbolicRegion *SR = dyn_cast(MR)) + T = SR->getSymbol()->getType(); + if (T->isVoidPointerType()) + return false; + SVal StoredVal = State->getSVal(MR); + if (SymbolRef Sym = StoredVal.getAsSymbol()) + Symbols.insert(Sym); + return true; + } + }; + + // Run pointerEscape callback with the newly conjured symbols. + for (auto I : dstPostCall) { + NodeBuilder B(I, Dst, *currBldrCtx); + InvalidatedSymbols Symbols; + ProgramStateRef State = I->getState(); + CollectReachableSymbolsCallback Scanner(State, Symbols); + const FunctionDecl *FuncDecl = + dyn_cast_or_null(Call.getDecl()); + if (FuncDecl) { + for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) { + if (Arg >= FuncDecl->getNumParams()) + break; + QualType ParamTy = FuncDecl->getParamDecl(Arg)->getType(); + if (ParamTy.isNull() || + (!ParamTy->isPointerType() && !ParamTy->isReferenceType())) + continue; + if (ParamTy->getPointeeType().isConstQualified()) + continue; + State->scanReachableSymbols(Call.getArgSVal(Arg), Scanner); + } + } + + // TODO: the PSK is a lie. + State = getCheckerManager().runCheckersForPointerEscape( + State, Symbols, &Call, PSK_DirectEscapeOnCall, nullptr); + + if (State != I->getState()) + B.generateNode(I->getLocation(), State, I); + else + Dst.insert(I); + } } ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, @@ -644,8 +709,8 @@ ITraits.setTrait(TargetR, RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion); State = State->invalidateRegions(TargetR, E, Count, LCtx, - /* CausesPointerEscape=*/false, nullptr, - &Call, &ITraits); + /* CausesPointerEscape=*/false, + nullptr, &Call, &ITraits); R = State->getSVal(Target.castAs(), E->getType()); } else { @@ -670,8 +735,7 @@ // Conservatively evaluate call by invalidating regions and binding // a conjured return value. void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr, - ExplodedNode *Pred, - ProgramStateRef State) { + ExplodedNode *Pred, ProgramStateRef State) { State = Call.invalidateRegions(currBldrCtx->blockCount(), State); State = bindReturnValue(Call, Pred->getLocationContext(), State);