Freigeben über


"Object reference not set to an instance of an object” (NullReference Exception) was intermittently reported when executing a customized receiving pipeline when de-batch an incoming message

Problem:

========

“Object
reference not set to an instance of an object” was intermittently reported when
executing a customized receiving pipeline when de-batch an incoming message.

Analysis:

========

1. The error
was caused by the following first chance Access Violation.

(2fac.347c):
Access violation - code c0000005 (first/second chance not available)

eax=1e0a7a40
ebx=1e09d858 ecx=00000000 edx=00078272 esi=1e09c998 edi=100d455c

eip=08e16ee5
esp=05daf880 ebp=05daf8c8 iopl=0 nv up ei ng nz na pe cy

cs=0023 ss=002b
ds=002b es=002b fs=0053 gs=002b efl=00010287

08e16ee5 3909
cmp dword ptr [ecx],ecx ds:002b:00000000=????????

Microsoft_BizTalk_Pipeline_Components!Microsoft.BizTalk.Component.XmlDasmReader.get_MessageContext()

Microsoft_BizTalk_Pipeline_Components!Microsoft.BizTalk.Component.XmlDasmComp.GetNext2(Microsoft.BizTalk.Component.Interop.IPipelineContext)

Microsoft_BizTalk_Pipeline_Components!Microsoft.BizTalk.Component.XmlDasmComp.GetNext(Microsoft.BizTalk.Component.Interop.IPipelineContext)

Microsoft_BizTalk_Messaging!Microsoft.BizTalk.Internal.ComponentWrapper.GetNext(Microsoft.BizTalk.Component.Interop.IPipelineContext)

Microsoft_BizTalk_Pipeline!Microsoft.BizTalk.PipelineOM.DisassemblerComponent.GetNext(Microsoft.BizTalk.Component.Interop.IPipelineContext)

Microsoft_BizTalk_Pipeline!Microsoft.BizTalk.PipelineOM.DisassemblingParserStage.GetNext(Microsoft.BizTalk.PipelineOM.IBTMPipelineContext)

Microsoft_BizTalk_Pipeline!Microsoft.BizTalk.PipelineOM.ReceivePipeline.GetNext()

2. The AV
occurred because the field m_npStk of the object XmlDasmReader is NULL.

0:038> !u
@eip

Normal JIT
generated code

Microsoft.BizTalk.Component.XmlDasmReader.get_MessageContext()

Begin 08e16ee0,
size 12

08e16ee0 8bc1
mov eax,ecx

08e16ee2 8b4820
mov ecx,dword ptr [eax+20h]

>>>
08e16ee5 3909 cmp dword ptr [ecx],ecx // Access Violation here since ecx is
zero, ecx is coming from eax+20

08e16ee7
e844dbffff call
Microsoft_BizTalk_Pipeline_Components!Microsoft.BizTalk.Component.NodeProcessorStack.get_Current()

08e16eec 8bd0
mov edx,eax

08e16eee 8b4208
mov eax,dword ptr [edx+8]

08e16ef1 c3 ret

0:038> !do
@eax

Name:
Microsoft.BizTalk.Component.XmlDasmReader

….

7933291c
40001e2 1c ...ections.ArrayList 0 instance 00000000 m_envelopes

080c923c
40001e3 20 ...odeProcessorStack 0 instance 00000000 m_npStk // eax+20 is the
field m_npStk(NodeProcessorStack) of the object
Microsoft.BizTalk.Component.XmlDasmReader

793308ec
40001e4 24 System.String 0 instance 1e0aafd0 m_docType

7933291c
40001e5 28 ...ections.ArrayList 0 instance 00000000 propertyPromotionList

....

3. The field
m_npStk is set to NULL because the XmlDasmReader.Close() method is called by
the object method ReadOnlySeekableStream.Finalize() when it is Disposed by GC.

microsoft_biztalk_pipeline_components!Microsoft.BizTalk.Component.XmlDasmReader.Close()

microsoft_biztalk_streaming!Microsoft.BizTalk.Streaming.XmlTranslatorStream.Close()

microsoft_biztalk_streaming!Microsoft.BizTalk.Streaming.ReadOnlySeekableStream.Cleanup()

microsoft_biztalk_streaming!Microsoft.BizTalk.Streaming.ReadOnlySeekableStream.Finalize()

mscorwks!FastCallFinalize

mscorwks!MethodTable::CallFinalizer

mscorwks!SVR::CallFinalizer

mscorwks!SVR::DoOneFinalization

mscorwks!SVR::FinalizeAllObjects

mscorwks!SVR::GCHeap::FinalizerThreadWorker

4. The object
ReadOnlySeekableStream was disposed above was created by the customized
pipeline component MessageValidator used in the pipeline.

microsoft_biztalk_streaming!Microsoft.BizTalk.Streaming.ReadOnlySeekableStream..ctor(System.IO.Stream)

xxxx_xxxx_xxxx_xxxx!xxxx.xxxx.xxxx.xxxx.xxxxx
(System.IO.Stream)

xxxx_xxxx_xxxx_xxxx!xxxx.xxxx.xxxx.xxxx.MessageValidator.Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext,
Microsoft.BizTalk.Message.Interop.IBaseMessage)

microsoft_biztalk_messaging!Microsoft.BizTalk.Internal.ComponentWrapper.Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext,
Microsoft.BizTalk.Message.Interop.IBaseMessage)

microsoft_biztalk_pipeline!Microsoft.BizTalk.PipelineOM.SimpleComponent.Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext,
Microsoft.BizTalk.Message.Interop.IBaseMessage)

microsoft_biztalk_pipeline!Microsoft.BizTalk.PipelineOM.SimpleStage.Execute(Microsoft.BizTalk.PipelineOM.IBTMPipelineContext,
Microsoft.BizTalk.Message.Interop.IBaseMessage, Int32)

114af168
1c7f38c6
microsoft_biztalk_pipeline!Microsoft.BizTalk.PipelineOM.Pipeline.Execute(Int32,
Int32, Microsoft.BizTalk.Message.Interop.IBaseMessage)

….

5. The problem
can be reproduced using a simple pipeline component as the below (at Validate
stage) + the default XML receiving component(at Disassemble stage) when
de-batch an incoming XML message.

….

public
IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg)

{

IBaseMessagePart
bodyPart = inmsg.BodyPart;

if (bodyPart!=null)

{

Stream
originalStrm = bodyPart.GetOriginalDataStream();

Stream strm =
null;

if
(originalStrm != null)

{

strm = new
ReadOnlySeekableStream(originalStrm);

bodyPart.Data =
strm;

//
pc.ResourceTracker.AddResource( strm ); // comments this line, the problem can
be reproduced easily, the problem will be fixed by remaining the line.

}

}

return inmsg;

}

….

Solution:

==========

This is the
coding flaw in the developed pipeline component(MessageValidator in this case),
please refer the description from the below document. (it is very good article
for Streaming Pipeline component development).

https://download.microsoft.com/download/0/7/3/073B05EF-E629-4425-9851-295B98CDE699/DevelopingAStreamingPipelineComponent.docx

……

Before
returning the message back to the pipeline in line 18, the StreamWriter object
that was created is added to the context’s ResourceTracker (line 15). This
ensures the .NET Garbage Collector does not dispose of this object and the
stream it is using. If it did, the underlying stream would have been closed and
disposed of also ll (the behaviour of the StreamWriter Dispose() method) and
would not be available for other component’s or indeed BizTalk Server itself.
Equally it also means that BizTalk Server will ensure disposing of this object
once the processing of the message is complete.

….

To add the
ResourceTracker.AddResource call in the pipeline component and let the BizTalk
engine managing the lifetime of the new created Stream object for you
.