Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recover containing GC object from managed 'ref' interior pointer

This question is newly relevant in light of the new ref locals and ref return features in the latest versions of C# 7:

With the increased prominence and wider use of managed--or "interior"--pointer variables in C#, occasionally you may need to recover the respective containing Pinnable GC object for such a pointer. For example, if you are passing around a managed pointer to an array element of type T, you might need the array reference T[] itself in order to call (e.g.) Array.Copy(...).

So, from managed code, is there any reasonably legitimate way to recover the containing GC object handle, given either of the following prevalent interior/managed pointer (ref, out, in) uses:

  1. Interior pointer to a (struct or class) field within a GC object instance;
  2. Managed pointer to a (struct or class) element T of Array T[].

Internally in .NET, it appears that the GC uses the following function: /coreclr/master/src/gc/gc.cpp

#ifdef INTERIOR_POINTERS
// will find all heap objects (large and small)
uint8_t* gc_heap::find_object (uint8_t* interior, uint8_t* low)
{
    ....

This code walks through known GC heaps checking for whether the specified interior pointer falls within the range of the known GC object allocations. Obviously, this method is not readily accessible from end-user managed code and, for all I know, may not even be relevant if there's no GC in progress.

I also looked through the new Span<T> and System.Memory libraries, but couldn't find a sequence of manipulations that would recover an (e.g.) array handle if you didn't start by providing it in the first place (whereby the containing handle gets squirreled away in those various structs). In cases where the _pinnable is optional (e.g. Span<T>), the GC handle in the struct is null, so if you don't opt-in from the start, there's no way to get it back.

Summary: Is there any way to recover the containing object handle from a managed pointer?

[edit:] If the managed pointer points to a value-type on the stack, it would be perfectly reasonable for the (putative) handle recovery function to indicate failure by (e.g.) returning 'null'.


Related: How does the C# garbage collector find objects whose only reference is an interior pointer?

like image 410
Glenn Slayden Avatar asked Oct 15 '18 21:10

Glenn Slayden


People also ask

How GC decides if objects are live in C#?

GC checks the below information to check if the object is live: It collects all handles of an object that are allocated by user code or by CLR. Keeps track of static objects, as they are referenced to some other objects. Use stack provided by stack walker and JIT.

Does C# support automatic garbage collection?

NET Framework. Automatic memory management is made possible by Garbage Collection in . NET Framework.

Which of the following provides automatic memory management and frees up memory when the question object is no longer required?

The garbage collector provides the following benefits: Frees developers from having to manually release memory. Allocates objects on the managed heap efficiently. Reclaims objects that are no longer being used, clears their memory, and keeps the memory available for future allocations.

What does the following stage in the automatic memory management is know as an object requiring finalization dies lives and then dies again?

However, if the object requires finalization, the object is considered live again until it is actually finalized, and then it is permanently dead. In other words, an object requiring finalization dies, lives, and then dies again. This is a very interesting phenomenon called resurrection.


1 Answers

No, recovery of the containing object from an interior pointer is not possible. During GC, interior pointers are translated into corresponding objects thanks to the so-called brick table and plug trees. Given a specified address, the proper brick table entry is calculated and corresponding plug tree is traversed to find the plug within which that address lives. Finally, that plug is scanned object-by-object to find the one that contains the considered address.

The point is those trees are built and available only during GC. So, even if such an "interior pointer recovery" API existed, it would have to wait for the GC and could provide an answer only afterwards (which seems very impractical). Other solutions, like linear memory scanning, would obviously possibly introduce tremendous overhead.

like image 83
Konrad Kokosa Avatar answered Oct 17 '22 01:10

Konrad Kokosa