Skip to main content

Command Palette

Search for a command to run...

Pure Managed Code and AccessViolationException

Published
•2 min read•View as Markdown

Be careful with explicit struct layout. Even when executing purely managed code, it is possible to trigger an AccessViolationException. Before I encountered this case, I was under the impression that the CLR (Common Language Runtime) prevented such memory corruption in a managed environment.

The Problem

By using [StructLayout(LayoutKind.Explicit)], you can overlap fields of different reference types at the same memory offset. In the example below, both a string and a StringBuilder occupy the same memory address:

using System;
using System.Runtime.InteropServices;
using System.Text;

[StructLayout(LayoutKind.Explicit)]
struct MyStruct
{
    [FieldOffset(0)]
    public string Str;

    [FieldOffset(0)]
    public StringBuilder Builder;
}

class Program
{
    static void Main()
    {
        MyStruct mystery = new MyStruct();

        // We assign a string reference to the memory location
        mystery.Str = "hello";
        Console.WriteLine($"String value: {mystery.Str}");

        // Here is the catch: we treat that same memory location as a StringBuilder
        StringBuilder sb = mystery.Builder;

        // AccessViolationException! 
        // The runtime tries to call a StringBuilder method on a String object's memory.
        sb.Append("123"); 
    }
}

Why does this happen?

When you set FieldOffset(0) for both fields, you are essentially performing an unsafe cast without using the unsafe keyword.

  1. The variable sb now holds a reference to a memory block that is actually a System.String.

  2. When you call .Append(), the CLR attempts to access the internal fields of what it thinks is a StringBuilder (like its internal buffer or capacity).

  3. Since the internal memory structure of a String is completely different, the CPU tries to read or write to an invalid memory address, resulting in an AccessViolationException.

Summary

While the CLR provides a "sandbox" for managed code, LayoutKind.Explicit is a powerful and potentially dangerous tool. It allows you to break the type system, leading to low-level crashes that are usually associated with C++ or unmanaged code.

Rule of thumb: Never overlap reference types in an explicit layout unless you are absolutely sure of the memory implications.