Skip to content

Commit

Permalink
[analyzer] Nullability: Suppress return diagnostics in inlined functi…
Browse files Browse the repository at this point in the history
…ons.

The nullability checker can sometimes miss detecting nullability precondition
violations in inlined functions because the binding for the parameter
that violated the precondition becomes dead before the return:

int * _Nonnull callee(int * _Nonnull p2) {
  if (!p2)
    // p2 becomes dead here, so binding removed.
    return 0; // warning here because value stored in p2 is symbolic.
  else
   return p2;
}

int *caller(int * _Nonnull p1) {
  return callee(p1);
}

The fix, which is quite blunt, is to not warn about null returns in inlined
methods/functions. This won’t lose much coverage for ObjC because the analyzer
always analyzes each ObjC method at the top level in addition to inlined. It
*will* lose coverage for C — but there aren’t that many codebases with C
nullability annotations.

rdar://problem/25615050

llvm-svn: 266109
  • Loading branch information
devincoughlin committed Apr 12, 2016
1 parent fd3e1ad commit 49bd58f
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 1 deletion.
3 changes: 2 additions & 1 deletion clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
Expand Up @@ -562,7 +562,8 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
if (Filter.CheckNullReturnedFromNonnull &&
NullReturnedFromNonNull &&
RetExprTypeLevelNullability != Nullability::Nonnull &&
!InSuppressedMethodFamily) {
!InSuppressedMethodFamily &&
C.getLocationContext()->inTopFrame()) {
static CheckerProgramPointTag Tag(this, "NullReturnedFromNonnull");
ExplodedNode *N = C.generateErrorNode(State, &Tag);
if (!N)
Expand Down
35 changes: 35 additions & 0 deletions clang/test/Analysis/nullability.mm
Expand Up @@ -238,6 +238,41 @@ void testPreconditionViolationInInlinedFunction(Dummy *p) {
doNotWarnWhenPreconditionIsViolated(p);
}

@interface TestInlinedPreconditionViolationClass : NSObject
@end

@implementation TestInlinedPreconditionViolationClass
-(Dummy * _Nonnull) calleeWithParam:(Dummy * _Nonnull) p2 {
Dummy *x = 0;
if (!p2) // p2 binding becomes dead at this point.
return x; // no-warning
else
return p2;
}

-(Dummy *)callerWithParam:(Dummy * _Nonnull) p1 {
return [self calleeWithParam:p1];
}

@end

int * _Nonnull InlinedPreconditionViolationInFunctionCallee(int * _Nonnull p2) {
int *x = 0;
if (!p2) // p2 binding becomes dead at this point.
return x; // no-warning
else
return p2;
}

int * _Nonnull InlinedReturnNullOverSuppressionCallee(int * _Nonnull p2) {
int *result = 0;
return result; // no-warning; but this is an over suppression
}

int *InlinedReturnNullOverSuppressionCaller(int * _Nonnull p1) {
return InlinedReturnNullOverSuppressionCallee(p1);
}

void inlinedNullable(Dummy *_Nullable p) {
if (p) return;
}
Expand Down

0 comments on commit 49bd58f

Please sign in to comment.