4

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;
    }
}
3
  • 3
    Compile it and see. That's always the best way of finding out, no point asking here... Commented Apr 9, 2012 at 16:27
  • Why would you do so? Please do not try to do C in C#! Commented Apr 9, 2012 at 16:29
  • 6
    @thecoop: Compiling it will only tell you if the code is syntactically valid, not if it is semantically valid. In this particular case, even running the code won't necessarily enable you to discover that the code is flawed. Commented Apr 9, 2012 at 18:55

5 Answers 5

18

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.

Sign up to request clarification or add additional context in comments.

2 Comments

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.
@thefiloe: I'm aware of that. How is that relevant, and which sentence of mine do you think is wrong?
11

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.

Comments

2

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)

Comments

1

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

0

No, once you leave the fixed block, the value of result is no longer valid (it may coincidentally be valid if the GC hasn't run).

The proper way to do this kind of operation is to either have a reference to a byte[] in unmanaged memory that you access through C# code, or copying the managed array into unmanaged memory.

5 Comments

Did you mean to say "fixeb block" instead of "unsafe block"?
@JaredPar - No, a fixed and unsafe are two differnt keywords. You certainly can make an unsafe variable fixed.
@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.
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.
@JaredPar: Yep, that was a brain fart on my part, meant fixed, wrote unsafe ><.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.