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:
- Interior pointer to a (
struct
orclass
) field within a GC object instance; - Managed pointer to a (
struct
orclass
) elementT
of ArrayT[]
.
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?