https://github.com/keepyixiao updated https://github.com/llvm/llvm-project/pull/224549
>From 94947c102f1aa5300f1f571fc7957c68de948d6d Mon Sep 17 00:00:00 2001 From: yixiao <[email protected]> Date: Fri, 18 Sep 2026 15:50:42 +0800 Subject: [PATCH] [Clang] Fix crash in alignment builtins with null pointers 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. --- clang/docs/ReleaseNotes.md | 2 ++ clang/lib/AST/ExprConstant.cpp | 29 +++++++++++++++++++++++++++++ clang/test/Sema/builtin-align.c | 21 +++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index f4a34a37aff52..48a3a75514eba 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -562,6 +562,8 @@ 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 a null pointer. (#GH224549) #### Bug Fixes to Attribute Support 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..47b3172672f66 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-warning {{expression is not an integer constant expression; folding it to a constant is a GNU extension}} + // expected-note@-1 {{this conversion is not allowed in a constant expression}} + _Static_assert(!__builtin_is_aligned((void *)32, 64), ""); // expected-warning {{expression is not an integer constant expression; folding it to a constant is a GNU extension}} + // expected-note@-1 {{this conversion is not allowed in a constant expression}} // 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); +_Bool global5 = __builtin_is_aligned((void *)32, 32); +_Bool global6 = __builtin_is_aligned((void *)32, 64); + +// 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); +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); +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) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
