[clang] [clang][Interp] Only diagnose null field access in constant contexts (PR #69223)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 16 10:03:15 PDT 2023


Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>
Message-ID:
In-Reply-To: <llvm/llvm-project/pull/69223/clang at github.com>


https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/69223

>From 8f92935def398da8de21146e4e308a49746ae320 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Mon, 16 Oct 2023 17:51:44 +0200
Subject: [PATCH 1/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 e3e6a4cec63b194..8c943a48cdcc0ac 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 3c866825d1f077c..0c341a62c89fa13 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -1089,3 +1089,36 @@ namespace DelegatingConstructors {
   static_assert(d4.a == 10, "");
   static_assert(d4.b == 12, "");
 }
+
+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()'}}
+}

>From e59c068eb2c9c0a50f70928964e518958b95434b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Mon, 16 Oct 2023 19:02:50 +0200
Subject: [PATCH 2/2] Cast pointers to intptr_t instead of long

---
 clang/test/AST/Interp/c.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c
index 637915328576af1..e980cf9d963224e 100644
--- a/clang/test/AST/Interp/c.c
+++ b/clang/test/AST/Interp/c.c
@@ -3,6 +3,8 @@
 // RUN: %clang_cc1 -verify=ref -std=c11 %s
 // RUN: %clang_cc1 -pedantic -verify=pedantic-ref -std=c11 %s
 
+typedef __INTPTR_TYPE__ intptr_t;
+
 _Static_assert(1, "");
 _Static_assert(0 != 1, "");
 _Static_assert(1.0 == 1.0, ""); // pedantic-ref-warning {{not an integer constant expression}} \
@@ -49,13 +51,13 @@ _Static_assert(&a != 0, ""); // ref-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}}
+int a2[(intptr_t)&((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}}
+const intptr_t L = (intptr_t)(&(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}}



More information about the cfe-commits mailing list