Index: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -1268,6 +1268,12 @@ "false", Released, Hide>, + CmdLineOption, CmdLineOption Vs, PointerEscapeKind K) const; public: Index: clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp @@ -40,6 +40,7 @@ check::EndFunction, check::NewAllocator, check::Bind, + check::PointerEscape, check::RegionChanges, check::LiveSymbols> { @@ -165,6 +166,15 @@ llvm::errs() << "RegionChanges\n"; return State; } + + ProgramStateRef checkPointerEscape(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call, + PointerEscapeKind Kind) const { + if (isCallbackEnabled(State, "PointerEscape")) + llvm::errs() << "PointerEscape\n"; + return State; + } }; } // end anonymous namespace Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1172,13 +1172,15 @@ } } -ProgramStateRef ExprEngine::escapeValue(ProgramStateRef State, SVal V, +ProgramStateRef ExprEngine::escapeValue(ProgramStateRef State, + ArrayRef Vs, PointerEscapeKind K) const { class CollectReachableSymbolsCallback final : public SymbolVisitor { - InvalidatedSymbols Symbols; + InvalidatedSymbols &Symbols; public: - explicit CollectReachableSymbolsCallback(ProgramStateRef) {} + explicit CollectReachableSymbolsCallback(InvalidatedSymbols &Symbols) + : Symbols(Symbols) {} const InvalidatedSymbols &getSymbols() const { return Symbols; } @@ -1187,11 +1189,13 @@ return true; } }; + InvalidatedSymbols Symbols; + CollectReachableSymbolsCallback CallBack(Symbols); + for (SVal V : Vs) + State->scanReachableSymbols(V, CallBack); - const CollectReachableSymbolsCallback &Scanner = - State->scanReachableSymbols(V); return getCheckerManager().runCheckersForPointerEscape( - State, Scanner.getSymbols(), /*CallEvent*/ nullptr, K, nullptr); + State, CallBack.getSymbols(), /*CallEvent*/ nullptr, K, nullptr); } void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -592,9 +592,47 @@ 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 invalidating 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. + + // Run pointerEscape callback with the newly conjured symbols. + SmallVector Escaped; + for (auto I : dstPostCall) { + NodeBuilder B(I, Dst, *currBldrCtx); + ProgramStateRef State = I->getState(); + Escaped.clear(); + 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; + QualType Pointee = ParamTy->getPointeeType(); + if (Pointee.isConstQualified() || Pointee->isVoidType()) + continue; + if (const MemRegion *MR = Call.getArgSVal(Arg).getAsRegion()) + if (!MR->hasStackStorage()) + Escaped.push_back(State->getSVal(MR, Pointee)); + } + } + + State = escapeValue(State, Escaped, PSK_EscapeOnConservativeCall); + + if (State == I->getState()) + Dst.insert(I); + else + B.generateNode(I->getLocation(), State, I); + } } ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, @@ -670,8 +708,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); Index: clang/test/Analysis/analyzer-config.c =================================================================== --- clang/test/Analysis/analyzer-config.c +++ clang/test/Analysis/analyzer-config.c @@ -37,6 +37,7 @@ // CHECK-NEXT: debug.AnalysisOrder:EndFunction = false // CHECK-NEXT: debug.AnalysisOrder:LiveSymbols = false // CHECK-NEXT: debug.AnalysisOrder:NewAllocator = false +// CHECK-NEXT: debug.AnalysisOrder:PointerEscape = false // CHECK-NEXT: debug.AnalysisOrder:PostCall = false // CHECK-NEXT: debug.AnalysisOrder:PostStmtArraySubscriptExpr = false // CHECK-NEXT: debug.AnalysisOrder:PostStmtCXXNewExpr = false @@ -97,4 +98,4 @@ // CHECK-NEXT: unroll-loops = false // CHECK-NEXT: widen-loops = false // CHECK-NEXT: [stats] -// CHECK-NEXT: num-entries = 94 +// CHECK-NEXT: num-entries = 95 Index: clang/test/Analysis/ponter-escape-on-conservative-calls.c =================================================================== --- /dev/null +++ clang/test/Analysis/ponter-escape-on-conservative-calls.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=debug.AnalysisOrder -analyzer-config debug.AnalysisOrder:PointerEscape=true -analyzer-config debug.AnalysisOrder:PostCall=true %s 2>&1 | FileCheck %s + + +void f(int *); + +int main() { + int a; + f(&a); + return 0; +} + +// CHECK: PostCall +// CHECK-NEXT: PointerEscape