From 281ada2105d9b0f38d04d01378f220a701e3f7e6 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Tue, 20 Jan 2026 22:42:13 +0100 Subject: [PATCH] Fix array size overflow in objectalloc.cpp (#123362) Fixes https://github.com/dotnet/runtime/issues/123361 The CI probably won't be happy to run the test repro --- src/coreclr/jit/layout.cpp | 27 ++++++++++++++++++++++++++- src/coreclr/jit/layout.h | 4 ++++ src/coreclr/jit/objectalloc.cpp | 7 +++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/layout.cpp b/src/coreclr/jit/layout.cpp index a1ad460435caa7..ae42615b878df8 100644 --- a/src/coreclr/jit/layout.cpp +++ b/src/coreclr/jit/layout.cpp @@ -901,6 +901,31 @@ ClassLayoutBuilder::ClassLayoutBuilder(Compiler* compiler, unsigned size) { } +//------------------------------------------------------------------------ +// IsArrayTooLarge: check if an array of the specified length would exceed +// the specified maximum byte size for its payload. +// +// Arguments: +// compiler - Compiler instance +// arrayHandle - class handle for array +// length - array length (in elements) +// maxByteSize - maximum allowed byte size for the array payload +// +// Return value: +// true if the array would be too large +// +bool ClassLayoutBuilder::IsArrayTooLarge(Compiler* compiler, + CORINFO_CLASS_HANDLE arrayHandle, + unsigned length, + unsigned maxByteSize) +{ + CORINFO_CLASS_HANDLE elemClsHnd = NO_CLASS_HANDLE; + var_types type = JITtype2varType(compiler->info.compCompHnd->getChildType(arrayHandle, &elemClsHnd)); + unsigned elementSize = (type == TYP_STRUCT) ? compiler->typGetObjLayout(elemClsHnd)->GetSize() : genTypeSize(type); + uint64_t byteSize = static_cast(elementSize) * static_cast(length); + return byteSize > maxByteSize; +} + //------------------------------------------------------------------------ // BuildArray: Construct a builder for an array layout // @@ -939,7 +964,7 @@ ClassLayoutBuilder ClassLayoutBuilder::BuildArray(Compiler* compiler, CORINFO_CL totalSize *= static_cast(length); totalSize.AlignUp(TARGET_POINTER_SIZE); totalSize += static_cast(OFFSETOF__CORINFO_Array__data); - assert(!totalSize.IsOverflow()); + assert(!totalSize.IsOverflow()); // should never overflow if caller used IsArrayTooLarge beforehand ClassLayoutBuilder builder(compiler, totalSize.Value()); diff --git a/src/coreclr/jit/layout.h b/src/coreclr/jit/layout.h index ca367d5fb56307..79e88a273fe19d 100644 --- a/src/coreclr/jit/layout.h +++ b/src/coreclr/jit/layout.h @@ -44,6 +44,10 @@ class ClassLayoutBuilder void CopyNameFrom(ClassLayout* layout, const char* prefix); #endif + static bool IsArrayTooLarge(Compiler* compiler, + CORINFO_CLASS_HANDLE arrayHandle, + unsigned length, + unsigned maxByteSize); static ClassLayoutBuilder BuildArray(Compiler* compiler, CORINFO_CLASS_HANDLE arrayType, unsigned length); }; diff --git a/src/coreclr/jit/objectalloc.cpp b/src/coreclr/jit/objectalloc.cpp index 07f367c2af583f..4f379e60c8caf2 100644 --- a/src/coreclr/jit/objectalloc.cpp +++ b/src/coreclr/jit/objectalloc.cpp @@ -1107,6 +1107,13 @@ bool ObjectAllocator::CanAllocateLclVarOnStack(unsigned int lclNum, return false; } + // Bail out if the array is definitely too large - we don't want to even start building its layout. + if (ClassLayoutBuilder::IsArrayTooLarge(comp, clsHnd, (unsigned)length, m_StackAllocMaxSize)) + { + *reason = "[array is too large]"; + return false; + } + ClassLayout* const layout = comp->typGetArrayLayout(clsHnd, (unsigned)length); classSize = layout->GetSize(); }