Skip to content

Fix ILVerify false positive: ReturnPtrToStack on by-value return of a ref struct#129032

Draft
Copilot wants to merge 4 commits into
mainfrom
copilot/ilverify-false-positive-fix
Draft

Fix ILVerify false positive: ReturnPtrToStack on by-value return of a ref struct#129032
Copilot wants to merge 4 commits into
mainfrom
copilot/ilverify-false-positive-fix

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jun 5, 2026

ILVerify incorrectly reports ReturnPtrToStack when a method returns an IsByRefLike (ref struct) type by value. The check at ImportReturn applied the IsPermanentHome requirement for any IsByRefLike return type, but IsPermanentHome is only meaningful when the stack holds a ByRef—not when it holds a value-type.

Root cause

The ImportReturn check treated IsByRefLike and IsByRef identically, requiring IsPermanentHome on the stack value. For by-value ref struct returns, the stack holds a ValueType-kind entry (from ldloc/ldarg), not a ByRef, so IsPermanentHome was always false — incorrectly triggering the error.

Additionally, ImportLoadVar never called SetIsPermanentHome() on the stack value it pushed, even though locals and arguments are permanent homes for the lifetime of the method.

Fix

ILImporter.StackValue.cs: Removed the Debug.Assert(Kind == StackValueKind.ByRef) guard from SetIsPermanentHome, allowing it to be called on value-type stack entries.

ILImporter.Verify.cs / ImportLoadVar: Added stackValue.SetIsPermanentHome() — stack values loaded from locals and arguments are always permanent homes.

With this in place, the ImportReturn check remains in its original simple form:

Check((!expectedReturnType.IsByRef && !expectedReturnType.IsByRefLike) || actualReturnType.IsPermanentHome,
      VerifierError.ReturnPtrToStack);

A ldloc/ldarg of a ref struct now carries IsPermanentHome = true, so the check correctly passes for by-value returns. Returning a byref to a local/arg (e.g. ldarga.s; ret) still correctly fails, as ImportAddressOfVar does not set IsPermanentHome.

Tests

Added to ReturnTests.il:

  • Return.RefStructByValue_Validldarg; stloc; ldloc; ret of a ref struct passes verification
  • Return.LocalRefStructFieldByRef_Invalid_ReturnPtrToStack — returning a byref to a field of a local ref struct argument is correctly rejected

@dotnet-policy-service
Copy link
Copy Markdown
Contributor

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

…returns

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot June 5, 2026 05:00
Copilot AI changed the title [WIP] Fix ILVerify false positive for ref struct return Fix ILVerify false positive: ReturnPtrToStack on by-value return of a ref struct Jun 5, 2026
Copilot finished work on behalf of jkotas June 5, 2026 05:01
Copilot AI requested a review from jkotas June 5, 2026 05:01
}

// Returning a ref struct by value (IsByRefLike) should be valid.
// This was a false positive: ILVerify incorrectly reported ReturnPtrToStack.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
// This was a false positive: ILVerify incorrectly reported ReturnPtrToStack.

Comment thread src/coreclr/tools/ILVerification.Tests/ILTests/ReturnTests.il Outdated
Comment thread src/coreclr/tools/ILVerification/ILImporter.Verify.cs Outdated
@jkotas
Copy link
Copy Markdown
Member

jkotas commented Jun 5, 2026

@copilot address my feedback

Also, address the "The other side of the bug is in" part of the original bug report

…ome fix

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot June 5, 2026 05:14
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jun 5, 2026

@copilot address my feedback

Also, address the "The other side of the bug is in" part of the original bug report

Addressed in the latest commit. The "other side of the bug" fix (ImportLoadVar) is what enables simplifying the check:

  1. ILImporter.StackValue.cs: Removed the Debug.Assert(Kind == StackValueKind.ByRef) from SetIsPermanentHome so it can be called on value-type stack entries.
  2. ILImporter.Verify.cs / ImportLoadVar: Added stackValue.SetIsPermanentHome() — locals and arguments are always permanent homes.
  3. ILImporter.Verify.cs / ImportReturn: The check is now back to its original simple form (|| actualReturnType.IsPermanentHome) — the ldloc/ldarg of a ref struct now carries IsPermanentHome = true, so the check correctly passes.
  4. ReturnTests.il: Removed the two comment lines and changed "still invalid" → "invalid".

Copilot finished work on behalf of jkotas June 5, 2026 05:14
Copilot AI requested a review from jkotas June 5, 2026 05:14
Comment thread src/coreclr/tools/ILVerification.Tests/ILTests/ReturnTests.il Outdated
Copilot AI review requested due to automatic review settings June 5, 2026 05:20
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 updates the ILVerification importer’s tracking of PermanentHome to address a ReturnPtrToStack false positive when returning a ref struct (IsByRefLike) by value, and adds IL tests covering the scenario.

Changes:

  • Mark stack values produced by ldloc/ldarg as PermanentHome (via ImportLoadVar), intended to allow by-value ref struct returns to pass verification.
  • Relax StackValue.SetIsPermanentHome() to be callable on non-ByRef stack kinds.
  • Add new IL test cases for returning a ref struct by value (valid) and returning a byref to a ref struct field (invalid).

Reviewed changes

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

File Description
src/coreclr/tools/ILVerification/ILImporter.Verify.cs Changes ImportLoadVar to set PermanentHome on loaded variables.
src/coreclr/tools/ILVerification/ILImporter.StackValue.cs Removes Debug.Assert(Kind == StackValueKind.ByRef) from SetIsPermanentHome().
src/coreclr/tools/ILVerification.Tests/ILTests/ReturnTests.il Adds a ref struct IL type and two return-related test methods.

Comment on lines 1461 to 1463
var stackValue = StackValue.CreateFromType(varType);
stackValue.SetIsPermanentHome();
if (index == 0 && argument && _thisType != null)
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.

ILVerify false positive: ReturnPtrToStack on by-value return of a ref struct local

3 participants