Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IdHTTP Access Violation on Disconnect

Indy 10:

two threads, thread 1 is calling Get on an TIdHTTP and blocked reading data. thread 2 will call disconnect on the same TIdHTTP in order to interrupt the Get.

I'm using Digest Authentication on the TIdHTTP and i get an AV ocassionally.

callstack for thread 1:

40491D [system.pas][System][@ClassDestroy][8989]
69EF2B [..\..\common\IdAuthenticationDigest.pas][IdAuthenticationDigest][TIdDigestAuthentication.Destroy][109]
404567 [system.pas][System][TObject.Free][8313]
6A2B69 [..\..\Common\IdHTTP.pas][IdHTTP][TIdCustomHTTP.DoOnDisconnected][1587]
534574 [IdTCPConnection.pas][IdTCPConnection][TIdTCPConnection.Disconnect][532]
534B3B [IdTCPConnection.pas][IdTCPConnection][TIdTCPConnection.Disconnect][767]
6A3FB3 [..\..\Common\IdHTTP.pas][IdHTTP][TIdCustomHTTP.DoRequest][2101]

callstack for thread 2:

402BA3 [system.pas][System][@FreeMem][2477]
404521 [system.pas][System][TObject.FreeInstance][8294]
40491D [system.pas][System][@ClassDestroy][8989]
69EF2B [..\..\common\IdAuthenticationDigest.pas][IdAuthenticationDigest]        [TIdDigestAuthentication.Destroy][109]
404567 [system.pas][System][TObject.Free][8313]
6A2B69 [..\..\Common\IdHTTP.pas][IdHTTP][TIdCustomHTTP.DoOnDisconnected][1587]
534574 [IdTCPConnection.pas][IdTCPConnection][TIdTCPConnection.Disconnect][532]
534B3B [IdTCPConnection.pas][IdTCPConnection][TIdTCPConnection.Disconnect][767]

basically at the end of the DoRequest it drops into a disconnect. seems like there's a race condition on the disconnects trying to free Request.Authentication.

downloaded the latest code for Indy 10 and looking at the code i believe the behavior should be the same.

i believe calling disconnect from another thread is the recommended usage pattern, am i wrong? is this a bug in Indy? seems like it would be necessary to lock the disconnect but hard to see what deadlocks that might create. anyone else ran into this?

like image 589
Mike Davis Avatar asked Sep 20 '12 18:09

Mike Davis


1 Answers

Yes, what you are encountering is a race condition with both threads trying to free the same Request.Authentication object twice when the socket is being disconnected. Given the stack traces, both threads would have to be disconnecting the socket at exactly the same time, because Disconnect() only calls DoOnDisconnect() if the IOHandler is still open, and the IOHandler is closed before DoOnDisconnect() is called.

What you could try doing is use the OnStatus event to enter a thread-safe lock such as a critical section or mutex in the hsDisconnecting state, and leave the lock in the hsDisconnected state. IOHandler.Close() and DoOnDisconnect() are called in between those states, so that would effectively serialize your threads so they cannot disconnect the socket and free the Request.Authentication object at the exact same time anymore.

like image 145
Remy Lebeau Avatar answered Oct 16 '22 10:10

Remy Lebeau