Thursday, March 15, 2012

Lesser Known CLR Custom Attributes -- UnsafeValueType

In a comment to the previous post about CLR Custom Attributes I listed some other custom attributes that the CLR recognizes (by name). Some of them I previously thought were compiler only custom attributes, so I decided to investigate them.

System.Runtime.CompilerServices.UnsafeValueTypeAttribute

The documentation for this attribute, somewhat uncharacteristically, actually explains what it does, but I decided to try it out.

Here's an example that demonstrates what it does:

using System;
using System.Runtime.CompilerServices;

//[UnsafeValueType]
struct Foo {
  public int field;
}

class Program {
  [MethodImpl(MethodImplOptions.NoOptimization)]
  static void Main() {
    int i = 1234;
    Foo foo = new Foo();
    Corrupt(ref foo, ref i);
    Console.WriteLine(i);
  }

  [MethodImpl(MethodImplOptions.NoInlining)]
  unsafe static void Corrupt(ref Foo foo, ref int unused) {
    fixed (int* p = &foo.field) {
      *(long*)p = 4567L << 32;
    }
  }
}

When you run this it prints out 4567 and terminates successfully. However, when you uncomment the //[UnsafeValueType] line and then run it again, you'll see that it prints out 1234 and crashes and if you attach a debugger you see that it crashes with error code STATUS_STACK_BUFFER_OVERRUN because the CLR inserted a canary on the stack after the unsafe value type.

As the documentation indicates, both the C++ and C# compiler use this attribute. The C++ compiler uses it to implement /GS for managed code and the C# compiler automatically applies it to the value types that it creates to represent fixed size buffers.

3/15/2012 9:42:27 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]