Skip to content

Move the return var out of liveLocalsIntervals#127931

Open
BrzVlad wants to merge 1 commit intodotnet:mainfrom
BrzVlad:fix-clrinterp-async-ret
Open

Move the return var out of liveLocalsIntervals#127931
BrzVlad wants to merge 1 commit intodotnet:mainfrom
BrzVlad:fix-clrinterp-async-ret

Conversation

@BrzVlad
Copy link
Copy Markdown
Member

@BrzVlad BrzVlad commented May 7, 2026

When generating an async call, in EmitSuspend, we obtain the set of vars that are alive at this point in time and we store this information inside the suspenData. If they async call needs to suspend it will store these vars into the ContinuationObject, with their values being restored when we resume the continuation.

Previous code would store the result value as well into the ContinuationObject. The problem is that this would lead to storing uninitialized data into the object, which can result in random GC crashes. This commit removes the result var from the set of live vars, stores associated information specifically for the return var inside the suspend data and we make use of this information to write the result only on the suspend resume path.

Fixes #127855

Copilot AI review requested due to automatic review settings May 7, 2026 19:00
@BrzVlad
Copy link
Copy Markdown
Member Author

BrzVlad commented May 7, 2026

/azp run runtime-libraries-interpreter

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@dotnet-policy-service
Copy link
Copy Markdown
Contributor

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

Copy link
Copy Markdown
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 interpreter async continuation state capture so the awaited call’s return value is no longer treated as a normal “live local” to copy into the continuation object (which previously could copy uninitialized stack data and lead to GC consistency crashes in interpreter mode). Instead, it tracks return-value metadata separately and restores the return value explicitly during the resume path.

Changes:

  • Exclude the call return-value var from liveVars when emitting async suspend data, and record dedicated return-value metadata (size + stack offset) in InterpAsyncSuspendData.
  • Adjust interpreter continuation suspend/resume copy logic so live locals are copied after the continuation’s result storage region, and explicitly copy the return value from GetResultStorage() back to the interpreter stack on resume.
  • Add fixup logic so the stored “return value var” is patched from var index to final stack offset during interval-map finalization.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/coreclr/vm/interpexec.cpp Shifts live-local copy region past result storage; adds explicit return-value restore on resume.
src/coreclr/interpreter/inc/interpretershared.h Extends InterpAsyncSuspendData with return-value continuation size and stack offset metadata.
src/coreclr/interpreter/compiler.cpp Stops treating return-value var as a live var; computes/stores return-value metadata and patches it during interval-map update.

Comment thread src/coreclr/vm/interpexec.cpp Outdated
Comment on lines +6024 to +6032
}
else
{
suspendData->returnValueContinuationDataSize = 0;
}

// Patched up in UpdateLocalIntervalMaps to hold the actual offset of the var
suspendData->returnValueVarStackOffset = returnValueVar;

When generating an async call, in EmitSuspend, we obtain the set of vars that are alive at this point in time and we store this information inside the suspenData. If they async call needs to suspend it will store these vars into the ContinuationObject, with their values being restored when we resume the continuation.

Previous code would store the result value as well into the ContinuationObject. The problem is that this would lead to storing uninitialized data into the object, which can result in random GC crashes. This commit removes the result var from the set of live vars, stores associated information specifically for the return var inside the suspend data and we make use of this information to write the result only on the suspend resume path.
@BrzVlad BrzVlad force-pushed the fix-clrinterp-async-ret branch from 94adc6a to 0dc387b Compare May 8, 2026 05:50
@BrzVlad BrzVlad marked this pull request as ready for review May 8, 2026 05:55
@BrzVlad BrzVlad requested a review from janvorli as a code owner May 8, 2026 05:55
Copilot AI review requested due to automatic review settings May 8, 2026 05:55
@BrzVlad BrzVlad requested a review from kg as a code owner May 8, 2026 05:55
Copy link
Copy Markdown
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

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/interpreter/inc/interpretershared.h
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ci-scan] Known Build Error: GC assertion is_in_heap_range in runtime-interpreter and runtime-libraries-interpreter

2 participants