Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>2021-04-17 02:33:13 +0300
committerGitHub <noreply@github.com>2021-04-17 02:33:13 +0300
commit4573751df68588c7cd0eb607e7c2b7a66d2d8434 (patch)
treeb5695da2720722a32e845f4deefc53ff3a583cc0 /src/coreclr/vm/gcenv.ee.cpp
parent689521757637dfbe286436456c97f23eedf8bf19 (diff)
Fix GC hole with collectible assemblies and tailcalls (#51315)
We must take special care to keep the tailcall dispatcher targets alive while tailcalls are in-flight. In particular, given the following callstack: [B]M2() [SPC]DispatchTailCalls [A]M() it could happen that [B]M2() queued a tail call to a function [B]M3(). Since there is a live dispatcher on the call stack, this would result in [B]M2() storing a function pointer pointing to [B]M3() and returning to this dispatcher to let it take care of the tailcall. If B was loaded in a collectible ALC, it would then be possible for there to be nothing keeping this ALC alive, and for the assembly to be unloaded before the dispatcher invoked the function pointer. I was unable to come up with a test case where this happened without making changes to the dispatcher; the window otherwise seems to be too small. To reproduce the problem I thus had to add a Thread.Sleep(50) into the dispatcher, which quickly resulted in an AccessViolationException in the scenario above. With the changes in this commit I was then no logner able to reproduce the problem. Fix #41314
Diffstat (limited to 'src/coreclr/vm/gcenv.ee.cpp')
-rw-r--r--src/coreclr/vm/gcenv.ee.cpp17
1 files changed, 16 insertions, 1 deletions
diff --git a/src/coreclr/vm/gcenv.ee.cpp b/src/coreclr/vm/gcenv.ee.cpp
index 7849958d068..ea327cc73d8 100644
--- a/src/coreclr/vm/gcenv.ee.cpp
+++ b/src/coreclr/vm/gcenv.ee.cpp
@@ -157,7 +157,22 @@ static void ScanStackRoots(Thread * pThread, promote_func* fn, ScanContext* sc)
static void ScanTailCallArgBufferRoots(Thread* pThread, promote_func* fn, ScanContext* sc)
{
- TailCallArgBuffer* argBuffer = pThread->GetTailCallTls()->GetArgBuffer();
+ TailCallTls* tls = pThread->GetTailCallTls();
+ // Keep loader associated with CallTailCallTarget alive.
+ if (sc->promotion)
+ {
+#ifndef DACCESS_COMPILE
+ const PortableTailCallFrame* frame = tls->GetFrame();
+ if (frame->NextCall != NULL)
+ {
+ MethodDesc* pMD = Entry2MethodDesc((PCODE)frame->NextCall, NULL);
+ if (pMD != NULL)
+ GcReportLoaderAllocator(fn, sc, pMD->GetLoaderAllocator());
+ }
+#endif
+ }
+
+ TailCallArgBuffer* argBuffer = tls->GetArgBuffer();
if (argBuffer == NULL || argBuffer->GCDesc == NULL)
return;