Author: george.karpenkov Date: Fri Aug 10 11:28:04 2018 New Revision: 339459
URL: http://llvm.org/viewvc/llvm-project?rev=339459&view=rev Log: Invalidate static locals when escaping lambdas Lambdas can affect static locals even without an explicit capture. rdar://39537031 Differential Revision: https://reviews.llvm.org/D50368 Modified: cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp cfe/trunk/test/Analysis/lambdas.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp?rev=339459&r1=339458&r2=339459&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp Fri Aug 10 11:28:04 2018 @@ -17,6 +17,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/CharUnits.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/TargetInfo.h" @@ -1033,6 +1034,32 @@ void invalidateRegionsWorker::VisitClust B = B.remove(baseR); } + if (const auto *TO = dyn_cast<TypedValueRegion>(baseR)) { + if (const auto *RD = TO->getValueType()->getAsCXXRecordDecl()) { + + // Lambdas can affect all static local variables without explicitly + // capturing those. + // We invalidate all static locals referenced inside the lambda body. + if (RD->isLambda() && RD->getLambdaCallOperator()->getBody()) { + using namespace ast_matchers; + + const char *DeclBind = "DeclBind"; + StatementMatcher RefToStatic = stmt(hasDescendant(declRefExpr( + to(varDecl(hasStaticStorageDuration()).bind(DeclBind))))); + auto Matches = + match(RefToStatic, *RD->getLambdaCallOperator()->getBody(), + RD->getASTContext()); + + for (BoundNodes &Match : Matches) { + auto *VD = Match.getNodeAs<VarDecl>(DeclBind); + const VarRegion *ToInvalidate = + RM.getRegionManager().getVarRegion(VD, LCtx); + AddToWorkList(ToInvalidate); + } + } + } + } + // BlockDataRegion? If so, invalidate captured variables that are passed // by reference. if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(baseR)) { Modified: cfe/trunk/test/Analysis/lambdas.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/lambdas.cpp?rev=339459&r1=339458&r2=339459&view=diff ============================================================================== --- cfe/trunk/test/Analysis/lambdas.cpp (original) +++ cfe/trunk/test/Analysis/lambdas.cpp Fri Aug 10 11:28:04 2018 @@ -1,10 +1,26 @@ // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s +// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core -analyzer-config inline-lambdas=false -DNO_INLINING=1 -verify %s // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.DumpCFG -analyzer-config inline-lambdas=true %s > %t 2>&1 // RUN: FileCheck --input-file=%t %s void clang_analyzer_warnIfReached(); void clang_analyzer_eval(int); +#ifdef NO_INLINING + +// expected-no-diagnostics + +int& invalidate_static_on_unknown_lambda() { + static int* z; + auto f = [] { + z = nullptr; + }; // should invalidate "z" when inlining is disabled. + f(); + return *z; // no-warning +} + +#else + struct X { X(const X&); }; void f(X x) { (void) [x]{}; } @@ -348,6 +364,18 @@ void testCapturedConstExprFloat() { lambda(); } +void escape(void*); + +int& invalidate_static_on_unknown_lambda() { + static int* z; + auto lambda = [] { + static float zz; + z = new int(120); + }; + escape(&lambda); + return *z; // no-warning +} + static int b = 0; @@ -365,6 +393,8 @@ int f() { return 0; } +#endif + // CHECK: [B2 (ENTRY)] // CHECK: Succs (1): B1 // CHECK: [B1] _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits