2

Is it ok to use a reference return of the converted pointer's value?

I have read this question. How is return by reference implemented in C#?

Is it ok to use the code below about garbage collector's memory move problem. (Helper.GetReference() & Helper.GetPointer())

class Program
{
    static unsafe void Main(string[] args)
    {
        byte[] bytes = new byte[1024];

        ref SomeStruct reference = ref Helper.GetReference<SomeStruct>(bytes);
        reference.field1 = 1;
        reference.field2 = 2;

        SomeStruct* pointer = Helper.GetPointer<SomeStruct>(bytes);
        pointer->field1 = 3;
        pointer->field2 = 4;
    }
}

public static class Helper
{
    // Can I use this?
    public static unsafe ref T GetReference<T>(byte[] bytes) where T : unmanaged
    {
        fixed (byte* p1 = bytes)
        {
            T* p2 = (T*)p1;
            return ref *p2;
        }
    }

    // Shouldn't I use it?
    public static unsafe T* GetPointer<T>(byte[] bytes) where T : unmanaged
    {
        fixed (byte* p1 = bytes)
        {
            return (T*)p1;
        }
    }
}

public struct SomeStruct
{
    public int field1;
    public int field2;
}
go kim
  • 23
  • 5

1 Answers1

2

As far i know, both of these methods are unsafe... Yes it does compile, however, because you have used unsafe in your Helper methods and referenced the same memory, your safety-net has been blown.

You are pointing to a portion of memory (a managed object) that can be moved by the Garbage Collector (aka your array), potentially leaving you with a dangling-pointer

You would need to fix (fixed) the array in your Main method to ensure safety (they way i see it), or your struct

Eg

fixed (byte* p = bytes) // even though p isn't being used
{
   SomeStruct* pointer = Helper.GetPointer<SomeStruct>(bytes);
   pointer->field1 = 3;
   pointer->field2 = 4;
}
TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • Can I ask you one more question? Is it ok to fix(fixed) SomeStruct like below?. fixed (SomeStruct* fixedPointer = &Helper.GetReference(bytes)) { s->field1 = 5; s->field2 = 6; } – go kim Feb 14 '20 at 05:44