Reland Produce warning for performing pointer arithmetic on a null pointer.

Summary:
Test and produce warning for subtracting a pointer from null or subtracting
null from a pointer.

This reland adds the functionality that the warning is no longer reusing an
existing warning, it has different wording for C vs C++ to refect the fact
that nullptr-nullptr has defined behaviour in C++,  it is suppressed
when the warning is triggered by a system header and adds
-Wnull-pointer-subtraction to allow the warning to be controlled.  -Wextra
implies -Wnull-pointer-subtraction.

Author: Jamie Schmeiser <schmeise@ca.ibm.com>
Reviewed By: efriedma (Eli Friedman), nickdesaulniers (Nick Desaulniers)
Differential Revision: https://reviews.llvm.org/D98798
This commit is contained in:
Jamie Schmeiser 2021-07-20 10:12:20 -04:00
parent 02cd937945
commit 9cb00b9ecb
7 changed files with 74 additions and 1 deletions

View File

@ -76,6 +76,9 @@ New Compiler Flags
file contains frame size information for each function defined in the source
file.
- ``-Wnull-pointer-subtraction`` emits warning when user code may have
undefined behaviour due to subtraction involving a null pointer.
Deprecated Compiler Flags
-------------------------
@ -92,6 +95,7 @@ Modified Compiler Flags
instead. ``-B``'s other GCC-compatible semantics are preserved:
``$prefix/$triple-$file`` and ``$prefix$file`` are searched for executables,
libraries, includes, and data files used by the compiler.
- ``-Wextra`` now also implies ``-Wnull-pointer-subtraction.``
Removed Compiler Flags
-------------------------

View File

@ -487,6 +487,7 @@ def ClassVarargs : DiagGroup<"class-varargs", [NonPODVarargs]>;
def : DiagGroup<"nonportable-cfstrings">;
def NonVirtualDtor : DiagGroup<"non-virtual-dtor">;
def NullPointerArithmetic : DiagGroup<"null-pointer-arithmetic">;
def NullPointerSubtraction : DiagGroup<"null-pointer-subtraction">;
def : DiagGroup<"effc++", [NonVirtualDtor]>;
def OveralignedType : DiagGroup<"over-aligned">;
def OldStyleCast : DiagGroup<"old-style-cast">;
@ -932,6 +933,7 @@ def Extra : DiagGroup<"extra", [
UnusedParameter,
UnusedButSetParameter,
NullPointerArithmetic,
NullPointerSubtraction,
EmptyInitStatement,
StringConcatation,
FUseLdPath,

View File

@ -6390,6 +6390,9 @@ def warn_pointer_arith_null_ptr : Warning<
def warn_gnu_null_ptr_arith : Warning<
"arithmetic on a null pointer treated as a cast from integer to pointer is a GNU extension">,
InGroup<NullPointerArithmetic>, DefaultIgnore;
def warn_pointer_sub_null_ptr : Warning<
"performing pointer subtraction with a null pointer %select{has|may have}0 undefined behavior">,
InGroup<NullPointerSubtraction>, DefaultIgnore;
def err_kernel_invalidates_sycl_unique_stable_name
: Error<"kernel instantiation changes the result of an evaluated "
"'__builtin_sycl_unique_stable_name'">;

View File

@ -10432,6 +10432,22 @@ static void diagnoseArithmeticOnNullPointer(Sema &S, SourceLocation Loc,
<< S.getLangOpts().CPlusPlus << Pointer->getSourceRange();
}
/// Diagnose invalid subraction on a null pointer.
///
static void diagnoseSubtractionOnNullPointer(Sema &S, SourceLocation Loc,
Expr *Pointer, bool BothNull) {
// Null - null is valid in C++ [expr.add]p7
if (BothNull && S.getLangOpts().CPlusPlus)
return;
// Is this s a macro from a system header?
if (S.Diags.getSuppressSystemWarnings() && S.SourceMgr.isInSystemMacro(Loc))
return;
S.Diag(Loc, diag::warn_pointer_sub_null_ptr)
<< S.getLangOpts().CPlusPlus << Pointer->getSourceRange();
}
/// Diagnose invalid arithmetic on two function pointers.
static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc,
Expr *LHS, Expr *RHS) {
@ -10863,7 +10879,16 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
LHS.get(), RHS.get()))
return QualType();
// FIXME: Add warnings for nullptr - ptr.
bool LHSIsNullPtr = LHS.get()->IgnoreParenCasts()->isNullPointerConstant(
Context, Expr::NPC_ValueDependentIsNotNull);
bool RHSIsNullPtr = RHS.get()->IgnoreParenCasts()->isNullPointerConstant(
Context, Expr::NPC_ValueDependentIsNotNull);
// Subtracting nullptr or from nullptr is suspect
if (LHSIsNullPtr)
diagnoseSubtractionOnNullPointer(*this, Loc, LHS.get(), RHSIsNullPtr);
if (RHSIsNullPtr)
diagnoseSubtractionOnNullPointer(*this, Loc, RHS.get(), LHSIsNullPtr);
// The pointee type may have zero size. As an extension, a structure or
// union may have zero size or an array may have zero length. In this

View File

@ -0,0 +1 @@
#define SYSTEM_MACRO(x) (x) = (char *)((char *)0 - (x))

View File

@ -0,0 +1,19 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wextra -std=c11 -isystem %S/Inputs
// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wnull-pointer-subtraction -std=c11 -isystem %S/Inputs
// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wextra -std=c11 -isystem %S/Inputs -Wsystem-headers -DSYSTEM_WARNINGS
// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wnull-pointer-subtraction -std=c11 -isystem %S/Inputs -Wsystem-headers -DSYSTEM_WARNINGS
#include <pointer-subtraction.h>
void a() {
char *f = (char *)0;
f = (char *)((char *)0 - f); // expected-warning {{performing pointer subtraction with a null pointer has undefined behavior}}
f = (char *)(f - (char *)0); // expected-warning {{performing pointer subtraction with a null pointer has undefined behavior}}
f = (char *)((char *)0 - (char *)0); // expected-warning {{performing pointer subtraction with a null pointer has undefined behavior}} expected-warning {{performing pointer subtraction with a null pointer has undefined behavior}}
#ifndef SYSTEM_WARNINGS
SYSTEM_MACRO(f);
#else
SYSTEM_MACRO(f); // expected-warning {{performing pointer subtraction with a null pointer has undefined behavior}}
#endif
}

View File

@ -0,0 +1,19 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wextra -std=c++11 -isystem %S/Inputs
// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wnull-pointer-subtraction -std=c++11 -isystem %S/Inputs
// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wextra -std=c++11 -isystem %S/Inputs -Wsystem-headers -DSYSTEM_WARNINGS
// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wnull-pointer-subtraction -std=c++11 -isystem %S/Inputs -Wsystem-headers -DSYSTEM_WARNINGS
#include <pointer-subtraction.h>
void a() {
char *f = (char *)0;
f = (char *)((char *)0 - f); // expected-warning {{performing pointer subtraction with a null pointer may have undefined behavior}}
f = (char *)(f - (char *)0); // expected-warning {{performing pointer subtraction with a null pointer may have undefined behavior}}
f = (char *)((char *)0 - (char *)0); // valid in C++
#ifndef SYSTEM_WARNINGS
SYSTEM_MACRO(f);
#else
SYSTEM_MACRO(f); // expected-warning {{performing pointer subtraction with a null pointer may have undefined behavior}}
#endif
}