Question

In an answer to his own controversial question, Mash has illustrated that you don't need the "unsafe" keyword to read and write directly to the bytes of any .NET object instance. You can declare the following types:

   [StructLayout(LayoutKind.Explicit)]
   struct MemoryAccess
   {

      [FieldOffset(0)]
      public object Object;

      [FieldOffset(0)]
      public TopBytes Bytes;
   }

   class TopBytes
   {
      public byte b0;
      public byte b1;
      public byte b2;
      public byte b3;
      public byte b4;
      public byte b5;
      public byte b6;
      public byte b7;
      public byte b8;
      public byte b9;
      public byte b10;
      public byte b11;
      public byte b12;
      public byte b13;
      public byte b14;
      public byte b15;
   }

And then you can do things like change an "immutable" string. The following code prints "bar" on my machine:

 string foo = "foo";
 MemoryAccess mem = new MemoryAccess();
 mem.Object = foo;
 mem.Bytes.b8 = (byte)'b';
 mem.Bytes.b10 = (byte)'a';
 mem.Bytes.b12 = (byte)'r';
 Console.WriteLine(foo);

You can also trigger an AccessViolationException by corrupting object references with the same technique.

Question: I thought that (in pure managed C# code) the unsafe keyword was necessary to do things like this. Why is it not necessary here? Does this mean that pure managed "safe" code is not really safe at all?

Was it helpful?

Solution

OK, that is nasty... the dangers of using a union. That may work, but isn't a very good idea - I guess I'd compare it to reflection (where you can do most things). I'd be interested to see if this works in a constrained access environment - if so, it may represent a bigger problem...


I've just tested it without the "Full Trust" flag, and the runtime rejects it:

Could not load type 'MemoryAccess' from assembly 'ConsoleApplication4, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because objects overlapped at offset 0 and the assembly must be verifiable.

And to have this flag, you already need high trust - so you can already do more nasty things. Strings are a slightly different case, because they aren't normal .NET objects - but there are other examples of ways to mutate them - the "union" approach is an interesting one, though. For another hacky way (with enough trust):

string orig = "abc   ", copy = orig;
typeof(string).GetMethod("AppendInPlace",
    BindingFlags.NonPublic | BindingFlags.Instance,
    null, new Type[] { typeof(string), typeof(int) }, null)
    .Invoke(orig, new object[] { "def", 3 });
Console.WriteLine(copy); // note we didn't touch "copy", so we have
                         // mutated the same reference

OTHER TIPS

Whoops, I've muddled unsafe with fixed. Here's a corrected version:

The reason that the sample code does not require tagging with the unsafe keyword is that it does not contain pointers (see below quote for why this is regarded as unsafe). You are quite correct: "safe" might better be termed "run-time friendly". For more information on this topic I refer you to Don Box and Chris Sells Essential .NET

To quote MSDN,

In the common language runtime (CLR), unsafe code is referred to as unverifiable code. Unsafe code in C# is not necessarily dangerous; it is just code whose safety cannot be verified by the CLR. The CLR will therefore only execute unsafe code if it is in a fully trusted assembly. If you use unsafe code, it is your responsibility to ensure that your code does not introduce security risks or pointer errors.

The difference between fixed and unsafe is that fixed stops the CLR from moving things around in memory, so that things outside the run-time can safely access them, whereas unsafe is about exactly the opposite problem: while the CLR can guarantee correct resolution for a dotnet reference, it cannot do so for a pointer. You may recall various Microsofties going on about how a reference is not a pointer, and this is why they make such a fuss about a subtle distinction.

You are still opting out of the 'managed' bit. There is the underlying assumption that if you can do that then you know what you're doing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top