From: Richard Trieu Date: Thu, 16 Jun 2011 21:36:56 +0000 (+0000) Subject: Add a new warning when a NULL constant is used in arithmetic operations. The warning... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3e95ba94fd34c5f6420c57d7732f601875074681;p=clang Add a new warning when a NULL constant is used in arithmetic operations. The warning will fire on cases such as: int x = 1 + NULL; git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133196 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 9d35438975..74f169626a 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2994,6 +2994,8 @@ def warn_runsigned_always_true_comparison : Warning< def warn_comparison_of_mixed_enum_types : Warning< "comparison of two values with different enumeration types (%0 and %1)">, InGroup>; +def warn_null_in_arithmetic_operation : Warning< + "use of NULL in arithmetic operation">; def err_invalid_this_use : Error< "invalid use of 'this' outside of a nonstatic member function">; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 76612cd6d8..2c988d15e3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -8925,6 +8925,60 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, rhs = move(resolvedRHS); } + bool LeftNull = Expr::NPCK_GNUNull == + lhs.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull); + bool RightNull = Expr::NPCK_GNUNull == + rhs.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull); + + // Detect when a NULL constant is used improperly in an expression. These + // are mainly cases where the null pointer is used as an integer instead + // of a pointer. + if (LeftNull || RightNull) { + if (Opc == BO_Mul || Opc == BO_Div || Opc == BO_Rem || Opc == BO_Add || + Opc == BO_Sub || Opc == BO_Shl || Opc == BO_Shr || Opc == BO_And || + Opc == BO_Xor || Opc == BO_Or || Opc == BO_MulAssign || + Opc == BO_DivAssign || Opc == BO_AddAssign || Opc == BO_SubAssign || + Opc == BO_RemAssign || Opc == BO_ShlAssign || Opc == BO_ShrAssign || + Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign) { + // These are the operations that would not make sense with a null pointer + // no matter what the other expression is. + if (LeftNull && RightNull) { + Diag(OpLoc, diag::warn_null_in_arithmetic_operation) + << lhs.get()->getSourceRange() << rhs.get()->getSourceRange(); + } else if (LeftNull) { + Diag(OpLoc, diag::warn_null_in_arithmetic_operation) + << lhs.get()->getSourceRange(); + } else if (RightNull) { + Diag(OpLoc, diag::warn_null_in_arithmetic_operation) + << rhs.get()->getSourceRange(); + } + } else if (Opc == BO_LE || Opc == BO_LT || Opc == BO_GE || Opc == BO_GT || + Opc == BO_EQ || Opc == BO_NE) { + // These are the operations that would not make sense with a null pointer + // if the other expression the other expression is not a pointer. + QualType LeftType = lhs.get()->getType(); + QualType RightType = rhs.get()->getType(); + bool LeftPointer = LeftType->isPointerType() || + LeftType->isBlockPointerType() || + LeftType->isMemberPointerType() || + LeftType->isObjCObjectPointerType(); + bool RightPointer = RightType->isPointerType() || + RightType->isBlockPointerType() || + RightType->isMemberPointerType() || + RightType->isObjCObjectPointerType(); + if ((LeftNull != RightNull) && !LeftPointer && !RightPointer) { + if (LeftNull) + Diag(OpLoc, diag::warn_null_in_arithmetic_operation) + << lhs.get()->getSourceRange(); + if (RightNull) + Diag(OpLoc, diag::warn_null_in_arithmetic_operation) + << rhs.get()->getSourceRange(); + } + } + } + switch (Opc) { case BO_Assign: ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, QualType()); diff --git a/test/SemaCXX/null_in_arithmetic_ops.cpp b/test/SemaCXX/null_in_arithmetic_ops.cpp new file mode 100644 index 0000000000..547c936c3e --- /dev/null +++ b/test/SemaCXX/null_in_arithmetic_ops.cpp @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s +#include + +void f() { + int a; + bool b; + + a = 0 ? NULL + a : a + NULL; // expected-warning 2{{use of NULL in arithmetic operation}} + a = 0 ? NULL - a : a - NULL; // expected-warning 2{{use of NULL in arithmetic operation}} + a = 0 ? NULL / a : a / NULL; // expected-warning 2{{use of NULL in arithmetic operation}} \ + // expected-warning {{division by zero is undefined}} + a = 0 ? NULL * a : a * NULL; // expected-warning 2{{use of NULL in arithmetic operation}} + a = 0 ? NULL >> a : a >> NULL; // expected-warning 2{{use of NULL in arithmetic operation}} + a = 0 ? NULL << a : a << NULL; // expected-warning 2{{use of NULL in arithmetic operation}} + a = 0 ? NULL % a : a % NULL; // expected-warning 2{{use of NULL in arithmetic operation}} \ + expected-warning {{remainder by zero is undefined}} + a = 0 ? NULL & a : a & NULL; // expected-warning 2{{use of NULL in arithmetic operation}} + a = 0 ? NULL | a : a | NULL; // expected-warning 2{{use of NULL in arithmetic operation}} + a = 0 ? NULL ^ a : a ^ NULL; // expected-warning 2{{use of NULL in arithmetic operation}} + + // Using two NULLs should only give one error instead of two. + a = NULL + NULL; // expected-warning{{use of NULL in arithmetic operation}} + a = NULL - NULL; // expected-warning{{use of NULL in arithmetic operation}} + a = NULL / NULL; // expected-warning{{use of NULL in arithmetic operation}} \ + // expected-warning{{division by zero is undefined}} + a = NULL * NULL; // expected-warning{{use of NULL in arithmetic operation}} + a = NULL >> NULL; // expected-warning{{use of NULL in arithmetic operation}} + a = NULL << NULL; // expected-warning{{use of NULL in arithmetic operation}} + a = NULL % NULL; // expected-warning{{use of NULL in arithmetic operation}} \ + // expected-warning{{remainder by zero is undefined}} + a = NULL & NULL; // expected-warning{{use of NULL in arithmetic operation}} + a = NULL | NULL; // expected-warning{{use of NULL in arithmetic operation}} + a = NULL ^ NULL; // expected-warning{{use of NULL in arithmetic operation}} + + a += NULL; // expected-warning{{use of NULL in arithmetic operation}} + a -= NULL; // expected-warning{{use of NULL in arithmetic operation}} + a /= NULL; // expected-warning{{use of NULL in arithmetic operation}} \ + // expected-warning{{division by zero is undefined}} + a *= NULL; // expected-warning{{use of NULL in arithmetic operation}} + a >>= NULL; // expected-warning{{use of NULL in arithmetic operation}} + a <<= NULL; // expected-warning{{use of NULL in arithmetic operation}} + a %= NULL; // expected-warning{{use of NULL in arithmetic operation}} \ + // expected-warning{{remainder by zero is undefined}} + a &= NULL; // expected-warning{{use of NULL in arithmetic operation}} + a |= NULL; // expected-warning{{use of NULL in arithmetic operation}} + a ^= NULL; // expected-warning{{use of NULL in arithmetic operation}} + + b = a < NULL || NULL < a; // expected-warning 2{{use of NULL in arithmetic operation}} + b = a > NULL || NULL > a; // expected-warning 2{{use of NULL in arithmetic operation}} + b = a <= NULL || NULL <= a; // expected-warning 2{{use of NULL in arithmetic operation}} + b = a >= NULL || NULL >= a; // expected-warning 2{{use of NULL in arithmetic operation}} + b = a == NULL || NULL == a; // expected-warning 2{{use of NULL in arithmetic operation}} + b = a != NULL || NULL != a; // expected-warning 2{{use of NULL in arithmetic operation}} + + b = &a < NULL || NULL < &a || &a > NULL || NULL > &a; + b = &a <= NULL || NULL <= &a || &a >= NULL || NULL >= &a; + b = &a == NULL || NULL == &a || &a != NULL || NULL != &a; + + b = 0 == a; + b = 0 == &a; + + b = ((NULL)) != a; // expected-warning{{use of NULL in arithmetic operation}} + + void (^c)(); + b = c == NULL || NULL == c || c != NULL || NULL != c; + + class X; + void (X::*d) (); + b = d == NULL || NULL == d || d != NULL || NULL != d; +} diff --git a/test/SemaCXX/nullptr_in_arithmetic_ops.cpp b/test/SemaCXX/nullptr_in_arithmetic_ops.cpp new file mode 100644 index 0000000000..350d18a13f --- /dev/null +++ b/test/SemaCXX/nullptr_in_arithmetic_ops.cpp @@ -0,0 +1,65 @@ +// RUN: %clang_cc1 -fsyntax-only -fblocks -std=c++0x -verify %s + +void f() { + int a; + bool b; + + a = 0 ? nullptr + a : a + nullptr; // expected-error 2{{invalid operands to binary expression}} + a = 0 ? nullptr - a : a - nullptr; // expected-error 2{{invalid operands to binary expression}} + a = 0 ? nullptr / a : a / nullptr; // expected-error 2{{invalid operands to binary expression}} + a = 0 ? nullptr * a : a * nullptr; // expected-error 2{{invalid operands to binary expression}} + a = 0 ? nullptr >> a : a >> nullptr; // expected-error 2{{invalid operands to binary expression}} + a = 0 ? nullptr << a : a << nullptr; // expected-error 2{{invalid operands to binary expression}} + a = 0 ? nullptr % a : a % nullptr; // expected-error 2{{invalid operands to binary expression}} + a = 0 ? nullptr & a : a & nullptr; // expected-error 2{{invalid operands to binary expression}} + a = 0 ? nullptr | a : a | nullptr; // expected-error 2{{invalid operands to binary expression}} + a = 0 ? nullptr ^ a : a ^ nullptr; // expected-error 2{{invalid operands to binary expression}} + + // Using two nullptrs should only give one error instead of two. + a = nullptr + nullptr; // expected-error{{invalid operands to binary expression}} + a = nullptr - nullptr; // expected-error{{invalid operands to binary expression}} + a = nullptr / nullptr; // expected-error{{invalid operands to binary expression}} + a = nullptr * nullptr; // expected-error{{invalid operands to binary expression}} + a = nullptr >> nullptr; // expected-error{{invalid operands to binary expression}} + a = nullptr << nullptr; // expected-error{{invalid operands to binary expression}} + a = nullptr % nullptr; // expected-error{{invalid operands to binary expression}} + a = nullptr & nullptr; // expected-error{{invalid operands to binary expression}} + a = nullptr | nullptr; // expected-error{{invalid operands to binary expression}} + a = nullptr ^ nullptr; // expected-error{{invalid operands to binary expression}} + + a += nullptr; // expected-error{{invalid operands to binary expression}} + a -= nullptr; // expected-error{{invalid operands to binary expression}} + a /= nullptr; // expected-error{{invalid operands to binary expression}} + a *= nullptr; // expected-error{{invalid operands to binary expression}} + a >>= nullptr; // expected-error{{invalid operands to binary expression}} + a <<= nullptr; // expected-error{{invalid operands to binary expression}} + a %= nullptr; // expected-error{{invalid operands to binary expression}} + a &= nullptr; // expected-error{{invalid operands to binary expression}} + a |= nullptr; // expected-error{{invalid operands to binary expression}} + a ^= nullptr; // expected-error{{invalid operands to binary expression}} + + b = a < nullptr || nullptr < a; // expected-error 2{{invalid operands to binary expression}} + b = a > nullptr || nullptr > a; // expected-error 2{{invalid operands to binary expression}} + b = a <= nullptr || nullptr <= a; // expected-error 2{{invalid operands to binary expression}} + b = a >= nullptr || nullptr >= a; // expected-error 2{{invalid operands to binary expression}} + b = a == nullptr || nullptr == a; // expected-error 2{{invalid operands to binary expression}} + b = a != nullptr || nullptr != a; // expected-error 2{{invalid operands to binary expression}} + + b = &a < nullptr || nullptr < &a || &a > nullptr || nullptr > &a; + b = &a <= nullptr || nullptr <= &a || &a >= nullptr || nullptr >= &a; + b = &a == nullptr || nullptr == &a || &a != nullptr || nullptr != &a; + + b = 0 == a; + b = 0 == &a; + + b = ((nullptr)) != a; // expected-error{{invalid operands to binary expression}} + + void (^c)(); + c = nullptr; + b = c == nullptr || nullptr == c || c != nullptr || nullptr != c; + + class X; + void (X::*d) (); + d = nullptr; + b = d == nullptr || nullptr == d || d != nullptr || nullptr != d; +} diff --git a/test/SemaObjCXX/null_objc_pointer.mm b/test/SemaObjCXX/null_objc_pointer.mm new file mode 100644 index 0000000000..1dadabef29 --- /dev/null +++ b/test/SemaObjCXX/null_objc_pointer.mm @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +#define NULL __null + +@interface X +@end + +void f() { + bool b; + X *d; + b = d < NULL || NULL < d || d > NULL || NULL > d; + b = d <= NULL || NULL <= d || d >= NULL || NULL >= d; + b = d == NULL || NULL == d || d != NULL || NULL != d; +}