Bug #79245 Dispose() throws an exception
Submitted: 12 Nov 2015 9:04 Modified: 6 Sep 7:49
Reporter: Phillip Gussow Email Updates:
Status: Won't fix Impact on me:
None 
Category:Connector / NET Severity:S1 (Critical)
Version:6.9.8 OS:Microsoft Windows
Assigned to: CPU Architecture:Any

[12 Nov 2015 9:04] Phillip Gussow
Description:
I'm running the MySQL connector in an ASP.NET application. Every couple of hours my application pool crashes with the following unhandled exception: 

MySql.Data.MySqlClient.MySqlException (0x80004005): Fatal error encountered during command execution. ---> MySql.Data.MySqlClient.MySqlException (0x80004005): Fatal error encountered attempting to read the resultset. ---> MySql.Data.MySqlClient.MySqlException (0x80004005): Reading from the stream has failed. ---> System.IO.EndOfStreamException: Attempted to read past the end of the stream. 
at MySql.Data.MySqlClient.MySqlStream.ReadFully(Stream stream, Byte[] buffer, Int32 offset, Int32 count) 
at MySql.Data.MySqlClient.MySqlStream.LoadPacket() 
at MySql.Data.MySqlClient.MySqlStream.LoadPacket() 
at MySql.Data.MySqlClient.MySqlStream.ReadPacket() 
at MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int64& insertedId) 
at MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId, Boolean force) 
at MySql.Data.MySqlClient.MySqlDataReader.NextResult() 
at MySql.Data.MySqlClient.MySqlDataReader.NextResult() 
at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior) 
at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior) 
at MySql.Data.MySqlClient.MySqlCommand.ExecuteNonQuery() 
at MySql.Data.MySqlClient.MySqlTransaction.Rollback() 
at MySql.Data.MySqlClient.MySqlConnection.CloseFully() 
at MySql.Data.MySqlClient.MySqlConnection.Close() 
at MySql.Data.MySqlClient.MySqlConnection.Dispose(Boolean disposing) 
at MySql.Data.MySqlClient.MySqlConnection.Finalize() 

I've found a couple of old bugs (from 2010) which mention the same stack trace. I'm running the lastest MySql.Data version (6.9.8) 

I can image that the connector tries to gracefully close a connection to the server. But if that fails I think the Dispose should not throw an exception. The object is gone afterwards anyway. Maybe on the server there is a leftover, but the connector has no control over the server anyway. 

How to repeat:
This is a problem for me as the stack trace is coming from the GC. For context: we're using the connector via NHibernate and we're also using Quartz which uses ADO to connect to MySql.

Suggested fix:
In my oppinion the Finalize should never throw an exception. I understand you try to gracefully close a connection. But if it fails: then it is too bad. Now the whole app pool dies because of this.
[12 Nov 2015 11:57] Andrii Nikitin
For those who experience crash because of this bug - consider implementing workarounds as explained at 
https://support.microsoft.com/en-us/kb/911816
[12 Nov 2015 12:20] Phillip Gussow
Thanks for the answer Andrii. I already used method 1 to discover this stacktrace in the first place. The Event Log was talking about a deserialization error because it couldn't find the MySQl.Data dll. By adding the UnhandledException part to the app domain I came to this stacktrace.

Method one does not prevent the pool from stopping. It only gives you a chance to log the exception before it quits.

Method 2 is indeed not a good idea :D

Is there any chance this (imho) bug might be solved in a short time frame?
[16 Nov 2015 10:53] Andrii Nikitin
Could you confirm why "Method 2" is bad idea (assuming that all unhandled exceptions are logged and addressed accordingly)?

In my understanding the problem will not occur if all MySQL Connections are closed properly. So one of solutions - you should review your source code and find out where MySQL Connections are not explicitly closed before dispose.
[16 Nov 2015 10:59] Andrii Nikitin
You can also try to suppress exceptions inside MySqlConnection.Dispose() and recompile Connector .NET from source code (not guaranteed to work, but worth trying in my understanding).
[16 Nov 2015 11:06] Phillip Gussow
Method 2 can cause other problems as Microsoft is saying. 

The problem will still occur if the application cannot reach the MySql server for some other reason. In that scenario the application pool will still crash and making it impossible for the application to do damage control (like auto reconnect or something like that).

From the reviewing perspective: I'm not using the MySql connection directly. I'm using NHibernate and Quartz.NET. Both use the database. Of course it could be that one of those applications has a bug as well. But the bottom line is that it in my opinion it is bad practice to expose exceptions from the Finalize.
[18 Nov 2015 10:51] Chiranjeevi Battula
Hello Phillip Gussow,

Thank you for the bug report.
Verified based on internal discussion with dev's.

Thanks,
Chiranjeevi.
[18 Nov 2015 12:04] Phillip Gussow
That is great news! Do you have any idea on a timeline for the release? I'm not looking for a committed date (but if you have one it would be nice ;-) ) but for an idea on the lead time. That will determine for me what I need to do right now :)
[2 Dec 2015 7:17] Phillip Gussow
Any update on this?
[11 Dec 2015 9:54] Phillip Gussow
I guess not? :(
[8 Feb 2016 18:53] Amarsanaa Amgalan
is there any progress?
[3 Mar 2016 10:10] Phillip Gussow
Since no progress is being made, is it possible to fix it our selfs? This problem is killing us big time causing us to do all kinds of workarounds.

Building the DLL from sources gives another problem: the signing part. We're also using Quartz, so we'd have to custom build this as well. This will take a lot of effort from us, while the fix itself is very easy in the code. Is there any way to speed up this release cycle (it's been over 3 months!)?
[6 Sep 7:49] Shane Bester
Closing bug as internal bug had a note:
---
C/NET 6.9 series is no longer supported anymore. This issue shouldn't happen
in 6.10/8.0 series since MySqlConnection object is treated differently. I
suggest you to use the newer release (8.0.15) instead. 
---