Bug #31174 "Repair" command on MyISAM crashes with small myisam_sort_buffer_size
Submitted: 24 Sep 2007 11:06 Modified: 23 Oct 2007 0:28
Reporter: Joerg Bruehe Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: MyISAM storage engine Severity:S1 (Critical)
Version:5.1.22-rc OS:Any
Assigned to: Alexey Kopytov CPU Architecture:Any
Tags: sr5_1

[24 Sep 2007 11:06] Joerg Bruehe
Description:
Detected in the build of 5.1.22-rc.

It happens on both AIX 5.2 and i5os, but only when doing a 32 bit build -
64 bit is ok.
Both platforms use the IBM C compiler on the PowerPC host.

Symptom:
=====
main.repair                    [ fail ]

Errors are (from /PATH/mysqltest-time) :
mysqltest: At line NNN: query 'REPAIR TABLE t1' failed: 2013: Lost connection to MySQL server during query
(the last lines may be the most important ones)

Stopping All Servers
Restoring snapshot of databases
Saving core
=====

In a debugging build, there is no crash, but different output:
-------------------------------------------------------
*** /PATH/mysql-test/r/repair.result
--- /PATH/mysql-test/r/repair.reject
***************
*** 76,89
  ('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
  ('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
  ('0'),('0'),('0'),('0'),('0'),('0'),('0');
- Warnings:
- Error 1034    myisam_sort_buffer_size is too small
- Error 1034    Number of rows changed from 0 to 157
  SET myisam_repair_threads=2;
  REPAIR TABLE t1;
  Table Op      Msg_type        Msg_text
! test.t1       repair  error   myisam_sort_buffer_size is too small
! test.t1       repair  warning Number of rows changed from 0 to 157
  test.t1       repair  status  OK
  SET myisam_repair_threads=@@global.myisam_repair_threads;
  SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size;
--- 76,85
  ('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
  ('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
  ('0'),('0'),('0'),('0'),('0'),('0'),('0');
  SET myisam_repair_threads=2;
  REPAIR TABLE t1;
  Table Op      Msg_type        Msg_text
! test.t1       repair  error   Internal error: Keys are not in order from sort
  test.t1       repair  status  OK
  SET myisam_repair_threads=@@global.myisam_repair_threads;
  SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size;
-------------------------------------------------------

How to repeat:
Found while running the test suite.
[28 Sep 2007 16:10] Ingo Strüwing
The cause for the crash is still unclear. When inserting "fprintf"s in the code path found in the backtrace, the behavior changes. After some attempts I proved that fprintf and dbx do not agree on contents of variables. This makes the debugger unusable.
[2 Oct 2007 5:59] Ingo Strüwing
I managed to build gdb on aix52, but it does not recognize the core file as a core file. :(
[4 Oct 2007 16:40] Ingo Strüwing
I tried to disable several 'register' attributes. It didn't help.
I added a lot of fprintf()s into mysys/queues.c, mysys/my_handler.c,
mysys/mf_qsort.c, storage/myisam/myisamdef.h, storage/myisam/mi_check.c,
storage/myisam/mi_search.c, and storage/myisam/sort.c.
When I started to add some, the crash path changed (it crashed at a
different place).
But now I seem to have a stable situation.
Currently the problem is that the qsort algorithm in mf_qsort.c
malfunctions so that it gets the same pointer at two places (see below
what the pointers are about).
My last action was to add fprintf()s after the use of the MEDIAN macro.
Up to this place nothing bad happens.
My next planned step was to print the result of every SWAP.
I hope to find the place where a swap is done incorrectly.
Or that inserting fprintf() into the algorithm makes it working.
If the latter happens then I would take it as proved that the compiler
is bad. Changing crash paths might even be enough, but I'd like to be
more sure that I had not missed something.

One explanation to the stuff that is sorted:
During REPAIR we sort key values.
They are stored in 'sort_keys'.
This data structure consists of two arrays:
1. An array of pointers that point into the second array.
2. An array of key strings.
The first array is sorted with qsort.
So there is no need to move the strings.
[9 Oct 2007 16:49] Alexey Kopytov
This bug is neither compiler- nor OS-specific. The following test case crashes the server on my Linux machine (I only replaced 4096 -> 4196 in the original test case):

CREATE TABLE t1(a CHAR(255), KEY(a));
SET myisam_sort_buffer_size=4196;
INSERT INTO t1 VALUES
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
('0'),('0'),('0'),('0'),('0'),('0'),('0');
SET myisam_repair_threads=2;
REPAIR TABLE t1;

The original test case failed on AIX because the internal data structures (BUFFPEK) are shorter on that platform (my_off_t is 4 bytes instead of 8, see bug #31254), so the control flow is different there (no "myisam_sort_buffer_size is too small" warning).

Perhaps the fix for bug #23175 was incomplete.
[11 Oct 2007 10:28] 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/35335

ChangeSet@1.2685, 2007-10-11 14:28:12+04:00, kaa@polly.(none) +3 -0
  Fix for bug #31174: "Repair" command on MyISAM crashes with small
  myisam_sort_buffer_size.
  
  An incorrect length of the sort buffer was used when calculating the
  maximum number of keys. When myisam_sort_buffer_size is small enough,
  this could result in the number of keys < number of
  BUFFPEK structures which in turn led to use of uninitialized BUFFPEKs.
  
  Fixed by correcting the buffer length calculation.
[17 Oct 2007 6:30] 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/35730

ChangeSet@1.2689, 2007-10-17 10:29:51+04:00, kaa@polly.(none) +2 -0
  Fixed the test case for bug #31174 to not fail on 64-bit platforms.
[18 Oct 2007 21:35] Bugs System
Pushed into 5.1.23-beta
[18 Oct 2007 21:37] Bugs System
Pushed into 5.0.52
[18 Oct 2007 21:37] Bugs System
Pushed into 4.1.24
[23 Oct 2007 0:28] Paul DuBois
Noted in 4.1.24, 5.0.52, 5.1.23 changelogs.

WIth small values of myisam_sort_buffer_size, REPAIR TABLE for MyISAM
tables could cause a server crash.