Timm =?utf-8?q?Bäder?= <tbae...@redhat.com> Message-ID: <llvm/llvm-project/pull/69223/cl...@github.com> In-Reply-To:
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/69223 Looks like this should work as long as we don't dereference the value. Note: This is a change from my local branch where I introduce integral pointers. One thing I changed is that null pointers are integral pointers and not block pointers, but in this version they are still block pointers so we have to be careful about `Pointee` being null. >From b20da36444adfbdbddd6d0dddf06535815ffe0c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Sun, 3 Sep 2023 07:03:04 +0200 Subject: [PATCH 1/2] [clang][Interp] Check pointer inc/dec ops for null --- clang/lib/AST/Interp/Interp.h | 7 +++++-- clang/test/AST/Interp/arrays.cpp | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index e3e6a4cec63b194..3d226a40f9cf608 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1488,11 +1488,14 @@ static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { using OneT = Integral<8, false>; + const Pointer &P = Ptr.deref<Pointer>(); + if (!CheckNull(S, OpPC, P, CSK_ArrayIndex)) + return false; + // Get the current value on the stack. - S.Stk.push<Pointer>(Ptr.deref<Pointer>()); + S.Stk.push<Pointer>(P); // Now the current Ptr again and a constant 1. - Pointer P = Ptr.deref<Pointer>(); OneT One = OneT::from(1); if (!OffsetHelper<OneT, Op>(S, OpPC, One, P)) return false; diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp index 281835f828bbd7c..18c4ae4354f54a0 100644 --- a/clang/test/AST/Interp/arrays.cpp +++ b/clang/test/AST/Interp/arrays.cpp @@ -333,6 +333,26 @@ namespace IncDec { // expected-note {{in call to}} \ // ref-error {{not an integral constant expression}} \ // ref-note {{in call to}} + + constexpr int nullptr1(bool Pre) { + int *a = nullptr; + if (Pre) + ++a; // ref-note {{arithmetic on null pointer}} \ + // expected-note {{arithmetic on null pointer}} + else + a++; // ref-note {{arithmetic on null pointer}} \ + // expected-note {{arithmetic on null pointer}} + return 1; + } + static_assert(nullptr1(true) == 1, ""); // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to}} \ + // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to}} + + static_assert(nullptr1(false) == 1, ""); // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to}} \ + // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to}} }; namespace ZeroInit { >From a1d79cbe5c3ad257b44beb0ba3b8cb3e0dcbe84a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Mon, 16 Oct 2023 17:51:44 +0200 Subject: [PATCH 2/2] [clang][Interp] Only diagnose null field access in constant contexts --- clang/lib/AST/Interp/Interp.h | 2 +- clang/lib/AST/Interp/Pointer.h | 4 +++- clang/test/AST/Interp/c.c | 12 +++++++++++ clang/test/AST/Interp/records.cpp | 33 +++++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 3d226a40f9cf608..9258442aaaa1d4d 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1159,7 +1159,7 @@ inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { /// 2) Pushes Pointer.atField(Off) on the stack inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) { const Pointer &Ptr = S.Stk.pop<Pointer>(); - if (!CheckNull(S, OpPC, Ptr, CSK_Field)) + if (S.inConstantContext() && !CheckNull(S, OpPC, Ptr, CSK_Field)) return false; if (!CheckExtern(S, OpPC, Ptr)) return false; diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index d5279e757f04764..c6a2f371764d02f 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -295,7 +295,7 @@ class Pointer { bool isUnion() const; /// Checks if the storage is extern. - bool isExtern() const { return Pointee->isExtern(); } + bool isExtern() const { return Pointee && Pointee->isExtern(); } /// Checks if the storage is static. bool isStatic() const { return Pointee->isStatic(); } /// Checks if the storage is temporary. @@ -348,6 +348,8 @@ class Pointer { /// Checks if the index is one past end. bool isOnePastEnd() const { + if (!Pointee) + return false; return isElementPastEnd() || getSize() == getOffset(); } diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c index 974ca72702f7dd0..637915328576af1 100644 --- a/clang/test/AST/Interp/c.c +++ b/clang/test/AST/Interp/c.c @@ -47,3 +47,15 @@ _Static_assert(&a != 0, ""); // ref-warning {{always true}} \ // expected-warning {{always true}} \ // pedantic-expected-warning {{always true}} \ // pedantic-expected-warning {{is a GNU extension}} + +struct y {int x,y;}; +int a2[(long)&((struct y*)0)->y]; // expected-warning {{folded to constant array}} \ + // pedantic-expected-warning {{folded to constant array}} \ + // ref-warning {{folded to constant array}} \ + // pedantic-ref-warning {{folded to constant array}} + +const struct y *yy = (struct y*)0; +const long L = (long)(&(yy->y)); // expected-error {{not a compile-time constant}} \ + // pedantic-expected-error {{not a compile-time constant}} \ + // ref-error {{not a compile-time constant}} \ + // pedantic-ref-error {{not a compile-time constant}} diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index bcc84087fc54020..88c9c5ae7db5553 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -1066,3 +1066,36 @@ namespace ParenInit { constexpr B b(A(1),2); } #endif + +namespace AccessOnNullptr { + struct F { + int a; + }; + + constexpr int a() { // expected-error {{never produces a constant expression}} \ + // ref-error {{never produces a constant expression}} + F *f = nullptr; + + f->a = 0; // expected-note 2{{cannot access field of null pointer}} \ + // ref-note 2{{cannot access field of null pointer}} + return f->a; + } + static_assert(a() == 0, ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to 'a()'}} \ + // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to 'a()'}} + + constexpr int a2() { // expected-error {{never produces a constant expression}} \ + // ref-error {{never produces a constant expression}} + F *f = nullptr; + + + const int *a = &(f->a); // expected-note 2{{cannot access field of null pointer}} \ + // ref-note 2{{cannot access field of null pointer}} + return f->a; + } + static_assert(a2() == 0, ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to 'a2()'}} \ + // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to 'a2()'}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits