Skip to content

When cloning method descs be careful with fields that have different offsets between the source and destination. #115798

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

VSadov
Copy link
Member

@VSadov VSadov commented May 20, 2025

Fixes: #115667

When cloning methoddescs into destination that has a different layout, memcopy only the base portion, then copy remaining fields individually.

If we memcopy the whole thing, non-base fields would be copied to wrong locations. Even if we subsequently copy the non-base fields individually, the initial memcopy may corrupt destination fields that are not present in the source.

The issue appears to be not new, but somehow did not cause problems until now.

Copy link
Contributor

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

@VSadov
Copy link
Member Author

VSadov commented May 20, 2025

CC: @jakobbotsch - the fix for the async issue.

@VSadov VSadov changed the title Clean old locations when shifting data inside methoddesc When cloning method descs be careful with fields that have different offsets between the source and destination. May 21, 2025
@VSadov VSadov marked this pull request as ready for review May 21, 2025 01:58
@Copilot Copilot AI review requested due to automatic review settings May 21, 2025 01:58
Copy link
Contributor

@Copilot 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 incorrect MethodDesc cloning when source and destination layouts differ by copying only the base portion and individually copying remaining fields.

  • Add a regression test project and test to reproduce the offset-cloning issue.
  • Update AllocAndInitMethodDescChunk to memcpy only the base for non-generic methods and handle the rest manually.
  • Retain full memcpy for generic methods to preserve existing behavior.

Reviewed Changes

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

File Description
src/tests/Regressions/coreclr/GitHub_115667/test115667.csproj Add project file for new regression test
src/tests/Regressions/coreclr/GitHub_115667/test115667.cs Add regression test reproducing incorrect MethodDesc cloning
src/coreclr/vm/methodtablebuilder.cpp Split memcpy into base-only copy for non-generic MethodDescs, then copy remainder fields
Comments suppressed due to low confidence (2)

src/coreclr/vm/methodtablebuilder.cpp:7322

  • The new else branch for generic methods (full memcpy path) isn't covered by existing tests; consider adding a regression test for cloning a generic MethodDesc to ensure this path remains correct.
else

src/coreclr/vm/methodtablebuilder.cpp:7303

  • Using pUnboxedMD->GetBaseSize() reads from uninitialized memory; use pMD->GetBaseSize() to determine the correct number of bytes to copy from the source.
memcpy(pUnboxedMD, pMD, pMD->GetBaseSize());

pUnboxedMD->SetHasNonVtableSlot();
if (bmtGenerics->GetNumGenericArgs() == 0)
{
memcpy(pUnboxedMD, pMD, pMD->GetBaseSize());
Copy link
Member Author

Choose a reason for hiding this comment

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

This is basically the fix. memcpy(pUnboxedMD, pMD, pMD->SizeOf()); vs. memcpy(pUnboxedMD, pMD, pMD->GetBaseSize());.

memcpy(pUnboxedMD, pMD, pMD->SizeOf()); may copy a few fields to wrong locations. Then it is not enough to write correct values to the new locations, we would also need to clean up wrong locations.

It is better for the initial memcopy to do only the base portion, which is the same between different layouts. The rest stays zero-inited.

Copy link
Member Author

@VSadov VSadov May 21, 2025

Choose a reason for hiding this comment

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

The problem that we see now is that we are corrupting a slot that is later set via interlocked exchange, which expects 0 comparand.
Since we have junk in the slot, the exchange does not happen and the junk stays in the slot and causes crashes.

@jakobbotsch
Copy link
Member

/azp run runtime-coreclr outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jakobbotsch
Copy link
Member

jakobbotsch commented May 21, 2025

I suspect the new test will need to be disabled in various places that do not support collectible ALCs or loading files from disk. You can check some of the other regression tests that use the CollectibleALC pattern to see where.

}
}

public class Program
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public class Program
public class Runtime_115667

System.Type runtimeTy = asm.GetType(typeof(Runtime).FullName);
mi.Invoke(null, new object[] { System.Activator.CreateInstance(runtimeTy) });

return 100;
Copy link
Member

Choose a reason for hiding this comment

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

This is unnecessary (and will fail a build analyzer we have in some builds). The test can return void instead.

@VSadov
Copy link
Member Author

VSadov commented May 21, 2025

addressed PR feedback

@VSadov
Copy link
Member Author

VSadov commented May 21, 2025

/azp run runtime-coreclr outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Member

@jakobbotsch jakobbotsch left a comment

Choose a reason for hiding this comment

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

LGTM, but I am not familiar with this part of the code so you probably want to wait for David's review too.

@VSadov
Copy link
Member Author

VSadov commented May 21, 2025

/azp run runtime-coreclr outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

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.

[runtime-async] Calling interface Task<T> methods on structs crash the runtime when invoked in an ALC
2 participants