Bug #53253 MySqlException often results in a useless stack trace
Submitted: 28 Apr 2010 14:42 Modified: 20 Jul 2010 19:24
Reporter: Craig Fowler Email Updates:
Status: Not a Bug Impact on me:
None 
Category:Connector / NET Severity:S3 (Non-critical)
Version:6.2.3 OS:Linux (Mono 1.9.1/Debian Testing)
Assigned to: Reggie Burnett CPU Architecture:Any
Tags: exception, stack-trace

[28 Apr 2010 14:42] Craig Fowler
Description:
Exceptions thrown by the MySql Connector/Net often come with useless stack traces - showing the same symptoms as improperly-rethrown exceptions.  See also #6983 (an ancient fixed bug).

Whilst that bug itself has been fixed - it seems that exceptions are still being re-thrown improperly (it could of course be more complex than that).

How to repeat:
An attachment will follow this report.  It contains a small C#/NUnit 2.4.7 project that illustrates what I am talking about.

To test it you will need to provide the MySql.Data.dll version 6.2.3 (I didn't include it in the Zip since it's just the stock one - no need to inflate the filesize needlessly).

There is also a tiny sample schema that should be imported into a MySql server (the code of the test is set with a connection string that connects to locahost, username root, no password - obviously change this in Test.cs if your connection details are different)

The test executes a query that will generate a MySql error (and thus an exception) - selecting a non-existant column from a table.

With the stock 6.2.3 MySql.Data.dll the stack trace attached to this exception is basically useless (it gets clobbered in the same way that a stack trace would be erased due to incorrect re-throwing of an exception).

If you then re-compile MySql.Data.dll with the modified MySql.Data/Provider/Source/NativeDriver.cs (I have included my slightly-modified version in the zip file) and then re-compile the test project against that modified MySql.Data.dll and re-run the test you should see a much more useful/complete stack trace for the exception.

Suggested fix:
I have included a 'fixed'

MySql.Data/Provider/Source/NativeDriver.cs

within the zip attachment.

This is not really the ideal/long-term fix however as it is really just a workaround that wraps the exception with a new one - MySqlException("Rethrown exception", ex) - in order to prevent the clobbering of the stack trace.

The original code (at this location) of NativeDriver.cs is actually correct - it should just read 'throw;' - however (somewhere else, at an unknown point in the source) I strongly suspect that an exception is being caught and re-thrown incorrectly.

I have spotted (whilst I was browsing through) that in some places Exception instances are being caught in catch blocks, stored in local variables/fields and then dealt with outside of the logic in the catch block.  It could be at one of these points that the /real/ problem has crept in, since in these places (outside the catch blocks) the 'throw;' syntax is invalid.  As a side-effect it also makes locating the actual error more difficult, since it is likely some way outside of the catch block where the exception came from.

Either way - until there can be a more thorough review of the code and refactoring to handle the catching/rethrowing of exceptions without clobbering the stack trace - this workaround puts us in a better position than before.
[28 Apr 2010 14:44] Craig Fowler
A small test case that demonstrates the issue.  See the README included and 'how to reproduce' for info

Attachment: Test.MySqlException.zip (application/zip, text), 11.41 KiB.

[3 May 2010 10:52] Tonci Grgin
Hi Craig and thanks for your report.

Although I wrote nothing inhere I am looking into it.
[3 May 2010 12:00] Tonci Grgin
Craig, although the re-throw is visible from current stack trace I like yours better.

Verified as described and waiting on Reggie to make final decision.
[23 Jun 2010 19:20] Reggie Burnett
I don't see the issue here.  I've checked this with 6.0, 6.1, and 6.2.  Here is the stacktrace I see from my testcase.  If you can show me more concretely the problem, I'll reconsider.

   at MySql.Data.MySqlClient.MySqlStream.ReadPacket() in C:\work\connector-net\6.2\MySql.Data\Provider\Source\MySqlStream.cs:line 142

   at MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int32& insertedId) in C:\work\connector-net\6.2
\MySql.Data\Provider\Source\NativeDriver.cs:line 562

   at MySql.Data.MySqlClient.Driver.GetResult(Int32 statementId, Int32& affectedRows, Int32& insertedId) in C:\work\connector-net\6.2\MySql.Data\Provider\Source\Driver.cs:line 377

   at MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId) in C:\work\connector-net\6.2\MySql.Data\Provider\Source\Driver.cs:line 366

   at MySql.Data.MySqlClient.MySqlDataReader.NextResult() in C:\work\connector-net\6.2\MySql.Data\Provider\Source\datareader.cs:line 858

   at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior) in C:\work\connector-net\6.2\MySql.Data\Provider\Source\command.cs:line 468

   at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader() in C:\work\connector-net\6.2\MySql.Data\Provider\Source\command.cs:line 347

   at MySql.Data.MySqlClient.MySqlCommand.ExecuteNonQuery() in C:\work\connector-net\6.2\MySql.Data\Provider\Source\command.cs:line 305

   at MySql.Data.MySqlClient.Tests.ExceptionTests.BadStackTrace() in C:\work\connector-net\6.2\MySql.Data\Tests\Source\ExceptionTests.cs:line 97
[5 Jul 2010 14:00] Craig Fowler
Sorry for the delay in responding on this.  Have re-opened the bug because I'm not sure if anyone will see notifications while it's "!Bg".

Either way - that stack trace you posted - I believe/assume that has been produced by Visual Studio's debugging function (since it contains source file names and line numbers, which a normal stack trace doesn't contain).

It could be that Visual Studio's debugging environment is behaving differently to the usual execution environment and hiding the issue from you.  Are you able to compile and then test outside of Visual Studio?  For example, using the standalone NUnit test runner.  Does this produce the same stack trace as the one generated inside VS?

I am personally using MonoDevelop and the standalone NUnit test runner on Linux/Mono (since I originally reported this I have upgraded to Mono 2.4.4 but I can still replicate the problem).

When I can next find some time I will try to put together a .NET framework environment on a Windows XP VM and give it a try in there using csc and the standalone NUnit GUI.
[20 Jul 2010 19:24] Reggie Burnett
I'm sorry but this is not a good solution.  First, throw; is the correct syntax for rethrowing an exception and it works fine with .NET (even outside of VS).  If mono is not handling it properly that is a Mono issue.

Second, your patch changes the type of exception that surfaces.  If a timeout occurs, I want a TimeoutException to surface in user code.  The same goes for the generic Exception block.  I'm not sure what type of exception is there but I want it to surface in the user code.

Closing as !bug.