ArgumentOutOfRangeException caused by a race into TapiCall

Developer
Dec 3, 2012 at 2:05 PM

Hi,

I think I've found a bug in the TapiCall class: actually, it is a race condition that can occur while a call's state changes very quickly. 

Symptoms are a ArgumentOutOfRangeException raised in very strange and unexpected places (of course, it is not systematic).

For example, I noticed this stack trace when simply reading call's properties like caller or called number:

 

System.ArgumentOutOfRangeException: Index and count must refer to a location within the buffer.
Parameter name: bytes
   at System.Text.EncodingNLS.GetString(Byte[] bytes, Int32 index, Int32 count)
   at JulMar.Atapi.Interop.NativeMethods.GetString(Byte[] buff, Int32 offset, Int32 len, Int32 stringType)
   at JulMar.Atapi.TapiCall.get_CalledId()

 

Looking at the code of TapiLine class caused a bit of confusion to me, as the GetString() method is invoked over the LINECALLINFO class, passing its properties dwCalledIDNameOffset and dwCalledIDNameSize as offsets. So, at a first glance, it seems like misleading values coming from the underlying TSP.

But recently, I noticed also this stack trace:

 

System.ArgumentOutOfRangeException: Requested range extends past the end of the array.
   at System.Runtime.InteropServices.Marshal.CopyToManaged(IntPtr source, Object destination, Int32 startIndex, Int32 length)
   at System.Runtime.InteropServices.Marshal.Copy(IntPtr source, Byte[] destination, Int32 startIndex, Int32 length)
   at JulMar.Atapi.TapiCall.GatherCallInfo() 
   at JulMar.Atapi.TapiCall..ctor(TapiAddress addrOwner, IntPtr hCall) 
   at JulMar.Atapi.TapiLine.LineCallback(TapiEvent dwMessage, IntPtr dwParam1, IntPtr dwParam2, IntPtr dwParam3) 
   at JulMar.Atapi.TapiManager.ProcessTapiMessage(LINEMESSAGE msg) 

...and looking at TapiCall.GatherCallInfo(), the two involved lines seem quite safe. So, I focused on the _lci class member (of type LINECALLINFO).

I think the access to _lci field is not protected against any race: it is written into GatherCallInfo() (and eventually more than once) and read many other times in many other places (such as when reading call's properties). GatherCallInfo() is executed upon TapiCall construction and, of course, upon processing any call's state change.
This can obiously lead to race: for example, GatherCallInfo() itself can be executed concurrently, resulting in 2 threads updating the same structure. Or maybe, while user's application is reading a call's property (that need to access to _lci more than once), an other thread can be executing GatherCallInfo() and writing to _lci.


What do you think about?

Regards, Marco.

 

 

 

Coordinator
Dec 3, 2012 at 5:10 PM
I'm not certain you would ever see LINE_CALLSTATUS occur on two threads. It's been 7 or 8 years since I did any TAPI development but I never saw that happen with Windows 2000. However, TAPI could have changed since then, or perhaps I just got lucky! It would be easy enough to synchronize the GetCallStatus method so only one thread can execute it at a time to see if the problem goes away...

mark



On Mon, Dec 3, 2012 at 8:05 AM, rum <notifications@codeplex.com> wrote:

From: rum

Hi,

I think I've found a bug in the TapiCall class: actually, it is a race condition that can occur while a call's state changes very quickly.

Symptoms are a ArgumentOutOfRangeException raised in very strange and unexpected places (of course, it is not systematic).

For example, I noticed this stack trace when simply reading call's properties like caller or called number:

System.ArgumentOutOfRangeException: Index and count must refer to a location within the buffer.
Parameter name: bytes
   at System.Text.EncodingNLS.GetString(Byte[] bytes, Int32 index, Int32 count)
   at JulMar.Atapi.Interop.NativeMethods.GetString(Byte[] buff, Int32 offset, Int32 len, Int32 stringType)
   at JulMar.Atapi.TapiCall.get_CalledId()

Looking at the code of TapiLine class caused a bit of confusion to me, as the GetString() method is invoked over the LINECALLINFO class, passing its properties dwCalledIDNameOffset and dwCalledIDNameSize as offsets. So, at a first glance, it seems like misleading values coming from the underlying TSP.

But recently, I noticed also this stack trace:

System.ArgumentOutOfRangeException: Requested range extends past the end of the array.
   at System.Runtime.InteropServices.Marshal.CopyToManaged(IntPtr source, Object destination, Int32 startIndex, Int32 length)
   at System.Runtime.InteropServices.Marshal.Copy(IntPtr source, Byte[] destination, Int32 startIndex, Int32 length)
   at JulMar.Atapi.TapiCall.GatherCallInfo() 
   at JulMar.Atapi.TapiCall..ctor(TapiAddress addrOwner, IntPtr hCall) 
   at JulMar.Atapi.TapiLine.LineCallback(TapiEvent dwMessage, IntPtr dwParam1, IntPtr dwParam2, IntPtr dwParam3) 
   at JulMar.Atapi.TapiManager.ProcessTapiMessage(LINEMESSAGE msg) 

...and looking at TapiCall.GatherCallInfo(), the two involved lines seem quite safe. So, I focused on the _lci class member (of type LINECALLINFO).

I think the access to _lci field is not protected against any race: it is written into GatherCallInfo() (and eventually more than once) and read many other times in many other places (such as when reading call's properties). GatherCallInfo() is executed upon TapiCall construction and, of course, upon processing any call's state change.
This can obiously lead to race: for example, GatherCallInfo() itself can be executed concurrently, resulting in 2 threads updating the same structure. Or maybe, while user's application is reading a call's property (that need to access to _lci more than once), an other thread can be executing GatherCallInfo() and writing to _lci.


What do you think about?

Regards, Marco.

Read the full discussion online.

To add a post to this discussion, reply to this email (atapi@discussions.codeplex.com)

To start a new discussion for this project, email atapi@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Developer
Jan 2, 2013 at 10:10 AM

Hi Mark, 

I just committed a patch (82107) that implements synchronization (I've tested it and I've no more observed any exceptions like that). 

Marco.

Mar 8, 2013 at 9:13 AM
Hello Marco,

at first glance it looks like that this discussion also meets my problem (i just created a discussion "ForwardInfo"). As i assume the problem in the "GatherAddressStatus" method (like you had the GatherLineStatus() identified as the reason), it would be great if you could have a look at my new discussion topic, i really do appreciate any hint on that.

best regards from Austria,
Wolfgang