[clang] [Clang] Diagnose invalid object size kinds during constant evaluation (PR #230979)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 12 04:55:18 PDT 2026
https://github.com/keepyixiao updated https://github.com/llvm/llvm-project/pull/230979
>From 78765d6d13599a325f0760d93875e5fe68aa3a49 Mon Sep 17 00:00:00 2001
From: nudt_yixiao <1272950933 at qq.com>
Date: Sun, 11 Oct 2026 20:40:45 +0800
Subject: [PATCH] [Clang] Diagnose invalid object size kinds during constant
evaluation
Out-of-range type arguments to __builtin_object_size and
__builtin_dynamic_object_size could trigger assertions during constant
evaluation.
Replace the assertions in both constant evaluators with range diagnostics.
Add regression tests for negative and too-large type arguments, covering both
builtins and both constant evaluators.
---
clang/docs/ReleaseNotes.md | 3 +++
.../include/clang/Basic/DiagnosticASTKinds.td | 2 ++
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 18 ++++++++++++------
clang/lib/AST/ExprConstant.cpp | 11 +++++++----
clang/test/Sema/builtin-object-size.c | 2 ++
5 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 77a1e73bc8af6..87744e6d9b4b5 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -693,6 +693,9 @@ features cannot lower the translation-unit ABI level;
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.
+- Fixed an assertion failure when `__builtin_object_size` or
+ `__builtin_dynamic_object_size` is called with an out-of-range type argument
+ during constant evaluation. (#GH225041)
#### Bug Fixes to Attribute Support
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 0aca1f75428f8..dedb1ff2f503b 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -29,6 +29,8 @@ def note_constexpr_invalid_downcast : Note<
"cannot cast object of dynamic type %0 to type %1">;
def note_constexpr_overflow : Note<
"value %0 is outside the range of representable values of type %1">;
+def note_constexpr_builtin_arg_out_of_range : Note<
+ "argument value %0 is outside the valid range [%1, %2]">;
def note_constexpr_offsetof_overflow : Note<
"overflow in offsetof">;
def note_constexpr_negative_shift : Note<"negative shift count %0">;
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 4a5c691d390a7..7020c73f4bb98 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2449,13 +2449,18 @@ static bool interp__builtin_object_size(InterpState &S, CodePtr OpPC,
// clear, objects are whole variables. If it is set, a closest surrounding
// subobject is considered the object a pointer points to. The second bit
// determines if maximum or minimum of remaining bytes is computed.
- uint64_t Kind;
- if (!popToUInt64(S, Call->getArg(1), Kind))
+ APSInt Kind;
+ if (!popToAPSInt(S, Call->getArg(1), Kind))
return false;
- assert(Kind <= 3 && "unexpected kind");
+ if (Kind < 0 || Kind > 3) {
+ S.FFDiag(Call->getArg(1), diag::note_constexpr_builtin_arg_out_of_range)
+ << Kind << 0 << 3;
+ return false;
+ }
+ unsigned KindValue = Kind.getZExtValue();
Pointer Ptr = S.Stk.pop<Pointer>();
- if (auto Result = evaluateBuiltinObjectSize(ASTCtx, Kind, Ptr,
+ if (auto Result = evaluateBuiltinObjectSize(ASTCtx, KindValue, Ptr,
Call->getArg(0), IsDynamic)) {
pushInteger(S, *Result, Call->getType());
return true;
@@ -2464,7 +2469,7 @@ static bool interp__builtin_object_size(InterpState &S, CodePtr OpPC,
if (Call->getArg(0)->HasSideEffects(ASTCtx)) {
// "If there are any side effects in them, it returns (size_t) -1
// for type 0 or 1 and (size_t) 0 for type 2 or 3."
- pushInteger(S, Kind <= 1 ? (size_t)-1 : (size_t)0, Call->getType());
+ pushInteger(S, KindValue <= 1 ? (size_t)-1 : (size_t)0, Call->getType());
return true;
}
@@ -2476,7 +2481,8 @@ static bool interp__builtin_object_size(InterpState &S, CodePtr OpPC,
return Invalid(S, OpPC);
case EvaluationMode::ConstantExpressionUnevaluated:
// Reduce it to a constant now.
- pushInteger(S, ((Kind & 2u) ? (size_t)0 : (size_t)-1), Call->getType());
+ pushInteger(S, ((KindValue & 2u) ? (size_t)0 : (size_t)-1),
+ Call->getType());
return true;
}
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 8551f4c9ae279..cf450699aee99 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -17176,10 +17176,13 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_dynamic_object_size:
case Builtin::BI__builtin_object_size: {
- // The type was checked when we built the expression.
- unsigned Type =
- E->getArg(1)->EvaluateKnownConstInt(Info.Ctx).getZExtValue();
- assert(Type <= 3 && "unexpected type");
+ APSInt TypeValue = E->getArg(1)->EvaluateKnownConstInt(Info.Ctx);
+ if (TypeValue < 0 || TypeValue > 3) {
+ Info.FFDiag(E->getArg(1), diag::note_constexpr_builtin_arg_out_of_range)
+ << TypeValue << 0 << 3;
+ return false;
+ }
+ unsigned Type = TypeValue.getZExtValue();
bool IsDynamic = BuiltinOp == Builtin::BI__builtin_dynamic_object_size;
if (std::optional<uint64_t> Size =
diff --git a/clang/test/Sema/builtin-object-size.c b/clang/test/Sema/builtin-object-size.c
index 8d48d3f569d91..52f53fd2b286f 100644
--- a/clang/test/Sema/builtin-object-size.c
+++ b/clang/test/Sema/builtin-object-size.c
@@ -30,6 +30,8 @@ int f3(void) {
return OBJECT_SIZE_BUILTIN(&a, 4); // expected-error {{argument value 4 is outside the valid range [0, 3]}}
}
+_Static_assert(OBJECT_SIZE_BUILTIN((void *)0, -1), ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{argument value -1 is outside the valid range [0, 3]}}
+_Static_assert(OBJECT_SIZE_BUILTIN((void *)0, 4), ""); // expected-error {{static assertion expression is not an integral constant expression}} expected-note {{argument value 4 is outside the valid range [0, 3]}}
// cannot call vsnprintf with va_list on x86_64
void f4(const char *fmt, ...) {
More information about the cfe-commits
mailing list