1

I have a void* that points to some managed object on the heap.
How do I convert that void* value to an object (pointing to the same thing, not a copy)?

Note that this is not a duplicate of C# - How To Convert Object To IntPtr And Back? because I don't have an output of GCHandle.ToIntPtr which can be converted back to GCHandle -- I have an actual address of an object.

Andrey Shchekin
  • 21,101
  • 19
  • 94
  • 162
  • See this : https://msdn.microsoft.com/en-us/library/windows/desktop/e4y9h1at(v=vs.100).aspx – Kangjun Heo Jun 14 '18 at 04:07
  • Possible duplicate of [C# - How To Convert Object To IntPtr And Back?](https://stackoverflow.com/questions/17339928/c-sharp-how-to-convert-object-to-intptr-and-back) – Kangjun Heo Jun 14 '18 at 04:10
  • @P.Knowledge Does `GCHandle.FromIntPtr` take a heap pointer? Documentation says "An IntPtr handle to a managed object" -- not sure what it means by IntPtr "handle" -- just a direct pointer? – Andrey Shchekin Jun 14 '18 at 04:25
  • @P.Knowledge Hmm, does not seem so: https://stackoverflow.com/a/17332274/39068. – Andrey Shchekin Jun 14 '18 at 04:26
  • Well, as you said, you have a `void*` pointer, right? .NET supports various way of using pointers, like `IntPtr`, which contains raw pointer, to handle in managed environment, and `GCHandle` is a structure to handle unmanaged memory, including pointers. – Kangjun Heo Jun 14 '18 at 04:30
  • This can be help: https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.gchandle(v=vs.110).aspx, https://msdn.microsoft.com/en-us/library/system.intptr(v=vs.110).aspx – Kangjun Heo Jun 14 '18 at 04:34
  • I can convert `void*` to `IntPtr`, however what's the next step? (`IntPtr` to `object`) – Andrey Shchekin Jun 14 '18 at 04:34
  • Then use `GCHandle.FromIntPtr(IntPtr)` and get `Target` and cast to appropriate type what you want. – Kangjun Heo Jun 14 '18 at 04:36
  • @P.Knowledge This should not be possible according to https://stackoverflow.com/a/17332274/39068. _FromIntPtr does not take the address of the object, it takes an opaque value_ – Andrey Shchekin Jun 14 '18 at 05:28
  • @AndreyShchekin You shouldn't have the address of a managed object unless you pinned it with `GCHandle` (or the equivalent of C++/CLI)... So how did you got this address? Remember that if you didn't pin it, the GC could have moved the object and the `void*` would be pointing to freed memory. – xanatos Jun 14 '18 at 06:38

1 Answers1

4

What you are trying to do is wrong on many levels... If the managed object isn't pinned, then it can be moved by the GC whenever it wants, so your void* will become illegal.

But you made a question. And I'll give you rope to hang yourself.

[StructLayout(LayoutKind.Explicit)]
public struct ObjectToIntPtr
{
    [FieldOffset(0)]
    public object[] Objects;
    [FieldOffset(0)]
    public IntPtr[] Ptrs;
}

and then:

var array = new int[] { int.MaxValue, 1, 2, 3 };

IntPtr ptr = new ObjectToIntPtr { Objects = new[] { array } }.Ptrs[0];

int[] array2 = (int[])new ObjectToIntPtr { Ptrs = new[] { ptr } }.Objects[0];

What you want is the last line. Note that I'm using arrays inside ObjectToIntPtr because the .NET runtime doesn't like if I try to do a struct with an object plus a IntPtr, but if they are arrays then there is no problem. sizeof(object) == sizeof(IntPtr) so there is no problem even there (the memory used by a new object[10] is the same memory used by a new IntPtr[10]).

xanatos
  • 109,618
  • 12
  • 197
  • 280
  • Nice idea! I might go this way if I don't find anything else. _What you are trying to do is wrong on many levels..._ I know, and the whole scenario is even weirder, however it's a .NET memory research thing, and not something to power banking or aviation, so should be good. – Andrey Shchekin Jun 14 '18 at 07:42