Bug #45463 compress=true crashes in mono
Submitted: 11 Jun 2009 21:47 Modified: 19 Jun 2009 4:01
Reporter: Christian Mueller Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / NET Severity:S2 (Serious)
Version:5.2.6,6.0.4 OS:Linux (opensuse-11.0, mono-2.4)
Assigned to: CPU Architecture:Any
Tags: compression, error, Mono

[11 Jun 2009 21:47] Christian Mueller
Description:
The stress test in the "How to repeat" section, throws different exceptions or crashes after a few seconds when compression is enabled. It seems to be happen with Mono only. On Windows it runs fine. I will file it the Mono Bug System too.
Some different outputs follow:

########## CASE 1 ##########

Unhandled Exception: System.ArgumentException: Object must be an array of primitives.
  at System.Buffer.ByteLength (System.Array array) [0x00031] in /root/install/mono-2.4/mcs/class/corlib/System/Buffer.cs:67
  at System.Buffer.BlockCopy (System.Array src, Int32 srcOffset, System.Array dst, Int32 dstOffset, Int32 count) [0x00089] in /root/install/mono-2.4/mcs/class/corlib/System/Buffer.cs:111
  at System.IO.MemoryStream.Read (System.Byte[] buffer, Int32 offset, Int32 count) [0x00086] in /root/install/mono-2.4/mcs/class/corlib/System.IO/MemoryStream.cs:255
  at zlib.SupportClass.ReadInput (System.IO.Stream sourceStream, System.Byte[] target, Int32 start, Int32 count) [0x00000]
  at zlib.ZInputStream.read (System.Byte[] b, Int32 off, Int32 len) [0x00000]
  at MySql.Data.MySqlClient.CompressedStream.Read (System.Byte[] buffer, Int32 offset, Int32 count) [0x00000]
  at MySql.Data.MySqlClient.CompressedStream.ReadByte () [0x00000]
  at MySql.Data.MySqlClient.MySqlStream.LoadPacket () [0x00000]
  at MySql.Data.MySqlClient.MySqlStream.ReadPacket () [0x00000]
  at MySql.Data.MySqlClient.NativeDriver.FetchDataRow (Int32 statementId, Int32 pageSize, Int32 columns) [0x00000]
  at MySql.Data.MySqlClient.MySqlDataReader.Read () [0x00000]
  at Test.MysqlStress.StressMysqlThread () [0x0009d] in MysqlStress.cs:78

########## CASE 2 ##########

Unhandled Exception: MySql.Data.MySqlClient.MySqlException: Fatal error encountered during command execution. ---> MySql.Data.MySqlClient.MySqlException: Fatal error encountered attempting to read the resultset. ---> MySql.Data.MySqlClient.MySqlException: Reading from the stream has failed. ---> zlib.ZStreamException: inflating: unknown compression method
  at zlib.ZInputStream.read (System.Byte[] b, Int32 off, Int32 len) [0x00000]
  at MySql.Data.MySqlClient.CompressedStream.Read (System.Byte[] buffer, Int32 offset, Int32 count) [0x00000]
  at MySql.Data.MySqlClient.CompressedStream.ReadByte () [0x00000]
  at MySql.Data.MySqlClient.MySqlStream.LoadPacket () [0x00000]
  --- End of inner exception stack trace ---
  at MySql.Data.MySqlClient.MySqlStream.LoadPacket () [0x00000]
  at MySql.Data.MySqlClient.MySqlStream.ReadPacket () [0x00000]
  at MySql.Data.MySqlClient.NativeDriver.ReadResult (System.UInt64& affectedRows, System.Int64& lastInsertId) [0x00000]
  at MySql.Data.MySqlClient.MySqlDataReader.GetResultSet () [0x00000]
  at MySql.Data.MySqlClient.MySqlDataReader.NextResult () [0x00000]
  --- End of inner exception stack trace ---
  at MySql.Data.MySqlClient.MySqlDataReader.NextResult () [0x00000]
  at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader (CommandBehavior behavior) [0x00000]
  --- End of inner exception stack trace ---
  at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader (CommandBehavior behavior) [0x00000]
  at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader () [0x00000]
  at (wrapper remoting-invoke-with-check) MySql.Data.MySqlClient.MySqlCommand:ExecuteReader ()
  at MySql.Data.MySqlClient.Driver.LoadCharacterSets () [0x00000]

########## CASE 3 ##########

Unhandled Exception: MySql.Data.MySqlClient.MySqlException: Fatal error encountered during data read. ---> MySql.Data.MySqlClient.MySqlException: Reading from the stream has failed. ---> zlib.ZStreamException: inflating: unknown compression method
  at zlib.ZInputStream.read (System.Byte[] b, Int32 off, Int32 len) [0x00000]
  at MySql.Data.MySqlClient.CompressedStream.Read (System.Byte[] buffer, Int32 offset, Int32 count) [0x00000]
  at MySql.Data.MySqlClient.CompressedStream.ReadByte () [0x00000]
  at MySql.Data.MySqlClient.MySqlStream.LoadPacket () [0x00000]
  --- End of inner exception stack trace ---
  at MySql.Data.MySqlClient.MySqlStream.LoadPacket () [0x00000]
  at MySql.Data.MySqlClient.MySqlStream.ReadPacket () [0x00000]
  at MySql.Data.MySqlClient.NativeDriver.FetchDataRow (Int32 statementId, Int32 pageSize, Int32 columns) [0x00000]
  at MySql.Data.MySqlClient.MySqlDataReader.Read () [0x00000]
  --- End of inner exception stack trace ---
  at MySql.Data.MySqlClient.MySqlDataReader.Read () [0x00000]
  at Test.MysqlStress.StressMysqlThread () [0x0009d] in MysqlStress.cs:78

How to repeat:
namespace Test {
	
	using System;
	using System.Collections.Generic;
	using System.Data.Common;
	using System.Text;
	using System.Threading;
	using MySql.Data.MySqlClient;
	
	class MysqlStress {

		static string connectionString =
			"Host=192.168.0.204;Uid=root;Pwd=secret;Database=test;" +
			"Charset=utf8;Compress=true;Convert Zero Datetime=true"
		;
		static int maxRows = 100;

		public static void Main( string[] args ) {
			StressMysql();
		}
		
		public static void StressMysql() {
			MySqlConnection con = new MySqlConnection( connectionString );
			con.Open();
			MySqlCommand cmd = new MySqlCommand();
			cmd.Connection = con;
			cmd.CommandText = "DROP TABLE IF EXISTS t1";
			cmd.ExecuteNonQuery();
			cmd.CommandText =
				@"CREATE TABLE t1 (
					id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
					ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
					dt DATETIME,
					ch VARCHAR(255) CHARACTER SET utf8,
					bn VARBINARY(255),
					tx TEXT CHARACTER SET utf8
				)"
			;
			cmd.ExecuteNonQuery();
			cmd.CommandText = "INSERT INTO t1 (dt,ch,bn,tx) VALUES(?dt,?ch,?bn,?tx)";
			cmd.Parameters.Clear();
			cmd.Parameters.Add( "?dt", MySqlDbType.DateTime );
			cmd.Parameters.Add( "?ch", MySqlDbType.VarChar );
			cmd.Parameters.Add( "?bn", MySqlDbType.VarBinary );
			cmd.Parameters.Add( "?tx", MySqlDbType.Text );
			cmd.Prepare();
			for( int i = 1; i <= maxRows; i++ ) {
				cmd.Parameters[0].Value = DateTime.Now;
				cmd.Parameters[1].Value = i.ToString() + new String( 'X', 200 );
				cmd.Parameters[2].Value = Encoding.ASCII.GetBytes( i.ToString() + new String( 'X', 200 ) );
				cmd.Parameters[3].Value = new String( 'X', 16384 );
				cmd.ExecuteNonQuery();
				Console.WriteLine( "insert row {0}", i );
			}
			List<Thread> threads = new List<Thread>();
			for( int i = 1; i <= 10; i++ ) {
				Thread thread = new Thread(
					new ThreadStart( StressMysqlThread ) );
				thread.Start();
				threads.Add( thread );
			}
			while( true ) {
				Thread.Sleep( 1000 );
			}
		}

		public static void StressMysqlThread() {
			MySqlConnection con = new MySqlConnection( connectionString );
			con.Open();
			while( true ) {
				MySqlCommand cmd = new MySqlCommand();
				Random rand = new Random();
				cmd.Connection = con;
				cmd.CommandText = "SELECT * FROM t1 WHERE id > " + rand.Next( maxRows - 1 );
				Console.WriteLine( cmd.CommandText );
				DbDataReader res = cmd.ExecuteReader();
				Dictionary<string, object> row = new Dictionary<string,object>();
				while( res.Read() ) {
					row.Clear();
					for( int i = 0; i < res.FieldCount; i++ )
						row[res.GetName( i )] = res[i];
				}
				res.Close();
				Thread.Sleep( rand.Next( 1000 ) );
			}
		}
	}
}
[12 Jun 2009 8:12] Tonci Grgin
Hi Christian and thanks for your report.

Actually, cases 2 and 3 seem identical and related to:
Version 5.0.1 (Beta)

  ----------cut-----------
  Other changes
  -------------
  Replaced use of .NET 2.0 compression code with open source zlib library
  Fixed compression

Do you have open source zlib library?

Case 1 seems to be related to Bug#28204 but that should be fixed already. Can you confirm your problems on some other box, especially if it doesn't exhibit problems 2 and 3?
[12 Jun 2009 17:23] Christian Mueller
Hi,

since it happens in all versions 5.0, 5.1, 5.2, 6.0 of the net-connector but only with mono (tested 2.4 and svn snapshot) and your driver is 100% managed (right?), it could be propably a mono runtime problem. Case 4 was a crash of mono, but it was to big to send it with the report. I will try to attach it. It's also not clear which exception raise. It looks like a C buffer overrun with undefined result.

Christian
[12 Jun 2009 17:23] Christian Mueller
MysqlStress.out

Attachment: MysqlStress.out (text/plain), 24.42 KiB.

[12 Jun 2009 17:28] Christian Mueller
I have open source zlib library. What should i do with it?
[15 Jun 2009 3:07] Christian Mueller
Tests on Ubuntu 9 32-bit with build in mono 2.0.1 show the same results.
[15 Jun 2009 7:47] Tonci Grgin
Christian.

Google search reveals many many troubles with mono/ZLib combination. Have you checked with mono-project to see if this is actually their problem?
[17 Jun 2009 14:46] Reggie Burnett
verified but not sure yet if this is truly a bug in c/net
[17 Jun 2009 18:29] 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/76506
[17 Jun 2009 18:31] Reggie Burnett
fixed in 5.2.7 and 6.0.5+

We believe this is a bug in Mono.  We had to not use WeakReferences in our Compressed stream class to avoid this crash.
[18 Jun 2009 8:48] Tony Bedford
An entry was added to both the 5.2.7 and the 6.0.5 changelogs:

A Connector/NET test program that connected to MySQL Server using the connection string option compress=true crashed, but only when running on Mono. The program worked as expected when running on Microsoft Windows.

This was due to a bug in Mono. Connector/NET was modified to avoid using WeakReferences in the Compressed stream class, which was causing the crash.
[19 Jun 2009 4:01] Christian Mueller
Thank you very much. Hopefully it will help somebody else too.
Light and love to everybody :)