In the .NET framework profiler, is ExceptionThrown 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 (version 4.1.6) and saw a specific case where I got GC during ExceptionThrown. (But that was a very rare. It 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 is different from .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 introduction, my question is:
Should the .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 the CLR or expected behavior)?
If not bug, can I at least rely 100% on .NET Framework CLR profiler UnwindExceptionFunctionEnter callback be GC-safe based on similar documentation around CoreCLR?
Yes, the GC is allowed to run. The .NET Core interface is not fundamentally different from the .NET Framework interface, and 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.