[clang] [Clang] Fix crash in alignment builtins with null pointers (PR #224549)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 18 00:59:00 PDT 2026
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
More information about the cfe-commits
mailing list