Unsafe method to get pointer to byte array
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.
Comments
-
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 about 12 yearsDid you mean to say "fixeb block" instead of "unsafe block"?
-
Security Hound about 12 years@JaredPar - No, a fixed and unsafe are two differnt keywords. You certainly can make an unsafe variable fixed.
-
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 afixed
block / reference will prevent movement within the heap. -
Eric Lippert about 12 yearsJared 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 about 12 years@JaredPar: Yep, that was a brain fart on my part, meant fixed, wrote unsafe ><.
-
Florian about 11 yearsyou 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 about 11 years@thefiloe: I'm aware of that. How is that relevant, and which sentence of mine do you think is wrong?