llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: nudt_yixiao (keepyixiao)

<details>
<summary>Changes</summary>

Clang can crash when evaluating __builtin_align_up, __builtin_align_down, or 
__builtin_is_aligned with a null pointer.

Handle base-less pointers without querying their base alignment, and use the 
numeric pointer value when possible.

Add regression tests for null pointer operands.

Fixes https://github.com/llvm/llvm-project/issues/216999

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


2 Files Affected:

- (modified) clang/lib/AST/ExprConstant.cpp (+29) 
- (modified) clang/test/Sema/builtin-align.c (+8) 


``````````diff
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 9242491832841..609009187ca46 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -10695,6 +10695,24 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const 
CallExpr *E,
     if (!getAlignmentArgument(E->getArg(1), E->getArg(0)->getType(), Info,
                               Alignment))
       return false;
+
+    // A base-less pointer has a known numeric address stored in Offset, but
+    // there is no underlying object relative to which the pointer can be
+    // adjusted. If the address is already sufficiently aligned, the builtin
+    // is a no-op and the original pointer value can be preserved.
+    if (!Result.Base) {
+      assert(Alignment.getBitWidth() <= 64 &&
+             "Cannot handle > 64-bit address-space");
+      uint64_t Alignment64 = Alignment.getZExtValue();
+      uint64_t PointerValue = Result.Offset.getQuantity();
+      if (llvm::isAligned(llvm::Align(Alignment64), PointerValue))
+        return true;
+
+      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
@@ -17072,6 +17090,17 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const 
CallExpr *E,
       // If we evaluated a pointer, check the minimum known alignment.
       LValue Ptr;
       Ptr.setFrom(Info.Ctx, Src);
+      // Pointers without a base have a known numeric address, so check that
+      // address directly instead of trying to determine a base alignment.
+      if (!Ptr.Base) {
+        assert(Alignment.getBitWidth() <= 64 &&
+               "Cannot handle > 64-bit address-space");
+        uint64_t Alignment64 = Alignment.getZExtValue();
+        uint64_t PointerValue = Ptr.Offset.getQuantity();
+        return Success(
+            llvm::isAligned(llvm::Align(Alignment64), PointerValue) ? 1 : 0, 
E);
+      }
+
       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..524ffeb0f5885 100644
--- a/clang/test/Sema/builtin-align.c
+++ b/clang/test/Sema/builtin-align.c
@@ -115,6 +115,8 @@ 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), "");
 
   // 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}}
@@ -126,6 +128,12 @@ int global1 = __builtin_align_down(33, 8);
 int global2 = __builtin_align_up(33, 8);
 _Bool global3 = __builtin_is_aligned(33, 8);
 
+// 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);
+
 extern void test_ptr(char *c);
 char *test_array_and_fnptr(void) {
   char buf[1024];

``````````

</details>


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

Reply via email to