-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Sporadic AV while using ApplyUpdate #50445
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
Tagging subscribers to this area: @tommcdon Issue DetailsRepro:
The AV ends up coming from the patched method:
cc: @mikem8361, @tommcdon
|
I guess Also, delete |
There is one other use: dynamicmethod.cpp line 267:
|
With ResetCodeEntryPoint(), the new method with the changes doesn't seem to be used. In Stephen's demo, the background colors don't change. |
Adding ThreadSuspend::SuspendEE around the ApplyEditAndContinue call in ApplyUpdate seems to fix the issue or at least makes it rare. After 35 changes, it hasn't crashed with this change. Before the change, it crashed with 3 or 4 updates. |
Add thread suspend around the update API. Issue: dotnet#50445
Have you tried to step through this method to see why it does not work?
Yes, that will make it harder to reproduce, but I do not think it would be the proper fix. |
I'm working on stepping through ResetCodeEntryPoint but my repro using dotnet-watch make that difficult (it keeps kill off the target process I'm trying to debug). I have a very rough sketch of the calls being made in this method:
I don't know this part of the runtime (obviously) very well so I not sure what is suppose to happen. The other uses of MethodDesc::ResetCodeEntryPoint seem to do more than just call this method. |
ResetTargetInterlocked should do the same thing as Reset, except that it should do it atomically. Reset updates the precode via multiple writes. ResetTargetInterlocked updates the precode using a single InterlockedCompareExchange. The final outcome should be identical in both cases. |
I stepped though both pMethod->Reset (works but crashes) and pMethod->ResetCodeEntryPoint (doesn't work) one of the differences is that in Reset this code executed:
Adding that after the call to ResetCodeEntryPoint causes the updated methods to be executed. It probably isn't correct either because it isn't interlocked.
I don't understand all the details here, but could it be that ApplyUpdate is changing the method via ENC (which I think doesn't use the code version manager) and tier compilation (which does)? And yes stepping through FixupPrecode::ResetTargetInterlocked() and FixupPrecode::Init() (called from Reset()) confirm they do the same thing but it doesn't seem to be enough. /cc @noahfalk because of his work on tier compilation. |
I would be ok with it as interim fix.
I guess that it is something we need to fix to make this robust and avoid intermittent crashes similar to this one. |
Yes, I expect that is exactly what you are seeing. Calling ResetEntryPoint() is directing the next call through the entrypoint to go into the PreStub. Once in there if the method has IsVersionable() == true then the PreStub would identify which version is now active and backpatch the precode with a pointer to that code. EnC won't take that path. I can't recall if there is a shortcut it might take by observing the NativeCodeSlot already has a valid code pointer in it, but even if it does go through all the work of jitting the updated IL, that new code will never be used because SetNativeCodeInterlocked isn't going to replace a non-null pre-existing code pointer. |
* Fix A/V in ApplyUpdate API Add thread suspend around the update API. Issue: #50445 * Remove thread suspension; switch to ResetCodeEntryPoint()
I'm going to leave this issue open to address the checked build assert at runtime/src/coreclr/vm/method.cpp Line 5012 in 5e79b4f
and maybe the theoretical race condition Noah mentioned. |
Added MethodDesc::ResetCodeEntryPointForEnC() that reset the entry point without the asserts that caused the problem. Introduced in the fix for dotnet#50445
Fix Type.GetFields() after EnC/Hot reload update Switch to the EncApproxFieldDescIterator in the GetFields() FCall. Issue: #51517 Fix debug build assert in ApplyUpdate Added MethodDesc::ResetCodeEntryPointForEnC() that reset the entry point without the asserts that caused the problem. Introduced in the fix for #50445
Repro:
RayTracerRepro.zip
dotnet watch
notepad Raytracer.cs
return new Color(0, 0, 0);
) to change one or more of the arguments to be a double value between 0 and 1 (e.g.return new Color(0, 0, .5);
. Ctrl-S to save.The AV ends up coming from the patched method:
cc: @mikem8361, @tommcdon
The text was updated successfully, but these errors were encountered: