https://github.com/keepyixiao created https://github.com/llvm/llvm-project/pull/230979
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. Assisted-by: AI Fixes https://github.com/llvm/llvm-project/issues/225041 >From e5c90d74f61df50d51d624dba52bf8a864e3df22 Mon Sep 17 00:00:00 2001 From: nudt_yixiao <[email protected]> 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 | 7 +++++++ 5 files changed, 31 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..45d9cb24df1b9 100644 --- a/clang/test/Sema/builtin-object-size.c +++ b/clang/test/Sema/builtin-object-size.c @@ -30,6 +30,13 @@ int f3(void) { return OBJECT_SIZE_BUILTIN(&a, 4); // expected-error {{argument value 4 is outside the valid range [0, 3]}} } +// expected-error@+2 {{static assertion expression is not an integral constant expression}} +// expected-note@+1 {{argument value -1 is outside the valid range [0, 3]}} +_Static_assert(OBJECT_SIZE_BUILTIN((void *)0, -1), ""); + +// expected-error@+2 {{static assertion expression is not an integral constant expression}} +// expected-note@+1 {{argument value 4 is outside the valid range [0, 3]}} +_Static_assert(OBJECT_SIZE_BUILTIN((void *)0, 4), ""); // cannot call vsnprintf with va_list on x86_64 void f4(const char *fmt, ...) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
