Skip to content

Conversation

@jakobbotsch
Copy link
Member

The JIT allows tailcalls that depend on widening happening in the callee: e.g. an int32 returning function can tailcall an int16 returning function because the managed ABI specifies that the callee will widen anyway.

However, this is not legal for async methods. For async methods the int32 and int16 returning functions come with two different resumption stubs that are responsible for propagating the returned result into the next continuation in asynchronous cases. Allowing an int32 -> int16 tailcall means only a 16-bit value gets propagated into a caller that expects 32 bits to be written into its continuation.

Fix #119060

The JIT allows tailcalls that depend on widening happening in the
callee: e.g. an int32 returning function can tailcall an int16 returning
function because the managed ABI specifies that the callee will widen
anyway.

However, this is not legal for async methods. For async methods the
int32 and int16 returning functions come with two different resumption
stubs that are responsible for propagating the returned result into the
next continuation in asynchronous cases. Allowing an int32 -> int16
tailcall means only a 16-bit value gets propagated into a caller that
expects 32 bits to be written into its continuation.

Fix dotnet#119060
@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Aug 27, 2025
@jakobbotsch jakobbotsch marked this pull request as ready for review August 28, 2025 09:11
Copilot AI review requested due to automatic review settings August 28, 2025 09:11
@jakobbotsch
Copy link
Member Author

PTAL @dotnet/jit-contrib

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 JIT compilation issue where widening tailcalls were incorrectly allowed in async functions. The problem occurs when an async function returning a wider type (e.g., int32) attempts to tailcall an async function returning a narrower type (e.g., int16), which can corrupt the continuation mechanism in async execution.

Key changes:

  • Modified JIT logic to disallow widening tailcalls specifically for async functions
  • Added comprehensive test case demonstrating the problematic scenario

Reviewed Changes

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

File Description
src/coreclr/jit/importercalls.cpp Added check to prevent widening tailcalls in async functions
src/tests/async/widening-tailcall/widening-tailcall.cs Test case reproducing the async widening tailcall bug
src/tests/async/widening-tailcall/widening-tailcall.csproj Project file for the new test

@jakobbotsch jakobbotsch added area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI runtime-async and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Aug 28, 2025
@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.

@jakobbotsch
Copy link
Member Author

/ba-g Deadlettered

@jakobbotsch jakobbotsch merged commit 9397efd into dotnet:main Aug 28, 2025
116 of 118 checks passed
@jakobbotsch
Copy link
Member Author

/backport to release/10.0

@github-actions
Copy link
Contributor

Started backporting to release/10.0: https://github.com/dotnet/runtime/actions/runs/17299660780

@github-actions github-actions bot locked and limited conversation to collaborators Sep 28, 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 runtime-async

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JIT: Invalid widening tailcalls in runtime async functions

2 participants