Description:
The MySqlDataReader can throw nullreference exceptions in its dispose method that is called from the Finalize. This will crash your application as the exception is unhandled. I seem to either get an error here:
System.NullReferenceException: Object reference not set to an instance of an object.
at MySql.Data.MySqlClient.MySqlConnection.set_Reader(MySqlDataReader value)
at MySql.Data.MySqlClient.MySqlDataReader.Close()
at MySql.Data.MySqlClient.MySqlDataReader.Dispose(Boolean disposing)
at MySql.Data.MySqlClient.MySqlDataReader.Finalize()
or here:
System.NullReferenceException: Object reference not set to an instance of an object.
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.Close()
at MySql.Data.MySqlClient.MySqlDataReader.Dispose(Boolean disposing)
at MySql.Data.MySqlClient.MySqlDataReader.Finalize()
I think the second one happens when the query is in the process of sending data back and it has a timeout.
How to repeat:
public void CrashTestFunc()
{
var provider = System.Data.Common.DbProviderFactories.GetFactory("MySql.Data.MySqlClient");
try
{
using (var conn = provider.CreateConnection())
{
conn.ConnectionString = @"<YOUR CONNECTION STRING>";
conn.Open();
using (var adapter = provider.CreateDataAdapter())
{
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "<YOUR LONG RUNNING QUERY>";
cmd.CommandTimeout = 1;
adapter.SelectCommand = cmd;
var dt = new DataTable();
adapter.Fill(dt);
}
}
}
}catch(Exception e)
{
System.Console.WriteLine("catching timeout exception");
}
}
public in Main()
{
System.Threading.Tasks.Task.Factory.StartNew(CrashTestFunc);
System.Threading.Tasks.Task.Factory.StartNew(CrashTestFunc);
System.Threading.Tasks.Task.Factory.StartNew(CrashTestFunc);
System.Threading.Thread.Sleep(10000);
}
Suggested fix:
The MySqlDataReader that is used underneath by the command and dataadapter should have been disposed of when the commmand and dataadapter were disposed. I think that is probably a bug.
If it wasn't disposed of correctly then, the finalize method should not assume the driver and driver.stream are not null. or you can catch these exceptions in dispose and not crash the program.