Skip to content
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

Fix A/V in ApplyUpdate API #50452

Merged
merged 2 commits into from
Apr 1, 2021
Merged

Fix A/V in ApplyUpdate API #50452

merged 2 commits into from
Apr 1, 2021

Conversation

mikem8361
Copy link
Member

Add thread suspend around the update API.

Issue: #50445

Add thread suspend around the update API.

Issue: dotnet#50445
@mikem8361 mikem8361 self-assigned this Mar 30, 2021
@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

I do not think that's the proper fix. Instead, I think we should patch the precode automically same was as tiered JIT. Tiered JIT is able to do that without thread suspend, so this one should be able to do it without thread suspend as well.

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks! We may want to open an issue to track switching this to the code version manager.

@stephentoub
Copy link
Member

Thanks for tracking this down, Mike.

@mikem8361 mikem8361 requested a review from noahfalk April 1, 2021 00:15
if (pMethod->HasNativeCodeSlot())
{
RelativePointer<TADDR> *pRelPtr = (RelativePointer<TADDR> *)pMethod->GetAddrOfNativeCodeSlot();
pRelPtr->SetValueMaybeNull(NULL);
Copy link
Member

Choose a reason for hiding this comment

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

There is probably still theoretically a race here that would result in the code not being updated. In practice I could imagine it is non-existent. The flow would look like:

Thread A: calls into unjitted method Foo for the first time and begins jitting using the original IL
Thread B: starts applying an Update, sets new dynamic IL for the method, resets code entrypoint, sets native code slot to NULL
Thread A: finishes jitting, sets the native code slot to the jitted method body for the original IL, backpatches the precode.
Thread B: exits the update, sometime later calls Foo(). The original IL runs because that is what A backpatched it to.

Copy link
Member

Choose a reason for hiding this comment

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

Agree. There may be also potential crashes where the code out there is not expecting native code to go from non-NULL to NULL.

Copy link
Member

Choose a reason for hiding this comment

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

@noahfalk Do you believe that it is a good idea to switch EnC to use the code version manager to address this type of issues?

Copy link
Member

Choose a reason for hiding this comment

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

EnC using code version manager is a nice long term direction - it is what I always hoped we get to. In terms of doing it now vs. do it later... its probably at least worth investigating now. The cheap way to implement it would be for the debugger to share the same API that the profiler uses, SetActiveILCodeVersions. Currently the profiler creates new versions with no IL and then uses a callback later to populate the IL just-in-time, but I'd expect it is fairly simple to add a new overload that accepts the IL up-front and stores it skipping the callback.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure changing ENC to use the code version manager can fit into our current 6.0 schedule. I'm already overbooked.

/cc: @tommcdon

Copy link
Member

@noahfalk noahfalk left a comment

Choose a reason for hiding this comment

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

This certainly looks better than the AV. There is probably still a theoretical race but potentially so rare its not clear it is worth fixing.

@jkotas
Copy link
Member

jkotas commented Apr 1, 2021

Failures are known issue #50520

@jkotas jkotas merged commit 88f281b into dotnet:main Apr 1, 2021
@mikem8361
Copy link
Member Author

We might have jumped the gun a little in merging this PR because under a checked build we hit this assert:

_ASSERTE(IsVersionable());

The reason I didn't hit before is I was only running on release builds because the repro runs everything (dotnet-watch, building the diffs, and the test app) on the same runtime. The "debug" builds were way too slow (took 5 minutes or longer to even get the test app started). I finally tried it on a checked build after Noah's comment that ENC edited methods will return IsVersionable() == false.

@jkotas
Copy link
Member

jkotas commented Apr 1, 2021

I think you can avoid that assert by calling GetPrecode()->ResetTargetInterlocked(); directly from encee.cpp

@mikem8361 mikem8361 deleted the hotreloadfix branch April 10, 2021 18:16
@ghost ghost locked as resolved and limited conversation to collaborators May 10, 2021
@karelz karelz added this to the 6.0.0 milestone May 20, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants