From 4c8cb14c1ab0abe44bef7b19e53671d28685372b Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 23 Oct 2014 19:00:10 +0000 Subject: [PATCH] patch to issue warning on comparing parameters with nonnull attribute when comparison is always true/false. Patch by Steven Wu with few fixes and minor refactoring and adding tests by me. rdar://18712242 llvm-svn: 220496 --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 8 ++++++ clang/lib/Sema/SemaChecking.cpp | 32 +++++++++++++++++++++++- clang/test/Sema/nonnull.c | 25 ++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e6ad4b5..8197f7d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2500,6 +2500,10 @@ def warn_impcast_pointer_to_bool : Warning< "address of%select{| function| array}0 '%1' will always evaluate to " "'true'">, InGroup; +def warn_cast_nonnull_to_bool : Warning< + "nonnull parameter '%0' will always evaluate to " + "'true'">, + InGroup; def warn_this_bool_conversion : Warning< "'this' pointer cannot be null in well-defined C++ code; pointer may be " "assumed to always convert to true">, InGroup; @@ -2512,6 +2516,10 @@ def warn_null_pointer_compare : Warning< "comparison of %select{address of|function|array}0 '%1' %select{not |}2" "equal to a null pointer is always %select{true|false}2">, InGroup; +def warn_nonnull_parameter_compare : Warning< + "comparison of nonnull parameter '%0' %select{not |}1" + "equal to a null pointer is always %select{true|false}1">, + InGroup; def warn_this_null_compare : Warning< "'this' pointer cannot be null in well-defined C++ code; comparison may be " "assumed to always evaluate to %select{true|false}0">, diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index fd2fa0c..495fa32 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -6678,7 +6678,37 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, // Weak Decls can be null. if (!D || D->isWeak()) return; - + // Check for parameter decl with nonnull attribute + if (ParmVarDecl* PV = dyn_cast(D)) { + if (FunctionDecl* FD = dyn_cast(PV->getDeclContext())) { + unsigned NumArgs = FD->getNumParams(); + llvm::SmallBitVector AttrNonNull(NumArgs); + for (const auto *NonNull : FD->specific_attrs()) { + if (!NonNull->args_size()) { + AttrNonNull.set(0, NumArgs); + break; + } + for (unsigned Val : NonNull->args()) { + if (Val >= NumArgs) + continue; + AttrNonNull.set(Val); + } + } + if (!AttrNonNull.empty()) + for (unsigned i = 0; i < NumArgs; ++i) + if (FD->getParamDecl(i) == PV && AttrNonNull[i]) { + std::string Str; + llvm::raw_string_ostream S(Str); + E->printPretty(S, nullptr, getPrintingPolicy()); + unsigned DiagID = IsCompare ? diag::warn_nonnull_parameter_compare + : diag::warn_cast_nonnull_to_bool; + Diag(E->getExprLoc(), DiagID) << S.str() << E->getSourceRange() + << Range << IsEqual; + return; + } + } + } + QualType T = D->getType(); const bool IsArray = T->isArrayType(); const bool IsFunction = T->isFunctionType(); diff --git a/clang/test/Sema/nonnull.c b/clang/test/Sema/nonnull.c index 3b654a8..53f94dd 100644 --- a/clang/test/Sema/nonnull.c +++ b/clang/test/Sema/nonnull.c @@ -83,3 +83,28 @@ void redecl_test(void *p) { redecl(p, 0); // expected-warning{{null passed}} redecl(0, p); // expected-warning{{null passed}} } + +// rdar://18712242 +#define NULL (void*)0 +__attribute__((__nonnull__)) +int evil_nonnull_func(int* pointer, void * pv) +{ + if (pointer == NULL) { // expected-warning {{comparison of nonnull parameter 'pointer' equal to a null pointer is always false}} + return 0; + } else { + return *pointer; + } + + if (pv == NULL) {} // expected-warning {{comparison of nonnull parameter 'pv' equal to a null pointer is always false}} +} + +int another_evil_nonnull_func(int* pointer, char ch, void * pv) __attribute__((nonnull(1, 3))); +int another_evil_nonnull_func(int* pointer, char ch, void * pv) { + if (pointer == NULL) { // expected-warning {{comparison of nonnull parameter 'pointer' equal to a null pointer is always false}} + return 0; + } else { + return *pointer; + } + + if (pv == NULL) {} // expected-warning {{comparison of nonnull parameter 'pv' equal to a null pointer is always false}} +} -- 2.7.4