forked from OSchip/llvm-project
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 llvm-svn: 339459
This commit is contained in:
parent
5bb9d798b4
commit
088adbfa16
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "clang/AST/Attr.h"
|
#include "clang/AST/Attr.h"
|
||||||
#include "clang/AST/CharUnits.h"
|
#include "clang/AST/CharUnits.h"
|
||||||
|
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||||
#include "clang/Analysis/AnalysisDeclContext.h"
|
#include "clang/Analysis/AnalysisDeclContext.h"
|
||||||
#include "clang/Basic/TargetInfo.h"
|
#include "clang/Basic/TargetInfo.h"
|
||||||
|
@ -1033,6 +1034,32 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
|
||||||
B = B.remove(baseR);
|
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
|
// BlockDataRegion? If so, invalidate captured variables that are passed
|
||||||
// by reference.
|
// by reference.
|
||||||
if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(baseR)) {
|
if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(baseR)) {
|
||||||
|
|
|
@ -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,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: %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
|
// RUN: FileCheck --input-file=%t %s
|
||||||
|
|
||||||
void clang_analyzer_warnIfReached();
|
void clang_analyzer_warnIfReached();
|
||||||
void clang_analyzer_eval(int);
|
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&); };
|
struct X { X(const X&); };
|
||||||
void f(X x) { (void) [x]{}; }
|
void f(X x) { (void) [x]{}; }
|
||||||
|
|
||||||
|
@ -348,6 +364,18 @@ void testCapturedConstExprFloat() {
|
||||||
lambda();
|
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;
|
static int b = 0;
|
||||||
|
|
||||||
|
@ -365,6 +393,8 @@ int f() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// CHECK: [B2 (ENTRY)]
|
// CHECK: [B2 (ENTRY)]
|
||||||
// CHECK: Succs (1): B1
|
// CHECK: Succs (1): B1
|
||||||
// CHECK: [B1]
|
// CHECK: [B1]
|
||||||
|
|
Loading…
Reference in New Issue