From dfc1e31d49fe1380c9bab43373995df5fed15e6d Mon Sep 17 00:00:00 2001 From: Jamie Schmeiser Date: Tue, 11 May 2021 11:29:50 -0400 Subject: [PATCH] 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. Reuse existing warning that this is undefined behaviour. Also add unit test for both warnings. Reformat to satisfy clang-format. Respond to review comments: add additional test. Respond to review comments: Do not issue warning for nullptr - nullptr in C++. Fix indenting to satisfy clang-format. Respond to review comments: Add C++ tests. Author: Jamie Schmeiser Reviewed By: efriedma (Eli Friedman), nickdesaulniers (Nick Desaulniers) Differential Revision: https://reviews.llvm.org/D98798 --- clang/lib/Sema/SemaExpr.cpp | 12 +++++++++++- clang/test/Sema/pointer-addition.c | 3 +++ clang/test/Sema/pointer-addition.cpp | 8 ++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 clang/test/Sema/pointer-addition.cpp diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 73d7675eb189f..1390c17de9ece 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -10779,7 +10779,17 @@ 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 should produce + // a warning expect nullptr - nullptr is valid in C++ [expr.add]p7 + if (LHSIsNullPtr && (!getLangOpts().CPlusPlus || !RHSIsNullPtr)) + diagnoseArithmeticOnNullPointer(*this, Loc, LHS.get(), false); + if (RHSIsNullPtr && (!getLangOpts().CPlusPlus || !LHSIsNullPtr)) + diagnoseArithmeticOnNullPointer(*this, Loc, RHS.get(), false); // 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 diff --git a/clang/test/Sema/pointer-addition.c b/clang/test/Sema/pointer-addition.c index 562f05340f7cb..ab641bd132363 100644 --- a/clang/test/Sema/pointer-addition.c +++ b/clang/test/Sema/pointer-addition.c @@ -29,4 +29,7 @@ void a(S* b, void* c) { // Cases that don't match the GNU inttoptr idiom get a different warning. f = (char*)0 - i; // expected-warning {{performing pointer arithmetic on a null pointer has undefined behavior}} int *g = (int*)0 + i; // expected-warning {{performing pointer arithmetic on a null pointer has undefined behavior}} + f = (char*)((char*)0 - f); // expected-warning {{performing pointer arithmetic on a null pointer has undefined behavior}} + f = (char*)(f - (char*)0); // expected-warning {{performing pointer arithmetic on a null pointer has undefined behavior}} + f = (char*)((char*)0 - (char*)0); // expected-warning {{performing pointer arithmetic on a null pointer has undefined behavior}} expected-warning {{performing pointer arithmetic on a null pointer has undefined behavior}} } diff --git a/clang/test/Sema/pointer-addition.cpp b/clang/test/Sema/pointer-addition.cpp new file mode 100644 index 0000000000000..5e09034ed9651 --- /dev/null +++ b/clang/test/Sema/pointer-addition.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wextra -std=c++11 + +void a() { + char *f = (char*)0; + f = (char*)((char*)0 - f); // expected-warning {{performing pointer arithmetic on a null pointer has undefined behavior}} + f = (char*)(f - (char*)0); // expected-warning {{performing pointer arithmetic on a null pointer has undefined behavior}} + f = (char*)((char*)0 - (char*)0); // valid in C++ +}