2

EDIT

  • This question is not: What is a NullReferenceException? A NullReferenceException occurs when a member is accessed of a reference which is null.
  • This question is: How can a NullReferenceException occur when there is no member access?

END EDIT

As far as I know, a NullReferenceException can only occur when a member of a reference type is being accessed. As far as I know, the "references" this and base can never be null.

Today I was confronted with a property which throws a NullReferenceException, while there is NO member access (except for members of this and base).

My question is: How!

This is the code:

public class ComponentObject : Base
{
    private readonly XmlNamespaceManager _nsmgr;    
    public XmlNode FieldGroupContainerWerknemers { get { ... } }

    public string NumberOfMngDirectorMainShareholders
    {
        get
        {
            XmlNode fieldGroupContainerWerknemers = this.FieldGroupContainerWerknemers;
            return base.GetValue(fieldGroupContainerWerknemers, this._nsmgr, "./ns1:FieldGroup//ns1:DynamicFields//ns1:Field[@Name='DgaAantal']//ns1:Value");
        }
    }
}

And this is the exception:

Exception type: NullReferenceException
Source: Turien.Interfaces.BizTalk.Policy.Helpers
Target Site: System.String get_NumberOfMngDirectorMainShareholders()
The following is a stack trace that identifies the location where the exception occured

    at Turien.Interfaces.BizTalk.Policy.Helpers.BatchCertigo.ComponentObject.get_NumberOfMngDirectorMainShareholders()
    at Turien.Interfaces.BizTalk.Policy.Helpers.BatchTurien.BatchE.BatchE.CreateCurrentCoverageData()
    at Turien.Interfaces.BizTalk.Policy.Helpers.BatchTurien.BatchE.BatchE.CreateLetterDataBatchE()
    at Turien.Interfaces.BizTalk.Policy.Helpers.BatchTurien.BatchE.BatchE.CreateContract()
    at Turien.Interfaces.BizTalk.Policy.Helpers.BatchTurien.BatchE.BatchE.CreateBatch(XmlDocument outputdata)
    at Turien.Interfaces.BizTalk.Policy.Helpers.BatchTurien.BatchBase`1.CreateBatch(XmlDocument outputdata, String fileName, Int32 outputNumber)

Steps I have taken:

  • I searched for another property NumberOfMngDirectorMainShareholders: this is the only one.
  • I used ILSpy to spy inside the DLL. The code in production is the same as in source control.

EDIT

For the people who are telling be to debug: I'd love to. Come up with a suggestion where to put my breakpoint and which variables to check out. And further more: what to do with that information. For example: if this.FieldGroupContainerWerknemers would be null, how would that cause this situation. Or if _nsmgr is null, how would it cause this problem (keep in mind: the stacktrace points to THIS method / property!)

Martin Mulder
  • 12,642
  • 3
  • 25
  • 54
  • 1
    There doesn't have to be a member *call*, you only need member *access* if the instance reference you try to access it on is `null`. I can spot quite a few accesses in that method, `this.XYZ` are all such accesses. If any of those are properties that in turn read other stuff, you have the possibility of that exception. – Lasse V. Karlsen Sep 25 '15 at 13:57
  • @LasseV.Karlsen Wouldn't the stacktrace be a step deeper if the problem were within those properties? – James Thorpe Sep 25 '15 at 13:59
  • Also, from where do you access that property? Since the exception refers to `get_` could it be that the null reference is actually the reference to your `ComponentObject` ? I highly doubt it but it doesn't really matter. The only way to solve this kind of problem is to debug, debug, debug. Obviously *something* is null, but we can't spot that by just looking at this code. You need to find this problem at runtime. – Lasse V. Karlsen Sep 25 '15 at 13:59
  • 1
    @JamesThorpe Most likely, but it depends on attributes as well, you can hide things from exception stacks if you only want user-provided code. But yes, I agree that this is not very likely. They're not commonly used (even I cannot remember them, only that I've seen them) outside of the compiler stage. – Lasse V. Karlsen Sep 25 '15 at 14:00
  • @LasseV.Karlsen I was unaware of such attributes - time to go reading, thanks! – James Thorpe Sep 25 '15 at 14:01
  • 1
    `base.GetValue`? your base is `object` in this sample code – Brett Caswell Sep 25 '15 at 14:03
  • @BrettCaswell: You are correct. A copy-paste error from my part. I corrected it. – Martin Mulder Sep 25 '15 at 14:04
  • @LasseV.Karlsen: If it would have been a call deep inside a property or something, it would have shown in the stacktrace. If it was the call to this property itself by a null reference to an instance of ComponentObject, it would have shown in the stack. – Martin Mulder Sep 25 '15 at 14:06
  • @LasseV.Karlsen: I do not think this post is duplicate with the one you have marked it with: The other post is a junior developer asking about his first NullReferenceException. This question is from a lead developer which has asked other senior developers to verify his... feeling of surprise. Please restore this post to its original status. – Martin Mulder Sep 25 '15 at 14:08
  • 1
    @LasseV.Karlsen: I think that 49% of the questions of this site can be answered with: Debug, debug, debug. I think 49% of the questions of this site can be answered with: Read, learn, try again. But this situation is pretty unique and your suggestion simply does not answer my question. Nor does the page you have found as duplicate. – Martin Mulder Sep 25 '15 at 14:12
  • If you really believe you have a different situation here, you should attempt to create an [MCVE](http://stackoverflow.com/help/mcve) that can reproduce the exhibited behavior. Then it would be easier for us to dig into and see if it's different or not. Ideally, this would take the form of a small console app, we could just copy and paste a single code file. – mason Sep 25 '15 at 14:12
  • I can restore it but I'm not convinced. That duplicate is the go-to question here on SO for NullReferenceException because it precisely answers almost all of those questions, you have to debug. We can sit here assuming or hypothesizing all night but in the end you have to debug. The only thing we can come up with in these comments are different ways to debug the problem but you still have to debug. That is still the answer. I'm not convinced this is different so I'm not going to reopen it. Someone else (or enough other people) might decide otherwise, I will certainly not reclose it. – Lasse V. Karlsen Sep 25 '15 at 14:12
  • Yes, obviously a lot of questions here on SO can be answered by "you find it out by debugging", that's not the point. The point is that typically (and this question here falls under this) there is simply not enough information present in the question itself to actually warrant an answer. *Something* is `null`, this is indisputable. We cannot see it in the code posted, this is also indisputable. What is left is debugging. Let me instead provide an actual answer: The code as posted should not produce that exception, there is no evidence that it should throw that exception. Yet it does. – Lasse V. Karlsen Sep 25 '15 at 14:15
  • I'm willing to vote to re-open if you can provide an MCVE that reproduces the behavior as I described above. – mason Sep 25 '15 at 14:17
  • @Mason: I cannot, at this point. It is a BizTalk-project, which uses this code. My machine does not support BizTalk-stuff, so I cannot debug it. The only thing I can do is read the code, analyze the and draw conclusion from it. So it basically comes down to the theoratical implicit question in the main title: How can a method cause a NullReferenceException while it is not accessing any members? – Martin Mulder Sep 25 '15 at 14:21
  • @LasseV.Karlsen: You are right that is should have used the word "access" instead of "called". I have fixed that. You say: "I can spot quite a few accesses in that method.". Can you point them out for me? Except for the members of `this` and `base`? – Martin Mulder Sep 25 '15 at 14:28
  • I would assign `base.GetValue(fieldGroupContainerWerknemers, this._nsmgr, "./ns1:FieldGroup//ns1:DynamicFields//ns1:Field[@Name='DgaAantal']//ns1:Value");` to `string` variable and put a debug point on it.. My guess it is a returning a null, and `CreateCurrentCoverageData()` is attempting to access a member from it: `NumberOfMngDirectorMainShareholders.Something` – Brett Caswell Sep 25 '15 at 14:34
  • 2
    @Brett: Thanx for the input and effort to help. But if this property would return null, and a member of that string would be accessed, the NullReferenceException would occur in `CreateCurrentCoverageData`, not in this property. – Martin Mulder Sep 25 '15 at 14:36
  • What's happening in Turien.Interfaces.BizTalk.Policy.Helpers.BatchCertigo.ComponentObject.get_NumberOfMngDirectorMainShareholders? –  Sep 25 '15 at 14:39
  • 1
    @Will: I do not understand your question. The code is in my question. – Martin Mulder Sep 25 '15 at 14:42
  • Is it possible the debug information got out of sync with the actual code? So that really the exception is happening elsewhere, but due to out of sync debug info it's misleading you and saying that it came from somewhere else? I'm not sure if that's possible, just fishing for explanations. – mason Sep 25 '15 at 15:07
  • or it's purposely suppressed.. is your base coming from your own code, or a different assembly? – Brett Caswell Sep 25 '15 at 15:08
  • .... yeah but still. –  Sep 25 '15 at 15:09
  • @mason: Nice premis. That is why I used ILSpy to look into the DLL so verify if the production code equals our source code in source control. They match. – Martin Mulder Sep 25 '15 at 15:18
  • @Will: The class contains an XmlDocument. The properties and methods are used to query this XML and return certain values or sub-nodes. Property `NumberOfMngDirectorMainShareholders` returns a value deep into the subnode which is returned from property `FieldGroupContainerWerknemers`. – Martin Mulder Sep 25 '15 at 15:21
  • There's something weird going on here beyond the NRE. Is there an inner exception? –  Sep 25 '15 at 15:22
  • Your code might be the same. But do you have .pdb files with debug information? Is it possible the .pdb files got out of sync with the .dlls? – mason Sep 25 '15 at 15:22
  • @Mason: No PDB-file. As far as I know, the PDB file is only used to find out line number in code. Without the PDB file, .NET should always be able to reconstruct the stacktrace, using reflection and such, – Martin Mulder Sep 25 '15 at 16:56
  • @Will: No, there is no inner exception. – Martin Mulder Sep 25 '15 at 16:56
  • @Mason: By the way: I am not trying to contradict you. I am really really hoping someone like you can come up with a solid story with the cause of this... hocus pocus :) – Martin Mulder Sep 25 '15 at 17:04
  • @MartinMulder I completely understand, I just haven't had to deal with .pdb files and was hoping that was a magical box that contained the solution. – mason Sep 25 '15 at 17:07
  • 1
    @Martin Mulder, what is `Base` and what is `GetValue`, is it (the base class and method) defined your assembly? does it inherit/implement a `System.Reflection` type.. like `PropertyInfo` or `MemberInfo`? – Brett Caswell Sep 25 '15 at 20:05
  • info on that - note the `[DebuggerStepThroughAttribute] [Diagnostics.DebuggerHidden]` attributes on the virtual `GetValue` methods of those types: http://referencesource.microsoft.com/#mscorlib/system/reflection/propertyinfo.cs,7f41c0c1ebadcc33 – Brett Caswell Sep 25 '15 at 20:07
  • Maybe the JIT compiler inlined some methods called from get_NumberOfMngDirectorMainShareholders()? Then the stack trace might differ from the source code. – Jakub Lortz Sep 25 '15 at 20:21
  • @MartinMulder is the issue still relevant for you? Have you obtained more information? – usr Sep 29 '15 at 21:15
  • Yes it is. I was hoping last Monday was the day of answers, but something else got priority. So somewhere this week we continue looking. – Martin Mulder Sep 29 '15 at 22:36

1 Answers1

2

The JIT compiler can inline method calls in release builds (with optimizations enabled).

In your example get_FieldGroupContainerWerknemers() or base.GetValue could have been inlined. In that case a NullReferenceException in these methods would have the stack trace pointing to get_NumberOfMngDirectorMainShareholders().

Inlining happens during JIT compilation, so you will not see it in the IL code.

Jakub Lortz
  • 14,616
  • 3
  • 25
  • 39
  • We tested this today. We recompiled the code w/o any optimizations. The exception was thrown again, but the stack trace was different: this time it was thrown in `base.GetValue`. This leads me tot conclude that `base.GetValue` was inlined in `get_FieldGroupContainerWerknemers`. Briljant theory! – Martin Mulder Sep 30 '15 at 09:24