JIT: disable stack allocation for sites in CEA cloned regions#121771
JIT: disable stack allocation for sites in CEA cloned regions#121771AndyAyersMS merged 4 commits intodotnet:mainfrom
Conversation
Our escape analysis assumes each stack allocation candidate node has a unique temp that has that allocation as its only assigned value. Conditional escape analysis may clone these nodes, creating a second allocation site assigning to the associated temp. This breaks the 1-1 assumption noted above. If those allocations do not escape then the JIT will stack allocate them, creating two distinct stack locals. In subsequent IR rewriting the JIT will then use the address of just one of the locals for all appearances of the temp, which is incorrect, and leads to the generated code possibly reading uninitialized stack slots. To fix this we disallow stack allocation for sites in blocks that were cloned, or their clones. (We can actually handle this case with better bookkeeping, but that is more involved). Fixes dotnet#121736.
|
No diffs locally. Still need to add the repro case. |
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
|
Are we going to backport this fix? |
|
@dotnet/jit-contrib PTAL No diffs, this case is a bit rare. Usually if you are doing CEA there's a loop involved that will inhibit stack allocation of any CEA-region
Yes, we should. |
There was a problem hiding this comment.
Pull Request Overview
This PR fixes a bug in the JIT's object stack allocation optimization where conditional escape analysis (CEA) clones allocation nodes, violating the single-assignment assumption and potentially leading to uninitialized stack slot reads.
Key Changes:
- Adds logic to detect and disable stack allocation for allocation sites in blocks that were cloned or are clones
- Captures the initial maximum block ID before any cloning occurs
- Uses the initial block ID to distinguish cloned blocks from original blocks
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| src/coreclr/jit/objectalloc.h | Adds m_initialMaxBlockID field and BlockIsCloneOrWasCloned method declaration |
| src/coreclr/jit/objectalloc.cpp | Implements the fix: initializes m_initialMaxBlockID, adds check in MorphAllocObjNodeHelper, and implements BlockIsCloneOrWasCloned method |
| src/tests/JIT/opt/ObjectStackAllocation/Runtime_121736.cs | Adds regression test that reproduces the issue fixed in #121736 |
| src/tests/JIT/opt/ObjectStackAllocation/Runtime_121736.csproj | Project file for the new regression test |
|
/backport to release/10.0 |
|
Started backporting to |
|
@AndyAyersMS backporting to git am output$ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch
Patch format detection failed.
Error: The process '/usr/bin/git' failed with exit code 128 |
…#121771) Our escape analysis assumes each stack allocation candidate node has a unique temp that has that allocation as its only assigned value. Conditional escape analysis may clone these nodes, creating a second allocation site assigning to the associated temp. This breaks the 1-1 assumption noted above. If those allocations do not escape then the JIT will stack allocate them, creating two distinct stack locals. In subsequent IR rewriting the JIT will then use the address of just one of the locals for all appearances of the temp, which is incorrect, and leads to the generated code possibly reading uninitialized stack slots. To fix this we disallow stack allocation for sites in blocks that were cloned, or their clones. (We can actually handle this case with better bookkeeping, but that is more involved). Fixes dotnet#121736.
…regions (#121860) Backport of #121771 to release/10.0 /cc @AndyAyersMS ## Customer Impact - [x] Customer reported - [ ] Found internally Reported by customer in #121736 ## Regression - [ ] Yes - [x] No An issue in a new optimization in .NET 10. Escape analysis assumes each stack allocation candidate node has a unique temp that has that allocation as its only assigned value. Conditional escape analysis may clone these nodes, creating a second allocation site assigning to the same temp. This breaks the 1-1 assumption noted above and can lead to silent bad codegen. To fix this we disallow stack allocation for sites in blocks that were cloned, or their clones. ## Testing Verified on the test case from the issue. ## Risk Low. Disables an optimization. No diffs for this in our SPMI testing.
Our escape analysis assumes each stack allocation candidate node has a unique temp that has that allocation as its only assigned value.
Conditional escape analysis may clone these nodes, creating a second allocation site assigning to the associated temp. This breaks the 1-1 assumption noted above.
If those allocations do not escape then the JIT will stack allocate them, creating two distinct stack locals. In subsequent IR rewriting the JIT will then use the address of just one of the locals for all appearances of the temp, which is incorrect, and leads to the generated code possibly reading uninitialized stack slots.
To fix this we disallow stack allocation for sites in blocks that were cloned, or their clones. (We can actually handle this case with better bookkeeping, but that is more involved).
Fixes #121736.