Why doesn't NullReferenceException contain information about what is null?

Solution 1:

An NRE is a very low-level exception. It is a hardware exception (a 'trap') generated by the processor when it is asked to read data from an address below 64K. That region of the virtual memory space is always unmapped, specifically to trap pointer bugs. It starts as an AccessViolation and gets turned into NRE by the CLR when the address is less than 0x00010000. At that point there is very little context for the exception, all that's known is the address of the machine code instruction that caused the trap.

Reverse-engineering that machine code instruction address back to a named variable in your program isn't possible. It is important that it works that way, a jitter would have to generate very inefficient code otherwise. All that can be reasonably done is recover the source code line number. That requires debugging info (a .pdb) that contains line number info. The CLR knows how to read the .pdb file and uses it to generate the exception's stack trace. However, this is often still inaccurate due to optimizations performed by the JIT optimizer, it moves code around. You'll only get a guaranteed match for the Debug build. The reason why the PDB for the Release build doesn't contain source line number info. You can change that.

This problem has a very simple solution. Check for null yourself and generate your own exception before letting the runtime do it. The test is quite cheap, well less than a nanosecond.

Solution 2:

You can setup Visual Studio to break on Throw for NullReferenceException immediately and not first at the catch block.

  • Debug
  • Exceptions
  • Common Language
  • Runtime Exceptions System
  • System.NullReferenceException (Check the box)

Then you will have a break in the line which caused the NullReferenceException.

Solution 3:

There's no trivial way to determine what was null at runtime -- the necessary information would have to be decompiled and inferred from the IL, which is sufficiently low-level that all it knows is that "the item at the top of the stack is null" but not how that item got there.

(And I don't know of such an extension, but it would be a nice debugger enhancement)

Solution 4:

NullReferenceException is thrown by the runtime, not by the language. The runtime doesn't know where the reference came; it just knows that an instruction tried to use a null reference.

In fact, the exception is "probably" the result of a native windows "invalid access violation" SEH exception, which is caught by the runtime and translated into IL exception ("probably": I have not checked if this is the case, but it's my guess of what's the most performing way to JIT the code).