Skip to content

Commit

Permalink
Merging r293043:
Browse files Browse the repository at this point in the history
------------------------------------------------------------------------
r293043 | dergachev | 2017-01-25 02:21:45 -0800 (Wed, 25 Jan 2017) | 12 lines

[analyzer] Fix MacOSXAPIChecker fp with static locals seen from nested blocks.

This is an attempt to avoid new false positives caused by the reverted r292800,
however the scope of the fix is significantly reduced - some variables are still
in incorrect memory spaces.

Relevant test cases added.

rdar://problem/30105546
rdar://problem/30156693
Differential revision: https://reviews.llvm.org/D28946

------------------------------------------------------------------------

llvm-svn: 294050
  • Loading branch information
zmodem committed Feb 3, 2017
1 parent a65b909 commit b2ebccc
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 3 deletions.
9 changes: 8 additions & 1 deletion clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
Expand Up @@ -94,11 +94,18 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
bool SuggestStatic = false;
os << "Call to '" << FName << "' uses";
if (const VarRegion *VR = dyn_cast<VarRegion>(RB)) {
const VarDecl *VD = VR->getDecl();
// FIXME: These should have correct memory space and thus should be filtered
// out earlier. This branch only fires when we're looking from a block,
// which we analyze as a top-level declaration, onto a static local
// in a function that contains the block.
if (VD->isStaticLocal())
return;
// We filtered out globals earlier, so it must be a local variable
// or a block variable which is under UnknownSpaceRegion.
if (VR != R)
os << " memory within";
if (VR->getDecl()->hasAttr<BlocksAttr>())
if (VD->hasAttr<BlocksAttr>())
os << " the block variable '";
else
os << " the local variable '";
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/StaticAnalyzer/Core/MemRegion.cpp
Expand Up @@ -816,9 +816,11 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,

const StackFrameContext *STC = V.get<const StackFrameContext*>();

if (!STC)
if (!STC) {
// FIXME: Assign a more sensible memory space to static locals
// we see from within blocks that we analyze as top-level declarations.
sReg = getUnknownRegion();
else {
} else {
if (D->hasLocalStorage()) {
sReg = isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)
? static_cast<const MemRegion*>(getStackArgumentsRegion(STC))
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/StaticAnalyzer/Core/RegionStore.cpp
Expand Up @@ -1849,6 +1849,8 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,

// Function-scoped static variables are default-initialized to 0; if they
// have an initializer, it would have been processed by now.
// FIXME: This is only true when we're starting analysis from main().
// We're losing a lot of coverage here.
if (isa<StaticGlobalSpaceRegion>(MS))
return svalBuilder.makeZeroVal(T);

Expand Down
7 changes: 7 additions & 0 deletions clang/test/Analysis/dispatch-once.m
Expand Up @@ -107,3 +107,10 @@ void test_block_var_from_outside_block() {
};
dispatch_once(&once, ^{}); // expected-warning{{Call to 'dispatch_once' uses the block variable 'once' for the predicate value.}}
}

void test_static_var_from_outside_block() {
static dispatch_once_t once;
^{
dispatch_once(&once, ^{}); // no-warning
};
}
35 changes: 35 additions & 0 deletions clang/test/Analysis/null-deref-static.m
@@ -0,0 +1,35 @@
// RUN: %clang_cc1 -w -fblocks -analyze -analyzer-checker=core,deadcode,alpha.core,debug.ExprInspection -verify %s

void *malloc(unsigned long);
void clang_analyzer_warnIfReached();

void test_static_from_block() {
static int *x;
^{
*x; // no-warning
};
}

void test_static_within_block() {
^{
static int *x;
*x; // expected-warning{{Dereference of null pointer}}
};
}

void test_static_control_flow(int y) {
static int *x;
if (x) {
// FIXME: Should be reachable.
clang_analyzer_warnIfReached(); // no-warning
}
if (y) {
// We are not sure if this branch is possible, because the developer
// may argue that function is always called with y == 1 for the first time.
// In this case, we can only advise the developer to add assertions
// for suppressing such path.
*x; // expected-warning{{Dereference of null pointer}}
} else {
x = malloc(1);
}
}

0 comments on commit b2ebccc

Please sign in to comment.