3

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

user967710
  • 1,815
  • 3
  • 32
  • 58

1 Answers1

4

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.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 2
    I think this needs further explaining: While a thread is in MODE_PREEMPTIVE, anything can happen in the runtime. GC is **not** delayed. Preemptive basically tells the CLR that the current thread does not handle managed objects in any way, so this thread will never block GC. While a thread is in MODE_COOPERATIVE, a GC can only happen while this thread agrees to it (or triggers it). More information can be found at https://github.com/dotnet/coreclr/blob/master/Documentation/coding-guidelines/clr-code-guide.md#2.1.8 – Egozy May 02 '19 at 05:51
  • 1
    Adding to the above, GC can indeed happen - but you are guaranteed that the ObjectID you receive in the callback won't be moved/deleted – Egozy May 02 '19 at 05:57