Bug #118579 Stack Overflow Exception When Connecitons Aborted During Connect
Submitted: 2 Jul 16:35 Modified: 18 Aug 11:29
Reporter: Adam Conway Email Updates:
Status: Verified Impact on me:
None 
Category:Connector / NET Severity:S2 (Serious)
Version:8.1.0 OS:Linux (Oracle Linux 9)
Assigned to: CPU Architecture:x86

[2 Jul 16:35] Adam Conway
Description:
We use the connector for a dotnet service which we have recently migrated from .Net Framework (running therefore on Windows) to .Net 8 and running on Linux.

We have an underlying issue with the service.  We are hitting a memory limit for the session and getting a lot of errors (which we log to the DB).  However, this is resulting in a stack overflow exception in the connector/net driver which then crashes the whole service.

I am not exactly sure how to repeat, since the exception I see in journalctl for the service gives a stack trace that never escapes the connector code to get to my code!  However, it should not be possible for this to arise, so as well as our underlying issue I see this as a bug in the connector.

What i see is this:
```
Stack overflow.
   at System.Net.Sockets.NetworkStream.Read(Byte[], Int32, Int32)
   at MySql.Data.MySqlClient.TimedStream+<ReadAsync>d__30.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.TimedStream+<ReadAsync>d__30, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<ReadAsync>d__30 ByRef)
   at MySql.Data.MySqlClient.MySqlStream+<ReadFullyAsync>d__31.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.MySqlStream+<ReadFullyAsync>d__31, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<ReadFullyAsync>d__31 ByRef)
   at MySql.Data.MySqlClient.MySqlStream+<LoadPacketAsync>d__32.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.MySqlStream+<LoadPacketAsync>d__32, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<LoadPacketAsync>d__32 ByRef)
   at MySql.Data.MySqlClient.MySqlStream+<ReadPacketAsync>d__30.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.MySqlStream+<ReadPacketAsync>d__30, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<ReadPacketAsync>d__30 ByRef)
   at MySql.Data.MySqlClient.MySqlStream.ReadPacketAsync(Boolean)
   at MySql.Data.MySqlClient.MySqlStream+<SendPacketAsync>d__33.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.MySqlStream+<SendPacketAsync>d__33, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<SendPacketAsync>d__33 ByRef)
   at MySql.Data.MySqlClient.NativeDriver+<ExecutePacketAsync>d__53.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.NativeDriver+<ExecutePacketAsync>d__53, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<ExecutePacketAsync>d__53 ByRef)
   at MySql.Data.MySqlClient.NativeDriver+<CloseAsync>d__43.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.NativeDriver+<CloseAsync>d__43, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<CloseAsync>d__43 ByRef)
   at MySql.Data.MySqlClient.Driver+<DisposeAsync>d__100.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.Driver+<DisposeAsync>d__100, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<DisposeAsync>d__100 ByRef)
   at MySql.Data.MySqlClient.Driver.DisposeAsync(Boolean, Boolean)
   at MySql.Data.MySqlClient.Driver+<CloseAsync>d__77.MoveNext()
```

How to repeat:
As said, I can't see exactly where in my code this is coming from.  The service reads config from the DSB and also logs to it.

We did some packet inspection and it looks like this happens when the request to the service is aborted during the connect phase of the DB call.
[2 Jul 16:39] Adam Conway
Also saw this - this is just a snippet, it kept repeating
```
   at MySql.Data.MySqlClient.Driver+<CloseAsync>d__77.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.Driver+<CloseAsync>d__77, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<CloseAsync>d__77 ByRef)
   at MySql.Data.MySqlClient.Driver.CloseAsync(Boolean)
   at MySql.Data.MySqlClient.NativeDriver+<HandleExceptionAsync>d__31.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.NativeDriver+<HandleExceptionAsync>d__31, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<HandleExceptionAsync>d__31 ByRef)
   at MySql.Data.MySqlClient.NativeDriver.HandleExceptionAsync(MySql.Data.MySqlClient.MySqlException, Boolean)
   at MySql.Data.MySqlClient.NativeDriver+<ExecutePacketAsync>d__53.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.NativeDriver+<ExecutePacketAsync>d__53, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<ExecutePacketAsync>d__53 ByRef)
   at MySql.Data.MySqlClient.NativeDriver.ExecutePacketAsync(MySql.Data.MySqlClient.MySqlPacket, Boolean)
   at MySql.Data.MySqlClient.NativeDriver+<CloseAsync>d__43.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.NativeDriver+<CloseAsync>d__43, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<CloseAsync>d__43 ByRef)
   at MySql.Data.MySqlClient.Driver+<DisposeAsync>d__100.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.Driver+<DisposeAsync>d__100, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<DisposeAsync>d__100 ByRef)
   at MySql.Data.MySqlClient.Driver+<CloseAsync>d__77.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.Driver+<CloseAsync>d__77, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<CloseAsync>d__77 ByRef)
   at MySql.Data.MySqlClient.Driver.CloseAsync(Boolean)
   at MySql.Data.MySqlClient.NativeDriver+<HandleExceptionAsync>d__31.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.NativeDriver+<HandleExceptionAsync>d__31, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<HandleExceptionAsync>d__31 ByRef)
   at MySql.Data.MySqlClient.NativeDriver.HandleExceptionAsync(MySql.Data.MySqlClient.MySqlException, Boolean)
   at MySql.Data.MySqlClient.NativeDriver+<ExecutePacketAsync>d__53.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[MySql.Data.MySqlClient.NativeDriver+<ExecutePacketAsync>d__53, MySql.Data, Version=9.1.0.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d]](<ExecutePacketAsync>d__53 ByRef)
```
[7 Jul 11:47] MySQL Verification Team
Hello Adam,

Thank you for the bug report.
May I request you to please provide a simple test case(c# class) to reproduce this issue at our end?

Regards,
Ashwini Patil
[23 Jul 3:33] Bradley Grainger
If an exception occurs (when shutting down a connection), the following series of methods will call each other in an infinite loop, leading to StackOverflowException.

NativeDriver.CloseAsync (https://github.com/mysql/mysql-connector-net/blob/07b692810f368a9009e74bb462670015c37727be...) will call ExecutePacketAsync.

NativeDriver.ExecutePacketAsync (https://github.com/mysql/mysql-connector-net/blob/07b692810f368a9009e74bb462670015c37727be...) will call HandleExceptionAsync if an exception is thrown sending a packet to the server.

NativeDriver.HandleExceptionAsync (https://github.com/mysql/mysql-connector-net/blob/07b692810f368a9009e74bb462670015c37727be...) will call owner.CloseAsync, which is on the Driver class.

Driver.CloseAsync (https://github.com/mysql/mysql-connector-net/blob/07b692810f368a9009e74bb462670015c37727be...) will call DisposeAsync.

Driver.DisposeAsync (https://github.com/mysql/mysql-connector-net/blob/07b692810f368a9009e74bb462670015c37727be...) will call handler.CloseAsync, which is the NativeDriver.CloseAsync method.

This takes us back to the first method in the loop.

You might be able to reproduce this by injecting a failure into the TCP stream during connection shutdown.

Otherwise, you might consider switching to MySqlConnector as an alternative library that doesn't have this bug. https://mysqlconnector.net/tutorials/migrating-from-connector-net/
[8 Aug 1:00] Bugs System
No feedback was provided for this bug for over a month, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
[18 Aug 9:07] Adam Conway
I'm sorry, we see this quite a bit but I haven't been able to repo at will.  But see the comment from Bradley Grainger that describes the loop that gets created.