[PATCH] Sema: Eliminate recursion from checkForFunctionCall()
Richard Trieu
rtrieu at google.com
Wed Jul 22 14:50:08 PDT 2015
On Wed, Jul 22, 2015 at 1:34 PM, Vedant Kumar <vsk at apple.com> wrote:
> Large CFGs cause clang::Sema::checkForFunctionCall() to stack overflow.
>
Is the code that produces the large CFG available? It may be useful to
test that other users of the CFG can cope with processing the code.
>
> I have a patch which breaks the recursion in checkForFunctionCall() by
> manually
> managing the call stack. This fixes the problem. The check-clang target
> reports
> no regressions.
>
> I don't have commit rights, so I'd appreciate someone taking a look at the
> patch and getting it into trunk :).
>
> thanks!
> vedant
>
>
> ================================================================================
>
> diff --git a/lib/Sema/AnalysisBasedWarnings.cpp
> b/lib/Sema/AnalysisBasedWarnings.cpp
> index f2ff48a..dc6dda0 100644
> --- a/lib/Sema/AnalysisBasedWarnings.cpp
> +++ b/lib/Sema/AnalysisBasedWarnings.cpp
> @@ -52,6 +52,8 @@
> #include <deque>
> #include <iterator>
> #include <vector>
> +#include <functional>
> +#include <utility>
>
> using namespace clang;
>
> @@ -175,59 +177,69 @@ static void checkForFunctionCall(Sema &S, const
> FunctionDecl *FD,
> CFGBlock &Block, unsigned ExitID,
> llvm::SmallVectorImpl<RecursiveState>
> &States,
> RecursiveState State) {
> - unsigned ID = Block.getBlockID();
> + std::vector<std::pair<std::reference_wrapper<CFGBlock>, RecursiveState>>
> + Stack;
> + Stack.emplace_back(std::make_pair(std::ref(Block), State));
>
> - // A block's state can only move to a higher state.
> - if (States[ID] >= State)
> - return;
> + while (!Stack.empty()) {
> + CFGBlock &CurBlock = Stack.back().first.get();
> + RecursiveState CurState = Stack.back().second;
> + Stack.pop_back();
>
> - States[ID] = State;
> + unsigned ID = CurBlock.getBlockID();
>
> - // Found a path to the exit node without a recursive call.
> - if (ID == ExitID && State == FoundPathWithNoRecursiveCall)
> - return;
> + // A block's state can only move to a higher state.
> + if (States[ID] >= CurState)
> + continue;
>
> - if (State == FoundPathWithNoRecursiveCall) {
> - // If the current state is FoundPathWithNoRecursiveCall, the
> successors
> - // will be either FoundPathWithNoRecursiveCall or FoundPath. To
> determine
> - // which, process all the Stmt's in this block to find any recursive
> calls.
> - for (const auto &B : Block) {
> - if (B.getKind() != CFGElement::Statement)
> - continue;
> + States[ID] = CurState;
> +
> + // Found a path to the exit node without a recursive call.
> + if (ID == ExitID && CurState == FoundPathWithNoRecursiveCall)
> + continue;
> +
> + if (CurState == FoundPathWithNoRecursiveCall) {
> + // If the current state is FoundPathWithNoRecursiveCall, the
> successors
> + // will be either FoundPathWithNoRecursiveCall or FoundPath. To
> determine
> + // which, process all the Stmt's in this block to find any recursive
> + // calls.
> + for (const auto &B : CurBlock) {
> + if (B.getKind() != CFGElement::Statement)
> + continue;
>
> - const CallExpr *CE =
> dyn_cast<CallExpr>(B.getAs<CFGStmt>()->getStmt());
> - if (CE && CE->getCalleeDecl() &&
> - CE->getCalleeDecl()->getCanonicalDecl() == FD) {
> -
> - // Skip function calls which are qualified with a templated class.
> - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(
> - CE->getCallee()->IgnoreParenImpCasts())) {
> - if (NestedNameSpecifier *NNS = DRE->getQualifier()) {
> - if (NNS->getKind() == NestedNameSpecifier::TypeSpec &&
> - isa<TemplateSpecializationType>(NNS->getAsType())) {
> - continue;
> + const CallExpr *CE =
> dyn_cast<CallExpr>(B.getAs<CFGStmt>()->getStmt());
> + if (CE && CE->getCalleeDecl() &&
> + CE->getCalleeDecl()->getCanonicalDecl() == FD) {
> +
> + // Skip function calls which are qualified with a templated
> class.
> + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(
> + CE->getCallee()->IgnoreParenImpCasts())) {
> + if (NestedNameSpecifier *NNS = DRE->getQualifier()) {
> + if (NNS->getKind() == NestedNameSpecifier::TypeSpec &&
> + isa<TemplateSpecializationType>(NNS->getAsType())) {
> + continue;
> + }
> }
> }
> - }
>
> - if (const CXXMemberCallExpr *MCE =
> dyn_cast<CXXMemberCallExpr>(CE)) {
> - if (isa<CXXThisExpr>(MCE->getImplicitObjectArgument()) ||
> - !MCE->getMethodDecl()->isVirtual()) {
> - State = FoundPath;
> + if (const CXXMemberCallExpr *MCE =
> dyn_cast<CXXMemberCallExpr>(CE)) {
> + if (isa<CXXThisExpr>(MCE->getImplicitObjectArgument()) ||
> + !MCE->getMethodDecl()->isVirtual()) {
> + CurState = FoundPath;
> + break;
> + }
> + } else {
> + CurState = FoundPath;
> break;
> }
> - } else {
> - State = FoundPath;
> - break;
> }
> }
> }
> - }
>
> - for (CFGBlock::succ_iterator I = Block.succ_begin(), E =
> Block.succ_end();
> - I != E; ++I)
> - if (*I)
> - checkForFunctionCall(S, FD, **I, ExitID, States, State);
> + for (auto I = CurBlock.succ_rbegin(), E = CurBlock.succ_rend(); I !=
> E; ++I)
> + if (*I)
> + Stack.emplace_back(std::make_pair(std::ref(**I), CurState));
> + }
> }
>
> static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150722/185825a8/attachment.html>
More information about the cfe-commits
mailing list