http://www.ecma-international.org/publications/standards/Ecma-335.htm
Page 334
"1.1.5.2 Managed pointers (type &)
1.2 Managed pointers (&) can point to a local variable, a method argument, a
field of an object, a field of a value
type, an element of an array, a static
field, or the address where an element
just past the end of an array would be
stored (for pointer indexes into
managed arrays). Managed pointers
cannot be null. (They shall be
reported to the garbage collector,
even if they do not point to managed
memory)"
Page 149
7.1.2 pinned
The signature encoding for pinned shall appear only in signatures that describe local variables (§15.4.1.3). While a method with a pinned local variable is executing, the VES shall not relocate the object to which the local refers. That is, if the implementation of the CLI uses a garbage collector that moves objects, the collector shall not move objects that are referenced by an active pinned local variable.
[Rationale: If unmanaged pointers are used to dereference managed objects, these objects shall be pinned. This happens, for example, when a managed object is passed to a method designed to operate with unmanaged data. end rationale]
I agree with Hans as to the rational behind the msil language design choice.
These two things are different:
int[] arry = new int[5];
fixed (int* ptr = arry)
{
...
}
vs.
int* ptr = stackalloc int[5];
If you look at the IL created for the second one, you'll see this (which I think is what you're expecting):
.locals init ([0] int32* ptr)
In the first version (your version), you're pointing to an instance of System.Array (a managed type). In my version (using stackalloc) you're pointing to what I think you're expecting to point to... a block of memory large enough for 5 ints.