Bug #60212 | Server crash with corrupt fetch buffer | ||
---|---|---|---|
Submitted: | 22 Feb 2011 20:01 | Modified: | 5 Mar 2015 11:16 |
Reporter: | John Water | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: InnoDB storage engine | Severity: | S1 (Critical) |
Version: | 5.5.9 | OS: | Any |
Assigned to: | Jimmy Yang | CPU Architecture: | Any |
Tags: | nchar, server crash |
[22 Feb 2011 20:01]
John Water
[22 Feb 2011 20:55]
Peter Laursen
I have some observations: 1) I clean up the script: Using the MySQL default delimiter + removing COMMITs that are irrelevant with MySQL (as there is no BEGIN/START TRANSACTION and I assume AUTOCOMMIT = 1). So after this it looks like: DROP TABLE IF EXISTS test; CREATE TABLE test ( pk INTEGER PRIMARY KEY NOT NULL, c1 VARCHAR(2000) CHARACTER SET ucs2 NULL ); INSERT INTO test VALUES( 1, 'hello' ); INSERT INTO test VALUES( 2, NULL ); INSERT INTO test VALUES( 3, 'rat' ); INSERT INTO test VALUES( 4, '' ); INSERT INTO test VALUES( 5, REPEAT( 'nvarchar', 250 ) ); INSERT INTO test VALUES( 6, 'dummy' ); INSERT INTO test VALUES( 7, 'dummy' ); INSERT INTO test VALUES( 8, NULL ); SELECT * FROM test; 2) with MySQL 5.1.55 I can run run the script from any client multiple times. On 5.5.9 it most often crashes (but not each time - sometimes I will have to run it twice). Changing charset to utf8 does not change anything. But with latin1 charset it does not crash ever. Also if I use MyISAM it does not. Both CREATE TABLE test ( pk INTEGER PRIMARY KEY NOT NULL, c1 VARCHAR(2000) CHARACTER SET latin1 NULL) and CREATE TABLE test ( pk INTEGER PRIMARY KEY NOT NULL, c1 VARCHAR(2000) CHARACTER SET ucs2 NULL) ENGINE MYISAM;) .. never crash for me. So 1) InnoDB + specific (unicode/multibyte) charsets + 5.5.9 causes this in combination 2) The user defined DELIMITER and the COMMITs in the original test case are not required to reproduce.
[22 Feb 2011 21:26]
MySQL Verification Team
Backtrace on Vista X86_64
Attachment: backtrace_60212.txt (text/plain), 5.84 KiB.
[22 Feb 2011 21:50]
MySQL Verification Team
Thank you for the bug report.
[23 Feb 2011 7:26]
John Embretsen
Issue is not limited to Windows, I see it on Unix as well.
[23 Feb 2011 14:25]
Jimmy Yang
This seems to be a regression from bug #52199, which introduced a new function row_mysql_pad_col(), including a "do while" loop to pad column. Unfortunately, do while loop checks the condition after the padding (not before), so in following code, even if len = 0, and pad == pad_end, it will still do padding, thus corrupt the ROW_PREBUILT_FETCH_MAGIC_N marker we put before and after the prebuilt->fetch_cache[] array: +row_mysql_pad_col( .... + case 2: + /* space=0x0020 */ + pad_end = pad + len; + ut_a(!(len % 2)); + do { + *pad++ = 0x00; + *pad++ = 0x20; + } while (pad < pad_end); + break; } (gdb) p len $70 = 0 (gdb) 293 *pad++ = 0x00; 294 *pad++ = 0x20; The row length is 4007, (gdb) p table->s->reclength $77 = 4007 gdb) p prebuilt->mysql_row_len $75 = 4007 so prebuilt->fetch_cache[0] is allocated with buf = mem_alloc(prebuilt->mysql_row_len + 8); with 8 bytes for before and after ROW_PREBUILT_FETCH_MAGIC_N marker. There are two columns, 1) pk integer is 4 bytes add 1 byte length info 2) varchar(2000) character set ucs2 is 2000 X 2 = 4000 bytes add 2 byte length info. So we have total 4 + 4000 + 1 + 2 = 4007 bytes, so when it comes to row_mysql_pad_col() in row_sel_field_store_in_mysql_format(), it wrongfully padded it, thus we eventually had a memory corruption and report it when we free prebuilt->fetch_cache[0]. 0x90c81fb is our 4007th byte, and its value is ROW_PREBUILT_FETCH_MAGIC_N (0x3705c31b) (gdb) x 0x90c81fb 0x90c81fb: 0x3705c31b so we will see after row_mysql_pad_col(), its value changed by padded 0x2000 there. (gdb) x 0x90c821b 0x90c821b: 0x37052000 Fix would be simply change the do while loop to while loop, and does the check before padding.
[23 Feb 2011 14:56]
Jimmy Yang
The row_mysql_pad_col() causing the problem is used in two places, except for row_sel_field_store_in_mysql_format() in this case, it is also used in row_ins_cascade_calc_update_vec() where there was a do while loop even before bug #52199 fix, however it guarantees the pad_len > 0, so do while loop is fine, and so does current row_mysql_pad_col(). I guess this is where this do while loop originally extracted. In any case, by simply changing the do while loop in row_mysql_pad_col() to while loop (checks condition first) could solve the root cause and crash problem.
[25 Apr 2011 20:47]
John Water
I have checked the MySQL 5.5.11 GA and found this crash problem is still there. I was wondering when you will fix this problem?
[6 Oct 2011 19:05]
John Water
Are you going to fix this server crash bug?
[5 Mar 2015 11:17]
MySQL Verification Team
this was fixed in *5.5.20 and 5.6.4* Bug 13405367 - 60212 SERVER CRASH WITH CORRUPT FETCH BUFFER