[Interpreter] Fix localloc to guarantee 16-byte stack alignment#125720
Merged
radekdoulik merged 3 commits intomainfrom Mar 31, 2026
Merged
[Interpreter] Fix localloc to guarantee 16-byte stack alignment#125720radekdoulik merged 3 commits intomainfrom
radekdoulik merged 3 commits intomainfrom
Conversation
Contributor
|
Tagging subscribers to this area: @BrzVlad, @janvorli, @kg |
…NMENT Co-authored-by: radekdoulik <4147484+radekdoulik@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] [Interpreter] Fix localloc alignment issue for stack
[Interpreter] Fix localloc to guarantee 16-byte stack alignment
Mar 18, 2026
BrzVlad
reviewed
Mar 18, 2026
Co-authored-by: BrzVlad <4720621+BrzVlad@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes CoreCLR interpreter localloc alignment to guarantee 16-byte alignment (matching INTERP_STACK_ALIGNMENT), addressing failures in ShowLocallocAlignment and preventing misaligned stackalloc buffers on interpreter platforms (e.g., WASM).
Changes:
- Allocate frame data fragments with
VMToOSInterface::AlignedAllocate(INTERP_STACK_ALIGNMENT, ...)and free withAlignedFree. - Align bump allocations in
FrameDataAllocator::Alloc()toINTERP_STACK_ALIGNMENTinstead ofsizeof(void*).
Comments suppressed due to low confidence (1)
src/coreclr/vm/interpframeallocator.cpp:94
- If the first fragment allocation fails (or a fragment’s backing allocation fails),
pFirstcan be left non-null whilepCurrentis still null, and the partially-constructed fragment isn’t deleted. This can corrupt the allocator state: after thenullptrreturn triggersOutOfMemoryException, subsequentAlloccalls will skip thepFirst == nullptrpath and then dereferencepCurrent.
Consider allocating into a temporary FrameDataFragment* and only assigning to pFirst/pCurrent after verifying pFrameStart != nullptr; otherwise delete the fragment before returning failure (same pattern should be applied for later fragment allocations too).
if (pFirst == nullptr)
{
pFirst = new (nothrow) FrameDataFragment(size);
if (pFirst == nullptr || pFirst->pFrameStart == nullptr)
{
return nullptr;
}
31 tasks
BrzVlad
approved these changes
Mar 31, 2026
radekdoulik
added a commit
to radekdoulik/runtime
that referenced
this pull request
Mar 31, 2026
…et#125720) `FrameDataAllocator::Alloc()` was aligning localloc buffers to `sizeof(void*)` (4–8 bytes) instead of `INTERP_STACK_ALIGNMENT` (16 bytes), causing the `ShowLocallocAlignment` regression test to fail on any platform using the CoreCLR interpreter (e.g., WASM). ## Description - **Fragment backing memory**: Replace `malloc` with `VMToOSInterface::AlignedAllocate(INTERP_STACK_ALIGNMENT, size)` so every fragment's base address is 16-byte aligned. Pair `free` → `VMToOSInterface::AlignedFree` accordingly. - **Bump allocation alignment**: Change `ALIGN_UP(size, sizeof(void*))` → `ALIGN_UP(size, INTERP_STACK_ALIGNMENT)` so `pFramePos` advances by a multiple of 16, keeping it aligned across all subsequent allocations and after `PopInfo` restores. `VMToOSInterface` is already available in all `cee_wks_core` VM files via `common.h`, which is force-included as a precompiled header (see `src/coreclr/vm/wks/CMakeLists.txt`). No additional include is needed. ## Customer Impact Programs using `stackalloc` (localloc) under the CoreCLR interpreter receive misaligned pointers. On WASM and other platforms requiring 16-byte alignment (e.g., for SIMD), this causes incorrect behavior or crashes. ## Regression Not a regression in a released build; this is a correctness gap in the interpreter that has existed since its introduction. ## Testing Existing `JIT/Regression/Dev11/External/dev11_239804/ShowLocallocAlignment` test covers this scenario. Full `clr+libs` build verified clean on Linux x64. ## Risk Low. The change is isolated to `interpframeallocator.cpp` — a single file only compiled under `FEATURE_INTERPRETER`. Both allocation paths (`AlignedAllocate`/`AlignedFree`) are already used elsewhere in the interpreter for the main stack (`interpexec.cpp`). No behavioral change outside the interpreter. <!-- START COPILOT ORIGINAL PROMPT --> <details> <summary>Original prompt</summary> > > ---- > > *This section details on the original issue you should resolve* > > <issue_title>[Interpreter] localloc does not guarantee platform stack alignment</issue_title> > <issue_description>`FrameDataAllocator::Alloc()` in `src/coreclr/vm/interpframeallocator.cpp` aligns localloc buffer sizes to `sizeof(void*)` (4 bytes on WASM, 8 bytes on 64-bit platforms): > > ```cpp > size = ALIGN_UP(size, sizeof(void*)); > ``` > > The JIT guarantees localloc returns pointers aligned to `STACK_ALIGN` (16 bytes on most platforms including WASM — see `src/coreclr/jit/targetwasm.h`), but the interpreter does not honor this. The fragment backing memory comes from raw `malloc()` with no explicit alignment, and subsequent bump allocations within a fragment are only pointer-size aligned. > > This causes the `ShowLocallocAlignment` regression test to fail on WASM (and would fail on any platform using the interpreter) because `stackalloc` returns 8-byte aligned addresses instead of the expected 16-byte alignment. > > ### Repro > > Run `JIT/Regression/Dev11/External/dev11_239804/ShowLocallocAlignment` on a platform using the CoreCLR interpreter (e.g. WASM). > > ### Expected > > Localloc returns a 16-byte aligned pointer (matching `STACK_ALIGN`). > > ### Actual > > Localloc returns a pointer aligned only to `sizeof(void*)`. > > ### Suggested fix > > Change the alignment in `FrameDataAllocator::Alloc()` to use `INTERP_STACK_ALIGNMENT` (16) instead of `sizeof(void*)`, and ensure the returned pointer (not just the size) is aligned.</issue_description> > > ## Comments on the Issue (you are @copilot in this section) > > <comments> > <comment_new><author>@radekdoulik</author><body> > @janvorli @BrzVlad should we align FrameDataAllocator::Alloc() to INTERP_STACK_ALIGNMENT?</body></comment_new> > <comment_new><author>@BrzVlad</author><body> > Sounds good. We could use AlignedAllocate here as well. </body></comment_new> > </comments> > </details> <!-- START COPILOT CODING AGENT SUFFIX --> - Fixes dotnet#125657 <!-- START COPILOT CODING AGENT TIPS --> --- 📱 Kick off Copilot coding agent tasks wherever you are with [GitHub Mobile](https://gh.io/cca-mobile-docs), available on iOS and Android. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: radekdoulik <4147484+radekdoulik@users.noreply.github.com> Co-authored-by: BrzVlad <4720621+BrzVlad@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
FrameDataAllocator::Alloc()was aligning localloc buffers tosizeof(void*)(4–8 bytes) instead ofINTERP_STACK_ALIGNMENT(16 bytes), causing theShowLocallocAlignmentregression test to fail on any platform using the CoreCLR interpreter (e.g., WASM).Description
mallocwithVMToOSInterface::AlignedAllocate(INTERP_STACK_ALIGNMENT, size)so every fragment's base address is 16-byte aligned. Pairfree→VMToOSInterface::AlignedFreeaccordingly.ALIGN_UP(size, sizeof(void*))→ALIGN_UP(size, INTERP_STACK_ALIGNMENT)sopFramePosadvances by a multiple of 16, keeping it aligned across all subsequent allocations and afterPopInforestores.VMToOSInterfaceis already available in allcee_wks_coreVM files viacommon.h, which is force-included as a precompiled header (seesrc/coreclr/vm/wks/CMakeLists.txt). No additional include is needed.Customer Impact
Programs using
stackalloc(localloc) under the CoreCLR interpreter receive misaligned pointers. On WASM and other platforms requiring 16-byte alignment (e.g., for SIMD), this causes incorrect behavior or crashes.Regression
Not a regression in a released build; this is a correctness gap in the interpreter that has existed since its introduction.
Testing
Existing
JIT/Regression/Dev11/External/dev11_239804/ShowLocallocAlignmenttest covers this scenario. Fullclr+libsbuild verified clean on Linux x64.Risk
Low. The change is isolated to
interpframeallocator.cpp— a single file only compiled underFEATURE_INTERPRETER. Both allocation paths (AlignedAllocate/AlignedFree) are already used elsewhere in the interpreter for the main stack (interpexec.cpp). No behavioral change outside the interpreter.Original prompt
📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.