Unsafe method to get pointer to byte array

10,216

Solution 1

If you are going to turn off the safety system then you are responsible for ensuring the memory safety of the program. As soon as you do, you are required to do everything safely without the safety system helping you. That's what "unsafe" means.

As the C# specification clearly says:

the address of a moveable variable can only be obtained using a fixed statement, and that address remains valid only for the duration of that fixed statement.

You are obtaining the address of a moveable variable and then using it after the duration of the fixed statement, so the address is no longer valid. You are therefore specifically required to not do precisely what you are doing.

You should not write any unsafe code until you have a thorough and deep understanding of what the rules you must follow are. Start by reading all of chapter 18 of the specification.

Solution 2

This code will compile just fine however it will lead to runtime issues. The code is essentially smuggling out a pointer to an unfixed object in the heap. The next GC which moves the MyClass type around will also move the data reference with it and any previously returned values from getData will now point to the incorrect location.

var obj = new MyClass();
unsafe byte* pValue = obj.getData();
// Assuming no GC has happened (bad assumption) then this works fine
*pValue = 42;

// Assume a GC has now happened and `obj` moved around in the heap.  The 
// following code is now over writing memory it simply doesn't own
*pValue = 42;

Did that last line cause the app to crash, overwrite a string value in another type or simply poke a value into an uninitialized array and just screw up a math problem else where? You have no idea. Best outcome is that the code just crashes quickly but in all likely hood it will do something far more subtle and evil.

Solution 3

You could use the Marshal.StructureToPtr() method instead of unsafe magic :)

StructureToPtr copies the contents of structure to the pre-allocated block of memory that the ptr parameter points to.

Marshal.StructureToPtr Method (Object, IntPtr, Boolean)

Solution 4

This code will not work (it will compile but at runtime it will cause problems). Once the fixed region ends, the data is no longer pinned.

Share:
10,216
uray
Author by

uray

i'am a programmer

Updated on June 13, 2022

Comments

  • uray
    uray about 2 years

    is this behaviour will be valid in C#

    public class MyClass
    {
        private byte[] data;
        public MyClass()
        {
            this.data = new byte[1024];
        }
        public unsafe byte* getData()
        {
            byte* result = null;
            fixed (byte* dataPtr = data)
            {
                result = dataPtr;
            }
            return result;
        }
    }
    
  • JaredPar
    JaredPar about 12 years
    Did you mean to say "fixeb block" instead of "unsafe block"?
  • Security Hound
    Security Hound about 12 years
    @JaredPar - No, a fixed and unsafe are two differnt keywords. You certainly can make an unsafe variable fixed.
  • JaredPar
    JaredPar about 12 years
    @Ramhound yes but an unsafe block doesn't protect values in any way. The this object is free to move around the GC heap even if it's currently in an unsafe block. Only a fixed block / reference will prevent movement within the heap.
  • Eric Lippert
    Eric Lippert about 12 years
    Jared is correct. The address becomes invalid when control leaves the fixed block, not when control leaves the unsafe block. See Chapter 18 of the C# specification.
  • Guvante
    Guvante about 12 years
    @JaredPar: Yep, that was a brain fart on my part, meant fixed, wrote unsafe ><.
  • Florian
    Florian about 11 years
    you are wrong. you can use the GCHandle struct by using the pinned flag to pinn an object to its memory adress until handle.Free() is called.
  • Eric Lippert
    Eric Lippert about 11 years
    @thefiloe: I'm aware of that. How is that relevant, and which sentence of mine do you think is wrong?