https://github.com/keepyixiao updated 
https://github.com/llvm/llvm-project/pull/224549

>From 6e031df77e6151d688e876476498bca08915cbf9 Mon Sep 17 00:00:00 2001
From: nudt_yixiao <[email protected]>
Date: Thu, 1 Oct 2026 17:56:25 +0800
Subject: [PATCH] [Clang] Fix crash in alignment builtins with base-less
 pointers

Avoid querying base alignment for pointers without an underlying object
during constant evaluation.

Null pointers are handled as always aligned values, while other
base-less pointers are rejected rather than interpreted using their
numeric address.

Add regression tests for null and integer-derived pointer operands.
---
 clang/docs/ReleaseNotes.md               |  4 ++++
 clang/lib/AST/ByteCode/InterpBuiltin.cpp | 16 +++++++++++++++
 clang/lib/AST/ExprConstant.cpp           | 26 ++++++++++++++++++++++++
 clang/test/Sema/builtin-align.c          | 21 +++++++++++++++++++
 clang/test/SemaCXX/builtin-align-cxx.cpp |  9 ++++++++
 5 files changed, 76 insertions(+)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index bf190df9769dd..28189cbac3883 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -595,6 +595,10 @@ features cannot lower the translation-unit ABI level;
   reference to a vector type; `vec_step` (in C++ for OpenCL) and
   `__builtin_ptrauth_type_discriminator` similarly no longer accept reference
   types that their evaluation silently mishandled. (#GH216997)
+- Fixed a crash when constant-evaluating `__builtin_align_up`, 
`__builtin_align_down`,
+  or `__builtin_is_aligned` with pointers without an underlying object. Null 
pointers 
+  are handled as aligned values, while other base-less pointers are rejected 
during constant
+  evaluation.
 
 #### Bug Fixes to Attribute Support
 
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp 
b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 3303a56f2c053..cd275cc931804 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1319,6 +1319,22 @@ static bool 
interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC,
   }
   assert(FirstArgT == PT_Ptr);
   const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+  // Null pointers are always aligned. Preserve null pointers for
+  // align_up/align_down and return true for is_aligned.
+  if (Ptr.isZero()) {
+    if (BuiltinOp == Builtin::BI__builtin_is_aligned) {
+      S.Stk.push<Boolean>(true);
+      return true;
+    }
+
+    assert(BuiltinOp == Builtin::BI__builtin_align_up ||
+           BuiltinOp == Builtin::BI__builtin_align_down);
+
+    S.Stk.push<Pointer>(Ptr);
+    return true;
+  }
+
   if (!Ptr.isBlockPointer() && !Ptr.isOpaquePointer()) {
     S.FFDiag(Call->getArg(0), diag::note_constexpr_alignment_compute)
         << Alignment;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 91bbc6ef3c9c2..119e8aedab9d7 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -10692,6 +10692,20 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const 
CallExpr *E,
     if (!getAlignmentArgument(E->getArg(1), E->getArg(0)->getType(), Info,
                               Alignment))
       return false;
+
+    if (!Result.Base) {
+      // Null pointers are always aligned and align_up/align_down preserve 
null.
+      if (Result.Offset.isZero())
+        return true;
+
+      // Non-null pointers without a base (for example, integer-to-pointer
+      // casts such as (void *)32) do not have enough information to perform
+      // pointer arithmetic during constant evaluation.
+      Info.FFDiag(E->getArg(0), diag::note_constexpr_alignment_adjust)
+          << Alignment;
+      return false;
+    }
+
     CharUnits BaseAlignment = getBaseAlignment(Info, Result);
     CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(Result.Offset);
     // For align_up/align_down, we can return the same value if the alignment
@@ -17079,6 +17093,18 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const 
CallExpr *E,
       // If we evaluated a pointer, check the minimum known alignment.
       LValue Ptr;
       Ptr.setFrom(Info.Ctx, Src);
+      if (!Ptr.Base) {
+        // Null pointers are always aligned.
+        if (Ptr.Offset.isZero())
+          return Success(1, E);
+
+        Info.FFDiag(E->getArg(0), diag::note_constexpr_alignment_compute)
+            << Alignment;
+        // Reject non-null pointers without an underlying object.
+        // Do not interpret the pointer offset as an integer address.
+        return false;
+      }
+
       CharUnits BaseAlignment = getBaseAlignment(Info, Ptr);
       CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(Ptr.Offset);
       // We can return true if the known alignment at the computed offset is
diff --git a/clang/test/Sema/builtin-align.c b/clang/test/Sema/builtin-align.c
index c33ad8d1ad0ef..080b77598886a 100644
--- a/clang/test/Sema/builtin-align.c
+++ b/clang/test/Sema/builtin-align.c
@@ -115,6 +115,12 @@ void constant_expression(int x) {
   _Static_assert(!__builtin_is_aligned(256, 512ULL), "");
   _Static_assert(__builtin_align_up(33, 32) == 64, "");
   _Static_assert(__builtin_align_down(33, 32) == 32, "");
+  _Static_assert(__builtin_is_aligned((void *)0, 1), "");    // 
expected-warning {{checking whether a value is aligned to 1 byte is always 
true}}
+  _Static_assert(__builtin_is_aligned((void *)0, 32), "");
+  _Static_assert(__builtin_is_aligned((void *)32, 32), "");  // expected-error 
{{static assertion expression is not an integral constant expression}}
+  // expected-note@-1 {{cannot constant evaluate whether run-time alignment is 
at least 32}}
+  _Static_assert(!__builtin_is_aligned((void *)32, 64), ""); // expected-error 
{{static assertion expression is not an integral constant expression}}
+  // expected-note@-1 {{cannot constant evaluate whether run-time alignment is 
at least 64}}
 
   // But not if one of the arguments isn't constant:
   _Static_assert(ALIGN_BUILTIN(33, x) != 100, ""); // expected-error {{static 
assertion expression is not an integral constant expression}}
@@ -125,6 +131,21 @@ void constant_expression(int x) {
 int global1 = __builtin_align_down(33, 8);
 int global2 = __builtin_align_up(33, 8);
 _Bool global3 = __builtin_is_aligned(33, 8);
+_Bool global4 = __builtin_is_aligned((void *)33, 8);  // expected-error 
{{initializer element is not a compile-time constant}}
+_Bool global5 = __builtin_is_aligned((void *)32, 32); // expected-error 
{{initializer element is not a compile-time constant}}
+_Bool global6 = __builtin_is_aligned((void *)32, 64); // expected-error 
{{initializer element is not a compile-time constant}}
+
+// Zero-valued null pointers are already aligned and should remain unchanged.
+void *null_align_up_1 = __builtin_align_up((void *)0, 1);     // 
expected-warning {{aligning a value to 1 byte is a no-op}}
+void *null_align_up_32 = __builtin_align_up((void *)0, 32);
+void *null_align_down_1 = __builtin_align_down((void *)0, 1); // 
expected-warning {{aligning a value to 1 byte is a no-op}}
+void *null_align_down_32 = __builtin_align_down((void *)0, 32);
+
+// Check alignment builtins with non-zero integer-derived pointers.
+void *num_align_up_32 = __builtin_align_up((void *)32, 32);     // 
expected-error {{initializer element is not a compile-time constant}}
+void *num_align_up_64 = __builtin_align_up((void *)32, 64);     // 
expected-error {{initializer element is not a compile-time constant}}
+void *num_align_down_32 = __builtin_align_down((void *)32, 32); // 
expected-error {{initializer element is not a compile-time constant}}
+void *num_align_down_64 = __builtin_align_down((void *)32, 64); // 
expected-error {{initializer element is not a compile-time constant}}
 
 extern void test_ptr(char *c);
 char *test_array_and_fnptr(void) {
diff --git a/clang/test/SemaCXX/builtin-align-cxx.cpp 
b/clang/test/SemaCXX/builtin-align-cxx.cpp
index 51e610ccc0cd1..d1feb0661b5b9 100644
--- a/clang/test/SemaCXX/builtin-align-cxx.cpp
+++ b/clang/test/SemaCXX/builtin-align-cxx.cpp
@@ -248,3 +248,12 @@ _Alignas(void) char align_void_array[1]; // expected-error 
{{invalid application
 
 static_assert(!__builtin_is_aligned(&"", 4), ""); // expected-error {{not an 
integral constant expression}} \
                                                   // expected-note {{cannot 
constant evaluate whether run-time alignment is at least 4}}
+
+static_assert(__builtin_is_aligned((void *)0, 1), "");    // expected-warning 
{{checking whether a value is aligned to 1 byte is always true}}
+static_assert(__builtin_is_aligned((void *)0, 32), "");   
+
+// Zero-valued null pointers are already aligned and should remain unchanged.
+void *null_align_up_1 = __builtin_align_up((void *)0, 1);     // 
expected-warning {{aligning a value to 1 byte is a no-op}}
+void *null_align_up_32 = __builtin_align_up((void *)0, 32);
+void *null_align_down_1 = __builtin_align_down((void *)0, 1); // 
expected-warning {{aligning a value to 1 byte is a no-op}}
+void *null_align_down_32 = __builtin_align_down((void *)0, 32);

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to