10

I'm writing unit tests for an MVC web app, and I've been getting null reference exceptions because the mocked-up test objects are only partly initialized. I know which line is throwing the exceptions, and it looks something like this:

return Supervisor.RegistrationInformation.Registrations
    .Any(r =>
        r.RegistrationCountry.IsUSAOrCandada() &&
        (!DatesWorked.Start.HasValue || r.RegistrationDate <= DatesWorked.Start.Value) &&
        (!DatesWorked.End.HasValue || r.RegistrationExpirationDate >= DatesWorked.End.Value) &&
        //...

There are a lot of references in there, and any of them could be the problem. However, NullReferenceException itself doesn't seem to capture which reference blew up. The fact that I'm passing in a lambda presents another challenge: As far as I can tell, I can't step through the lambda during debugging and see which members of r are null.

Is there any way I can do one or both of the following:

  • Have Visual Studio tell me exactly which reference threw the NullReferenceException?
  • Failing that, is there a way to make the debugger step through the lambda expression (or just hover over things to see their values) as it's being evaluated by Any?

I feel like there must be a way to do these things, but I can't seem to find it. I'm on VS2010 Premium, and I have Resharper, VS Power Tools, and a couple other extensions installed. If there's an add-on that does this, I'd be fine with that.

Edit:

As Eric Lippert points out, it's impossible to pinpoint the source of an NR exception when the code has been compiled in Release configuration. I'm only asking about working in debug mode. If Visual Studio (or some extension to VS) can track the source of a reference while debugging, that would answer my question.

Edit 2:

The second question--how to break and step through a lambda--has been answered, but I'd still like to know if there's an automatic way to track down a null reference.

Justin Morgan - On strike
  • 30,035
  • 12
  • 80
  • 104

8 Answers8

17

There is not in general a way to do what you want, no. To understand why, think about what is happening when a null reference exception is thrown. Imagine that you are the compiler, and you must emit code to process a call to abc.Def.Ghi.Jkl(), where abc is a local, Def and Ghi are fields of reference type, and Jkl is a method. There is no IL instruction that can do something that complicated; you have to break it down. So you emit code for an equivalent program where everything is much simpler. You emit the program fragment:

temp1 = abc.Def;
temp2 = temp1.Ghi;
temp2.Jkl();

Suppose temp2 is null because Ghi was null. That fact will not be discovered until Jkl is invoked, at which point the thing throwing the exception does not have any knowledge of how temp2 was initialized. That happened long ago, a nanosecond in the past and machine code has no memory of the past; the null reference does not keep a little note on it that says where the null came from, any more than when you say "a = b + c", the resulting number twelve does not keep a note along with it that says "I was the sum of b and c".

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Thanks for your insight, Eric, it's great to have you around to answer these questions. Does the fact that I'm in debug mode give me any options here? I was fairly certain an optimized build would do exactly as you described, but I thought there might be an option to make the debugger track things like this (at cost of performance, no doubt). – Justin Morgan - On strike Dec 07 '11 at 16:46
  • @JustinMorgan: You're very welcome. To answer your follow-up question: the debugger these days has lots of features that I don't know about! I am not a power user of the debugger, oddly enough. Given the number of features that the thing has these days, there may well be a mode where you can peer backwards in time and ask "how did this value get here?" If there is, I don't know what it is. – Eric Lippert Dec 07 '11 at 17:04
  • While the running code doesn't and shouldn't keep note, the jitter can certainly create a mapping between execution address and IL instruction(assuming low enough optimization) from which it should be able to deduce which variable or expression caused the `NullReferenceException`. It already keeps similar mappings for other purposes. No idea if it actually does create this particular mapping, but in principle it should be able to do it. – CodesInChaos Dec 09 '11 at 23:19
  • @CodeInChaos Having the CLR keep an Instruction Pointer->IL Offset mapping around (which you can achieve by running the debugee with a CLR Profiler attached and using the COR_PRF_ENABLE_JIT_MAPS flag) would still not be sufficient, because in order to deduce exactly which C# expression is being reffered to in a specific IL offset, you would have to *decompile* the method, since the ILOffset->Code Range mapping offered by the pdb file are not finely grained enough (they generally map to statements, not expressions). – Omer Raviv Dec 10 '11 at 11:11
  • 1
    @EricLippert There is no such feature as part of Visual Studio debugger, but it does exist as part of commercial extension to Visual Studio I co-authored, in a feature called [Statement Visualization](http://www.bugaidsoftware.com/2011/11/tips-for-using-statement-visualization/) – Omer Raviv Dec 10 '11 at 11:13
  • @OmerRaviv - Great, I was hoping someone would suggest an extension that could do this. I'll definitely take a look. – Justin Morgan - On strike Dec 10 '11 at 22:33
3

This won't solve your entire problem, but it should help:

You can set a breakpoint inside the lambda -- just not in the usual way (clicking in the gutter will breakpoint the containing statement, not the innards of the lambda). You have to put the cursor inside the lambda and hit F9 -- then you'll get a breakpoint inside your lambda.

Joe White
  • 94,807
  • 60
  • 220
  • 330
2

One solution for your particular problem is to rewrite the lambda in a multiline one that evaluates every condition one by one and returns explicitely. You can then more easily trace through it and find the null reference.

Coincoin
  • 27,880
  • 7
  • 55
  • 76
  • 1
    The first two paragraphs of this question are nonsense, but the last one is a fair suggestion. `Any` is not lazy. – mqp Dec 06 '11 at 22:41
  • 1
    Wow. I don't know what I was thinking. `Any()` in a foreach? Pfffftt. I corrected it. Thanks. – Coincoin Dec 06 '11 at 22:47
  • I considered this as an option, and would have fallen back on it if I hadn't eventually found the problem code. I was wondering if it was possible to step inside the lambda without doing this (which does turn out to be possible; see **Joe White**'s comment under the question). – Justin Morgan - On strike Dec 07 '11 at 17:43
1

If you set a breakpoint here, you should be able to inspect each of the values before the line is executed and the exception is thrown. You just have to methodically look at each dereferenced item until you find the Null one. Visual Studio is very good at this sort of thing.

i_am_jorf
  • 53,608
  • 15
  • 131
  • 222
  • My issue was being able to break inside the lambda expression, or ideally to have the debugger just tell me the culprit so I can save some time. **Joe White**'s comment on the question told me how to break inside the lambda. – Justin Morgan - On strike Dec 07 '11 at 16:51
1

You can put a breakpoint inside the lambda expression, and when it hits, you should be able to hover over the expression and see their values just fine.

Looking at your code, I can see that only one of three expressions might've caused the NullRef- r, r.RegistrationCountry and DatesWorked.

Put those three expressions in your Watch window, and either ask the debugger to break on any NullReferenceException (via Debug->Exceptions), or put a breakpoint inside the lambda expression, and make it a conditional breakpoint on the condition r == null || r.RegistrationCountry == null || DatesWorked == null, and the answer should appear pretty quick.

Omer Raviv
  • 11,409
  • 5
  • 43
  • 82
  • At the time I posted the question I didn't know how to get a breakpoint inside a lambda expression, although that particular part has been answered. The conditional breakpoint and break-on-NRE ideas are both good suggestions, though. +1. – Justin Morgan - On strike Dec 07 '11 at 17:53
1

I wouldn't normally make a non-answer answer, but I think that the answer saying there is no general way to do this is not correct.

It seems to me like you could write a wrapper function taking an expression tree, decomposing each subexpression that has property and field accessors, and reconstructing it with explicit null checks that throw an informative exception on each of those accessors. Pseudocode:

static Expression<Func<T, bool>> WithNullDebugging(Expression<Func<T, bool>> exp)
{
    for each node in the expression tree
        if node is a field, property, or method accessor
            generate a null check for this member and an exception throw
            substitute the checked node for this node
        else if the node has subexpression children
            call this method recursively on each child
            substitute each checked subexpression for the subexpression

    return the fixed expression tree
}

I don't usually do metaprogramming in C#, so I'm not sure, but I think this is quite possible; someone smart let me know if it's not, and I'll remove or fix this answer.

mqp
  • 70,359
  • 14
  • 95
  • 123
  • I like this idea. It's like a debugging extension for lambda expressions. This particular issue has been solved, but if I can use something like this in the future, I'll keep it in mind. Thanks. – Justin Morgan - On strike Dec 07 '11 at 17:46
1

The immediate problem is that the lambda is wrapping a lot of complex logic up in a single statement, so you can't find where the crash happened.

But that's just a side effect. The real problem is that your code is assuming, incorrectly, that none of the references will be null.

One approach would be to try to isloate the crash and put a bandage over the "bit that broke". But that will not attack the root of the problem: there are unchecked assumptions in the code, and you already have proof that at least one of them is wrong. If another one is wrong, then at some undefined point in future, your program will probably crash again, and you will debug and bandage again. This can go on and on, and your code will get hacked about every time.

You need to put down your debugger and think about the code. All of the code, in one pass. "Desk-check" it: run through each part of the expression and ask yourself "Can this bit be null? What will happen if it is? And if so, how can I make it safe?"

That way, you will be able to re-write the entire expression in a form that you know is null-aware, and you won't ever need to debug into it to work out why it blew up.

For example, this:

    r.RegistrationCountry.IsUSAOrCandada() && 

...could cause a null dereference if r==null or if r.RegistrationCountry==null. The code needs to check for these possibilities. The "most defensive" code would be to check every reference something like this:

    r != null && r.RegistrationCountry != null && r.RegistrationCountry.IsUSAOrCandada() && 

which guarantees that each step will only be executed if the previous step succeeded. Note though, that the list may never provide r==null, so that check might not be necessary. Or r.RegistrationCountry may be a struct (a non-nullable type), so you'll know that check is unrequired. So you can avoid unnecessary checks by thinking about it. But you need to think through each part of the code to challenge and eliminate all the assumptions.

Jason Williams
  • 56,972
  • 11
  • 108
  • 137
0

yes.You need to install the Resharper extension in visual studio. Resharper is Continuous code quality analysis tool.

you can find more details on below link

https://www.jetbrains.com/resharper/

user3483639
  • 203
  • 1
  • 2
  • 5