Skip to content

[clang][ExprConst] Reject field access with nullptr base #113885

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 21, 2024

Conversation

tbaederr
Copy link
Contributor

@tbaederr tbaederr commented Oct 28, 2024

Reject them if the base is null, not only if the entire pointer is null.

Fixes #113821

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Oct 28, 2024
@llvmbot
Copy link
Member

llvmbot commented Oct 28, 2024

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

Changes

Reject them if the base is null, not only if the entire pointer is null.


Full diff: https://github.com/llvm/llvm-project/pull/113885.diff

2 Files Affected:

  • (modified) clang/lib/AST/ExprConstant.cpp (+1-1)
  • (modified) clang/test/CXX/expr/expr.const/p2-0x.cpp (+2-1)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 8e36cad2d2c6e7..a6694bc0641508 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1703,7 +1703,7 @@ namespace {
     bool checkNullPointerDiagnosingWith(const GenDiagType &GenDiag) {
       if (Designator.Invalid)
         return false;
-      if (IsNullPtr) {
+      if (getLValueBase().isNull()) {
         GenDiag();
         Designator.setInvalid();
         return false;
diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp
index 767eee1c74f054..67160ba571f33c 100644
--- a/clang/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp
@@ -188,7 +188,7 @@ namespace UndefinedBehavior {
 
   namespace Ptr {
     struct A {};
-    struct B : A { int n; };
+    struct B : A { int n; int m; };
     B a[3][3];
     constexpr B *p = a[0] + 4; // expected-error {{constant expression}} expected-note {{element 4 of array of 3 elements}}
     B b = {};
@@ -204,6 +204,7 @@ namespace UndefinedBehavior {
     static_assert((A*)nb == 0, "");
     static_assert((B*)na == 0, "");
     constexpr const int &nf = nb->n; // expected-error {{constant expression}} expected-note {{cannot access field of null pointer}}
+    constexpr const int &mf = nb->m; // expected-error {{constant expression}} expected-note {{cannot access field of null pointer}}
     constexpr const int *np1 = (int*)nullptr + 0; // ok
     constexpr const int *np2 = &(*(int(*)[4])nullptr)[0]; // ok
     constexpr const int *np3 = &(*(int(*)[4])nullptr)[2]; // expected-error {{constant expression}} expected-note {{cannot perform pointer arithmetic on null pointer}}

@@ -1703,7 +1703,7 @@ namespace {
bool checkNullPointerDiagnosingWith(const GenDiagType &GenDiag) {
if (Designator.Invalid)
return false;
if (IsNullPtr) {
if (getLValueBase().isNull()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was the old check not good enough here? In the added testcase, nb is a null pointer.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see. We're adjusting the offset before we call addDecl. I think this would be better fixed by reversing the order in which we do those steps -- first addDecl and then adjust the offset. A null base isn't necessarily a null pointer, so checking for a null base here seems wrong (but only in the weird case of a zero integer cast to a non-null pointer value, which we should only accept in constant-folding mode, not when properly evaluating).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The offset is added in adjustOffset(), which calls clearIsNullPointer(). This is called before we call addDecl(), so at that point the pointer is already considered non-null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the check here was !Base until 402804b

@tbaederr
Copy link
Contributor Author

tbaederr commented Nov 5, 2024

Ping

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but the changes should come with a release note.

@tbaederr
Copy link
Contributor Author

tbaederr commented Nov 8, 2024

@zygoloid Do you approve too?

@tbaederr
Copy link
Contributor Author

Ping

@zygoloid
Copy link
Collaborator

As mentioned in the comment thread, I'd prefer to see this addressed by reversing the order in which we call addDecl versus add an offset. While it's a corner case, I think this change would cause us to start rejecting things like this example where we form a non-null pointer with no base in a constant-folded region. Currently, the subsequent member access (->hardware_register_1) is accepted, because it's not accessing a member of a null pointer -- it's accessing a member of an integral non-null pointer.

I don't know how important things like this example are, but they do at least seem useful in some cases.

@tbaederr
Copy link
Contributor Author

I think I understand what you mean by changing the order now. I changed two other places as well, just to be consistent.

Copy link
Collaborator

@zygoloid zygoloid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG, thank you!

@tbaederr tbaederr merged commit 685e41e into llvm:main Nov 21, 2024
9 checks passed
bherrera pushed a commit to misttech/integration that referenced this pull request Dec 6, 2024
After llvm/llvm-project#113885 clang will now
correctly diagnose the use of nullptr in constexpr contexts. Instead,
we can rewrite the check with std::extent_v.

Original-Bug: 381885679
Original-Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/1166981
Original-Revision: 6e83c9357c23aeb49d6808fc84472894ac1ca671
GitOrigin-RevId: 9e5bf26c76114bd573166508f37ace410362a42c
Change-Id: I4027a3c538c4077b812665701d4080c095a8b01c
bherrera pushed a commit to misttech/mist-os that referenced this pull request Dec 6, 2024
After llvm/llvm-project#113885 clang will now
correctly diagnose the use of nullptr in constexpr contexts. Instead,
we can rewrite the check with std::extent_v.

Bug: 381885679
Change-Id: Ib001e61c84e130cbdfb322f44948f58cf64da635
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/1166981
Fuchsia-Auto-Submit: Paul Kirth <[email protected]>
Reviewed-by: Novin Changizi <[email protected]>
Commit-Queue: Auto-Submit <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[ExprConst] Field access resulting in null pointer is diagnosed at compile time
4 participants