mirror of https://github.com/microsoft/clang.git
Emit a -Wnull-dereference warning for "*null" not just "*null = something". Addresses rdar://9269271.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130207 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
0cd7be4c4d
commit
8a285ae6fc
|
@ -282,6 +282,25 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) {
|
|||
return Owned(E);
|
||||
}
|
||||
|
||||
static void CheckForNullPointerDereference(Sema &S, Expr *E) {
|
||||
// Check to see if we are dereferencing a null pointer. If so,
|
||||
// and if not volatile-qualified, this is undefined behavior that the
|
||||
// optimizer will delete, so warn about it. People sometimes try to use this
|
||||
// to get a deterministic trap and are surprised by clang's behavior. This
|
||||
// only handles the pattern "*null", which is a very syntactic check.
|
||||
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts()))
|
||||
if (UO->getOpcode() == UO_Deref &&
|
||||
UO->getSubExpr()->IgnoreParenCasts()->
|
||||
isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull) &&
|
||||
!UO->getType().isVolatileQualified()) {
|
||||
S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
|
||||
S.PDiag(diag::warn_indirection_through_null)
|
||||
<< UO->getSubExpr()->getSourceRange());
|
||||
S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
|
||||
S.PDiag(diag::note_indirection_through_null));
|
||||
}
|
||||
}
|
||||
|
||||
ExprResult Sema::DefaultLvalueConversion(Expr *E) {
|
||||
// C++ [conv.lval]p1:
|
||||
// A glvalue of a non-function, non-array type T can be
|
||||
|
@ -317,6 +336,8 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
|
|||
if (T->isVoidType())
|
||||
return Owned(E);
|
||||
|
||||
CheckForNullPointerDereference(*this, E);
|
||||
|
||||
// C++ [conv.lval]p1:
|
||||
// [...] If T is a non-class type, the type of the prvalue is the
|
||||
// cv-unqualified version of T. Otherwise, the type of the
|
||||
|
@ -7993,25 +8014,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS,
|
|||
RHS.get(), AA_Assigning))
|
||||
return QualType();
|
||||
|
||||
|
||||
// Check to see if the destination operand is a dereferenced null pointer. If
|
||||
// so, and if not volatile-qualified, this is undefined behavior that the
|
||||
// optimizer will delete, so warn about it. People sometimes try to use this
|
||||
// to get a deterministic trap and are surprised by clang's behavior. This
|
||||
// only handles the pattern "*null = whatever", which is a very syntactic
|
||||
// check.
|
||||
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(LHS->IgnoreParenCasts()))
|
||||
if (UO->getOpcode() == UO_Deref &&
|
||||
UO->getSubExpr()->IgnoreParenCasts()->
|
||||
isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull) &&
|
||||
!UO->getType().isVolatileQualified()) {
|
||||
DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
|
||||
PDiag(diag::warn_indirection_through_null)
|
||||
<< UO->getSubExpr()->getSourceRange());
|
||||
DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
|
||||
PDiag(diag::note_indirection_through_null));
|
||||
}
|
||||
|
||||
CheckForNullPointerDereference(*this, LHS);
|
||||
// Check for trivial buffer overflows.
|
||||
CheckArrayAccess(LHS->IgnoreParenCasts());
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
|
||||
// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
|
||||
// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
|
||||
// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
|
||||
|
||||
//===----------------------------------------------------------------------===
|
||||
// Declarations
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.experimental.UnreachableCode -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.experimental.UnreachableCode -Wno-null-dereference -verify %s
|
||||
|
||||
// Trigger a warning if the analyzer reaches this point in the control flow.
|
||||
#define WARN ((void)*(char*)0)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=flat -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=flat -Wno-null-dereference -verify %s
|
||||
#define FAIL ((void)*(char*)0)
|
||||
struct simple { int x; };
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
// NOTE: Use '-fobjc-gc' to test the analysis being run twice, and multiple reports are not issued.
|
||||
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
|
||||
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
|
||||
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
|
||||
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
|
||||
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
|
||||
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
|
||||
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
|
||||
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
|
||||
|
||||
#ifndef __clang_analyzer__
|
||||
#error __clang__analyzer__ not defined
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
|
||||
// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
|
||||
// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
|
||||
// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
|
||||
|
||||
//===----------------------------------------------------------------------===
|
||||
// Declarations
|
||||
|
|
|
@ -174,6 +174,12 @@ void test19() {
|
|||
*(int*)0 = 0; // expected-warning {{indirection of non-volatile null pointer}} \
|
||||
// expected-note {{consider using __builtin_trap}}
|
||||
*(volatile int*)0 = 0; // Ok.
|
||||
|
||||
// rdar://9269271
|
||||
int x = *(int*)0; // expected-warning {{indirection of non-volatile null pointer}} \
|
||||
// expected-note {{consider using __builtin_trap}}
|
||||
int x2 = *(volatile int*)0; // Ok.
|
||||
int *p = &(*(int*)0); // Ok;
|
||||
}
|
||||
|
||||
int test20(int x) {
|
||||
|
|
|
@ -6,8 +6,8 @@ struct foo a(); // expected-note {{'a' declared here}}
|
|||
void b(struct foo);
|
||||
void c();
|
||||
|
||||
void func() {
|
||||
void func(void *p) {
|
||||
a(); // expected-error{{calling 'a' with incomplete return type 'struct foo'}}
|
||||
b(*(struct foo*)0); // expected-error{{argument type 'struct foo' is incomplete}}
|
||||
c(*(struct foo*)0); // expected-error{{argument type 'struct foo' is incomplete}}
|
||||
b(*(struct foo*)p); // expected-error{{argument type 'struct foo' is incomplete}}
|
||||
c(*(struct foo*)p); // expected-error{{argument type 'struct foo' is incomplete}}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ foo somefunc2() {} // expected-error {{Objective-C interface type 'foo' cannot b
|
|||
// rdar://6780761
|
||||
void f0(foo *a0) {
|
||||
extern void g0(int x, ...);
|
||||
g0(1, *(foo*)0); // expected-error {{cannot pass object with interface type 'foo' by-value through variadic function}}
|
||||
g0(1, *(foo*)a0); // expected-error {{cannot pass object with interface type 'foo' by-value through variadic function}}
|
||||
}
|
||||
|
||||
// rdar://8421082
|
||||
|
|
Loading…
Reference in New Issue