Skip to content

Conversation

@pavelsavara
Copy link
Member

@pavelsavara pavelsavara commented Jan 26, 2026

Fixes #114096

@pavelsavara pavelsavara added this to the 11.0.0 milestone Jan 26, 2026
@pavelsavara pavelsavara self-assigned this Jan 26, 2026
@pavelsavara pavelsavara added arch-wasm WebAssembly architecture area-GC-coreclr os-browser Browser variant of arch-wasm labels Jan 26, 2026
@dotnet-policy-service
Copy link
Contributor

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

SString err;
ex->GetMessage(err);
LogErrorToHost("Error message: %s", err.GetUTF8());
abort();
Copy link
Member

Choose a reason for hiding this comment

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

I don't think calling abort() here is what we want. See FinalizerThread::FinalizerThreadStart where we will continue to loop.

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 thought that we are supposed to "kill the process" when we see managed exception in the finalizer thread.

On other OS FinalizerThread::FinalizerThreadStart is running on different(main) thread than the finalizer.
How does the UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP know that something failed on finalizer thread ?

I can use CrashDumpAndTerminateProcess(1); that is there in the macro instead of the abort()

Copy link
Member

@AaronRobinsonMSFT AaronRobinsonMSFT Jan 26, 2026

Choose a reason for hiding this comment

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

when we see managed exception in the finalizer thread.

That is mostly true, but there are configurations here that we should only change with a clear comment on why. There is a fair bit of native infrastructure here that could trigger and we should be sensitive to that. Take a look at ManagedThreadBase_DispatchOuter and ManagedThreadBase_DispatchMiddle. @jkotas or @janvorli Can probably educate us both on the precise expectations here and what is reasonable to do.

I can use CrashDumpAndTerminateProcess(1); that is there in the macro instead of the abort()

That is a better place to start and what I would expect that API instead of abort() regardless of what we do. I might suggest CrashDumpAndTerminateProcess(ex->GetHR());.

Copy link
Member

Choose a reason for hiding this comment

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

How does the UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP know that something failed on finalizer thread ?

I am not sure if I understand the question correctly. When a managed exception escapes the finalizer thread code, it is actually in a form of PAL_SEHException, so that macro catches it, reports the exception as unhandled and then calls the CrashDumpAndTerminateProcess to shutdown the runtime.

Copy link
Member

Choose a reason for hiding this comment

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

I've forgotten to mention that this is for Unix. On Windows, it is a SEH exception and the OS itself takes care of it (shutting down the process, generating dump)

Copy link
Member

Choose a reason for hiding this comment

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

I think UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP is close to what we want for wasm.

You may want to actually test what happens when you throw in the finalizer on wasm. You should see unhandled exception message with stacktrace.

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 think I see my mistake now. I got confused by ManagedThreadBase::KickOff. I thought it's creating another thread. I will continue tomorrow. Thank you so far!

pavelsavara and others added 7 commits January 26, 2026 18:48
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Co-authored-by: Aaron R Robinson <arobins@microsoft.com>
Co-authored-by: Aaron R Robinson <arobins@microsoft.com>
Co-authored-by: Aaron R Robinson <arobins@microsoft.com>
Co-authored-by: Aaron R Robinson <arobins@microsoft.com>
Co-authored-by: Aaron R Robinson <arobins@microsoft.com>

public static bool IsPreciseGcSupported => !IsMonoRuntime
&& !IsBrowser; // TODO-WASM: https://github.com/dotnet/runtime/issues/114096
public static bool IsPreciseGcSupported => !IsMonoRuntime;
Copy link
Member

Choose a reason for hiding this comment

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

@janvorli Are we actually running successfully all tests assuming precise GC ? I know we are reporting quite a fair chunk of vars conservatively (I believe everything aside from the IL globals, args and locals)

Copy link
Member

Choose a reason for hiding this comment

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

IIRC, @davidwrighton has enabled conservative reporting of call arguments and temp vars, the rest should be reported precisely. David, have I forgotten about something?

Copy link
Member

Choose a reason for hiding this comment

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

I believe that the conservative reporting in the interpreter is still "precise" - for the definition of "precise" used by this property.

Precise GC here means that the runtime is not trying to interpret random values found on the stack as GC object references.

Copy link
Member

Choose a reason for hiding this comment

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

We are not running with fully precise GC today. I had an idea about how we could implement it semi-efficiently, but I haven't actually tried to see if it would work. However, the level of conservative GC we have today is extremely limited relative to what Mono was doing, so we might be close enough to precise GC semantics for nearly all the tests to pass. The notable detail is that I believe we are only reliably visibly imprecise for tests which check to see if a value got promoted (since our reporting will pin things that don't need pinning), and during the instruction after a call instruction. This is a MUCH smaller problem set than Mono had.

Copy link
Member

Choose a reason for hiding this comment

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

The notable detail is that I believe we are only reliably visibly imprecise for tests which check to see if a value got promoted (since our reporting will pin things that don't need pinning)

This sounds like we are just extending a lifetime within a method, correct? That does would count as imprecise GC. RyuJIT extends the lifetime within a method as well.

// Wait for work to do...

_ASSERTE(GetFinalizerThread()->PreemptiveGCDisabled());
#ifdef _DEBUG
Copy link
Member

Choose a reason for hiding this comment

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

These GetFinalizerThread()->m_GCOnTransitionsOK = FALSE/TRUE should be moved up as well. It is important that the call to EnablePreemptiveGC is enclosed by these calls - it is a perf optimization for GC stress.

GCHeapUtilities::GetGCHeap()->CollectionCount(GCHeapUtilities::GetGCHeap()->GetMaxGeneration());
FinalizeAllObjects();

GetFinalizerThread()->DisablePreemptiveGC();
Copy link
Member

Choose a reason for hiding this comment

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

Should this be after the ifdef?

}

VOID FinalizerThread::FinalizerThreadWorkerIteration()
{
Copy link
Member

Choose a reason for hiding this comment

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

Could you please add the expected contract here? (maybe you have not pushed your local changes up yet)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-GC-coreclr os-browser Browser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[browser][coreclr] run finalizers on browser timer

6 participants