From ed0fad8a9e247911ce453bbbcb0cb0bcd595ca73 Mon Sep 17 00:00:00 2001 From: Bradley Grainger Date: Fri, 16 Aug 2024 20:45:23 -0700 Subject: [PATCH] Fix potential NullReferenceException. Fixes #1506 Signed-off-by: Bradley Grainger --- src/MySqlConnector/MySqlConnection.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/MySqlConnector/MySqlConnection.cs b/src/MySqlConnector/MySqlConnection.cs index 571af0e51..4e3663e66 100644 --- a/src/MySqlConnector/MySqlConnection.cs +++ b/src/MySqlConnector/MySqlConnection.cs @@ -879,13 +879,14 @@ internal ServerSession Session internal void Cancel(ICancellableCommand command, int commandId, bool isCancel) { - if (m_session?.Id is not string sessionId || State != ConnectionState.Open || m_session?.TryStartCancel(command) is not true) + // NOTE: read and cache m_session in a local variable because it can be set to null by CloseAsync on another thread + if (m_session is not { } session || State != ConnectionState.Open || !session.TryStartCancel(command)) { Log.IgnoringCancellationForCommand(m_logger, commandId); return; } - Log.CommandHasBeenCanceled(m_logger, commandId, sessionId, isCancel ? "Cancel()" : "command timeout"); + Log.CommandHasBeenCanceled(m_logger, commandId, session.Id, isCancel ? "Cancel()" : "command timeout"); try { // open a dedicated connection to the server to kill the active query @@ -894,12 +895,12 @@ internal void Cancel(ICancellableCommand command, int commandId, bool isCancel) AutoEnlist = false, Pooling = false, }; - if (m_session.IPEndPoint is { Address: { } ipAddress, Port: { } port }) + if (session.IPEndPoint is { Address: { } ipAddress, Port: { } port }) { csb.Server = ipAddress.ToString(); csb.Port = (uint) port; } - csb.UserID = m_session.UserID; + csb.UserID = session.UserID; var cancellationTimeout = GetConnectionSettings().CancellationTimeout; csb.ConnectionTimeout = cancellationTimeout < 1 ? 3u : (uint) cancellationTimeout; @@ -912,20 +913,20 @@ internal void Cancel(ICancellableCommand command, int commandId, bool isCancel) #endif using var killCommand = new MySqlCommand(killQuerySql, connection); killCommand.CommandTimeout = cancellationTimeout < 1 ? 3 : cancellationTimeout; - m_session?.DoCancel(command, killCommand); + session.DoCancel(command, killCommand); } catch (InvalidOperationException ex) { // ignore a rare race condition where the connection is open at the beginning of the method, but closed by the time // KILL QUERY is executed: https://github.com/mysql-net/MySqlConnector/issues/1002 - Log.IgnoringCancellationForClosedConnection(m_logger, ex, sessionId); - m_session?.AbortCancel(command); + Log.IgnoringCancellationForClosedConnection(m_logger, ex, session.Id); + session.AbortCancel(command); } catch (MySqlException ex) { // cancelling the query failed; setting the state back to 'Querying' will allow another call to 'Cancel' to try again - Log.CancelingCommandFailed(m_logger, ex, sessionId, command.CommandId); - m_session?.AbortCancel(command); + Log.CancelingCommandFailed(m_logger, ex, session.Id, command.CommandId); + session.AbortCancel(command); } }