For educational purposes, I'm writing a set of methods that cause runtime exceptions in C# to understand what all the exceptions are and what causes them. Right now, I'm tinkering with programs that cause an AccessViolationException.
The most obvious way (to me) to do this was to write to a protected memory location, like this:
System.Runtime.InteropServices.Marshal.WriteInt32(IntPtr.Zero, 0);
Just as I had hoped, this threw an AccessViolationException. I wanted to do it more concisely, so I decided to write a program with unsafe code, and do (what I thought was) exactly the same thing by assigning 0 to the zero-pointer.
unsafe
{
*(int*)0 = 0;
}
For reasons that elude me, this throws a NullReferenceException. I played around with it some and found out that using *(int*)1 instead also throws a NullReferenceException, but if you use a negative number, like *(int*)-1 it will throw an AccessViolationException.
What's going on here? Why does *(int*)0 = 0 cause a NullReferenceException, and why doesn't it cause an AccessViolationException?