Bug #40005 NullReferenceException in MySqlCommand.TimeOut causing process to crash
Submitted: 13 Oct 2008 14:54 Modified: 8 Jul 2009 12:52
Reporter: Please Remove Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / NET Severity:S1 (Critical)
Version:5.1.5,5.2.3 OS:Windows
Assigned to: Reggie Burnett CPU Architecture:Any
Tags: NullReferenceException, timeout

[13 Oct 2008 14:54] Please Remove
Description:
This exception has occured a few times on our application server, causing the process to terminate:

System.NullReferenceException: Object reference not set to an instance of an object.
   bei MySql.Data.MySqlClient.MySqlCommand.TimeoutExpired(Object commandObject)
   bei System.Threading._TimerCallback.TimerCallback_Context(Object state)
   bei System.Threading.ExecutionContext.runTryCode(Object userData)
   bei System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   bei System.Threading._TimerCallback.PerformTimerCallback(Object state)

This is the code from MySqlCommand.TimeoutExpired:

MySqlCommand cmd = (commandObject as MySqlCommand);

cmd.timedOut = true;
try
{
    cmd.Cancel();
}
catch (Exception ex)
{
   // if something goes wrong, we log it and eat it.  There's really nothing
   // else we can do.
   if (connection.Settings.Logging)
       Logger.LogException(ex);
}

It seems that the cast somehow fails or null is getting passed in. Both is inexplicable to me, as the MySqlCommand clearly is passed as state to the TimerCallback:

timer = new Timer(timerDelegate, this, this.CommandTimeout * 1000, Timeout.Infinite);

How to repeat:
Not quite sure yet, will try to produce a test case.

Suggested fix:
Check if cast was successful:

MySqlCommand cmd = (commandObject as MySqlCommand);

if (cmd != null)
{
   cmd.timedOut = true;
   try
   {
      cmd.Cancel();
   }
   catch (Exception ex)
   {
      // if something goes wrong, we log it and eat it.  There's really nothing
      // else we can do.
      if (connection.Settings.Logging)
         Logger.LogException(ex);
   }
}
[14 Oct 2008 6:38] Tonci Grgin
Hi Dennis and thanks for your report.

Please do try to produce a test case for this so I can check.
[20 Oct 2008 9:58] Please Remove
Hi Tonci,

unfortunately I'm not able to provide a test case locally. Judging from our server log, this seems to have happened under high load, which I can't reproduce on my machine. But I think that my suggested fix makes sense anyway, because the cast is unsafe and could fail for other reasons.
[15 Jan 2009 19:25] Tonci Grgin
Dennis, I must agree with proposed check thus verified even though I've never seen it...
Let's see what Reggie says.
[7 Jul 2009 19:39] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/78163
[7 Jul 2009 19:40] Reggie Burnett
fixed in 5.1.8, 5.2.7, and 6.0.5.  Was never able to reproduce this but added check that user suggested.
[8 Jul 2009 12:52] Tony Bedford
An entry was added to the 5.1.8, 5.2.7 and 6.0.5 changelogs:

MySQL Connector/NET generated the following exception:

System.NullReferenceException: Object reference not set to an instance of an object.
   bei MySql.Data.MySqlClient.MySqlCommand.TimeoutExpired(Object commandObject)
   bei System.Threading._TimerCallback.TimerCallback_Context(Object state)
   bei System.Threading.ExecutionContext.runTryCode(Object userData)
   bei
System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode
code, CleanupCode backoutCode, Object userData)
   bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext,
ContextCallback callback, Object state)
   bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext,
ContextCallback callback, Object state)
   bei System.Threading._TimerCallback.PerformTimerCallback(Object state)