Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is memory access in the lowest address space (non-null though) reported as NullReferenceException by .NET?

Tags:

c#

.net

clr

This causes an AccessViolationException to be thrown:

using System;  namespace TestApplication {     internal static class Program     {         private static unsafe void Main()         {             ulong* addr = (ulong*)Int64.MaxValue;             ulong val = *addr;         }     } } 

This causes a NullReferenceException to be thrown:

using System;  namespace TestApplication {     internal static class Program     {         private static unsafe void Main()         {             ulong* addr = (ulong*)0x000000000000FF;             ulong val = *addr;         }     } } 

They're both invalid pointers and both violate memory access rules. Why the NullReferenceException?

like image 811
Michael J. Gray Avatar asked Oct 29 '11 17:10

Michael J. Gray


People also ask

How do I fix NullReferenceException in C #?

You can eliminate the exception by declaring the number of elements in the array before initializing it, as the following example does. For more information on declaring and initializing arrays, see Arrays and Arrays. You get a null return value from a method, and then call a method on the returned type.

How do I fix this error system NullReferenceException object reference not set to an instance of an object?

The best way to avoid the "NullReferenceException: Object reference not set to an instance of an object” error is to check the values of all variables while coding. You can also use a simple if-else statement to check for null values, such as if (numbers!= null) to avoid this exception.

Why am I getting a NullReferenceException?

This error is caused when an object is trying to be used by a script but does not refer to an instance of an object. To fix this example we can acquire a reference to an instance of the script using GameObject.

What does system NullReferenceException mean?

NullReferenceException: Object reference not set to an instance of an object. This exception is thrown when you try to access any properties / methods/ indexes on a type of object which points to null.


2 Answers

This is caused by a Windows design decision made many years ago. The bottom 64 kilobytes of the address space is reserved. An access to any address in that range is reported with a null reference exception instead of the underlying access violation. This was a wise choice, a null pointer can produce reads or writes at addresses that are not actually zero. Reading a field of a C++ class object for example, it has an offset from the start of the object. If the object pointer is null then the code will bomb from reading at an address that's larger than 0.

C# doesn't have quite the same problem, the language guarantees that a null reference is caught before you can call an instance method of a class. This is however language specific, it is not a CLR feature. You can write managed code in C++/CLI and generate non-zero null pointer dereferences. Calling a method on a nullptr object works. That method will merrily execute. And call other instance methods. Until it tries to access an instance variable or call a virtual method, which requires dereferencing this, kaboom then.

The C# guarantee is very nice, it makes diagnosing null reference problems much easier since they are generated at the call site and don't bomb somewhere inside a nested method. And it is fundamentally safer, the instance variable might not trigger an exception on extremely large objects when its offset is larger than 64K. Pretty hard to do in managed code btw, unlike C++. But doesn't come for free, explained in this blog post.

like image 74
Hans Passant Avatar answered Oct 16 '22 23:10

Hans Passant


A null reference exception and an access violation exception are both raised by the CPU as an access violation. The CLR then has to guess whether the access violation should be specialized to a null reference exception or left as the more general access violation.

It is evident from your results that the CLR infers that access violations at addresses very close to 0 are caused by a null reference. Because they were almost certainly generated by a null reference plus field offset. Your use of unsafe code fools this heuristic.

like image 21
Raymond Chen Avatar answered Oct 16 '22 23:10

Raymond Chen