Skip to content

JIT: disable stack allocation for sites in CEA cloned regions#121771

Merged
AndyAyersMS merged 4 commits intodotnet:mainfrom
AndyAyersMS:Fix121736
Nov 20, 2025
Merged

JIT: disable stack allocation for sites in CEA cloned regions#121771
AndyAyersMS merged 4 commits intodotnet:mainfrom
AndyAyersMS:Fix121736

Conversation

@AndyAyersMS
Copy link
Member

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.

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.
@github-actions github-actions bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Nov 19, 2025
@AndyAyersMS
Copy link
Member Author

No diffs locally. Still need to add the repro case.

@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

@JulieLeeMSFT
Copy link
Member

Are we going to backport this fix?

@AndyAyersMS AndyAyersMS marked this pull request as ready for review November 19, 2025 17:40
Copilot AI review requested due to automatic review settings November 19, 2025 17:40
@AndyAyersMS
Copy link
Member Author

@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 new, but First() will just call MoveNext() once and not loop.

Are we going to backport this fix?

Yes, we should.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@AndyAyersMS AndyAyersMS merged commit ac260b4 into dotnet:main Nov 20, 2025
118 checks passed
@AndyAyersMS
Copy link
Member Author

/backport to release/10.0

@github-actions
Copy link
Contributor

Started backporting to release/10.0 (link to workflow run)

@github-actions
Copy link
Contributor

@AndyAyersMS backporting to release/10.0 failed, the patch most likely resulted in conflicts. Please backport manually!

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

Link to workflow output

AndyAyersMS added a commit to AndyAyersMS/runtime that referenced this pull request Nov 20, 2025
…#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.
jkotas pushed a commit that referenced this pull request Dec 4, 2025
…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.
@github-actions github-actions bot locked and limited conversation to collaborators Dec 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Internal CLR error and others after .net10 upgrade

3 participants