Search code examples
.netclrcoreclrclr-profiling-api

clr profiler api: is ICorProfilerCallback::ExceptionThrown GC safe


I was wondering in .net framework profiler, is ExceptionThrown (https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/icorprofilercallback-exceptionthrown-method) guaranteed to not overlap with GC?

Looking at documentation, it appears so - "If the profiler blocks here and garbage collection is attempted, the runtime will block until this callback returns"

However, I ran my profiler attached to paint.net (https://www.getpaint.net/ - version 4.1.6) and saw a specific case where I got GC during ExceptionThrown. (but that was a very rare - only happened on startup and only once in about every 20 runs) - that led data to change right as I was reading it, since gc moved it around.

At least in the .net core version -https://github.com/dotnet/coreclr/blob/master/Documentation/botr/profiling.md it explicitly says what callbacks are GC callout safe. ExceptionThrown is not one of them. ExceptionUnwindFunctionEnter is, for example. However, back to .NET framework - https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/icorprofilercallback-exceptionunwindfunctionenter-method - in .NET framework documentation remark about GC is identical to that of ExceptionThrown.

I know that .NET core != .NET framework. However, I feel like their profilers' code is quite similar and has same guarantees. I couldn't find a similar resource about GC-safety around .NET framework callbacks.

So after all this intro, my question is:

  1. Should .NET framework clr profiler ExceptionThrown callback be GC-safe. And if so, how can it be that I saw GC call starts and ends during ExceptionThrown (possible bug in clr or expected behavior)?

  2. If not bug, can I at least rely 100% on .NET framework clr profiler UnwindExceptionFunctionEnter callback be GC-safe based on similar documentation around core-clr?

Thx


Solution

  • Yes, the GC is allowed to run. The .NETCore interface is not fundamentally different from the .NETFramework interface, the github documentation is accurate.

    It is pretty easy to see when you look at the CLR source. While the tester appears to have been operating at the Ballmer Peak, his contract assertions must be accurate. Copy/pasting the relevant code:

        // Preemptive mode would be bad, dude.  There's an objectId in the param list!
        MODE_COOPERATIVE;
    

    The MODE_COOPERATIVE macro indicates that the GC is enabled. The MODE_PREEMPTIVE macro says that the GC is delayed.