Bug #56494 Segfault in upgrade_shared_lock_to_exclusive() for REPAIR of merge table
Submitted: 2 Sep 2010 12:07 Modified: 20 Nov 2010 22:55
Reporter: Jon Olav Hauglid Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Locking Severity:S3 (Non-critical)
Version:5.5 OS:Any
Assigned to: Jon Olav Hauglid CPU Architecture:Any
Triage: Triaged: D1 (Critical)

[2 Sep 2010 12:07] Jon Olav Hauglid
Description:
If mysql_admin_table() (used for REPAIR TABLE, OPTIMIZE TABLE etc.)
fails to open a table, it will try to continue in order to possibly
repair a corrupt table. This includes trying to upgrade the metadata
lock on the table to MDL_EXCLUSIVE.

However, if opening a merge table fails because the metadata lock on
the table cannot be acquired due to a conflicting lock on a child table,
the server will later segfault when trying to upgrade the (non-existing) lock.

How to repeat:
--source include/have_debug_sync.inc

CREATE TABLE t1 (a INT) engine=MyISAM;
CREATE TABLE t2 (a INT) engine=MyISAM;
CREATE TABLE m1 (a INT) engine=MERGE UNION=(t1, t2);

connect (con1, localhost, root);

connection default;
SET DEBUG_SYNC= 'after_lock_tables_takes_lock SIGNAL waiting WAIT_FOR repaired';
--send CREATE TABLE IF NOT EXISTS t1 (a INT);

connection con1;
SET DEBUG_SYNC= 'now WAIT_FOR waiting';
SET SESSION lock_wait_timeout= 1;
REPAIR TABLE m1;
[3 Sep 2010 13:52] 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/117524

3133 Jon Olav Hauglid	2010-09-03
      Bug #56494 Segfault in upgrade_shared_lock_to_exclusive() for
                 REPAIR of merge table
      
      This crash happened if a table maintenance statement (ANALYZE TABLE,
      REPAIR TABLE, etc.) was executed on a MERGE table and a metadata
      lock on the MERGE table could not be acquired due to a conflicting
      metadata lock on a child table.
      
      During processing of maintenance statments, the metadata lock on
      the table is upgraded. If the lock was not acquired in the first 
      place, this would cause a segfault.
      
      This patch fixes the problem by checking that we in fact have a 
      metadata lock on the table before lock upgrade is attempted.
      
      Test case added to mdl_sync.test.
[6 Sep 2010 7:20] Jon Olav Hauglid
See also Bug#56516.
[7 Sep 2010 8:45] 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/117677

3133 Jon Olav Hauglid	2010-09-07
      Bug #56494 Segfault in upgrade_shared_lock_to_exclusive() for
                 REPAIR of merge table
      
      This crash happened if a table maintenance statement (ANALYZE TABLE,
      REPAIR TABLE, etc.) was executed on a MERGE table and opening and 
      locking a child table failed. This could for example happen if a child
      table did not exist or if a lock timeout happened while waiting for
      a conflicting metadata lock to disappear.
      
      Since opening and locking the MERGE table and its children failed,
      the tables would be closed and the metadata locks released.
      The table maintenance statement would however still try to continue
      and upgrade the metadata lock on the MERGE table. But since the lock
      already had been released, this caused a segfault.
      
      This patch fixes the problem by checking that we in fact have a 
      metadata lock on the table before lock upgrade is attempted.
      
      Test case added to mdl_sync.test.
[9 Sep 2010 7:52] 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/117804

3134 Jon Olav Hauglid	2010-09-09
      Bug #56494 Segfault in upgrade_shared_lock_to_exclusive() for
                 REPAIR of merge table
      
      This crash happened if a table maintenance statement (ANALYZE TABLE,
      REPAIR TABLE, etc.) was executed on a MERGE table and opening and 
      locking a child table failed. This could for example happen if a child
      table did not exist or if a lock timeout happened while waiting for
      a conflicting metadata lock to disappear.
      
      Since opening and locking the MERGE table and its children failed,
      the tables would be closed and the metadata locks released.
      However, TABLE_LIST::table for the MERGE table would still be set,
      with its value invalid since the tables had been closed.
      This caused the table maintenance statement to try to continue
      and upgrade the metadata lock on the MERGE table. But since the lock
      already had been released, this caused a segfault.
      
      This patch fixes the problem by setting TABLE_LIST::table to NULL 
      if open_and_lock_tables() fails. This prevents the maintenance
      statement from continuing and trying to upgrade the metadata lock.
      The patch also fixes a problem where REPAIR TABLE ... USE_FRM
      would cause an assert for MERGE tables, even if child tables
      were opened successfully.
      
      Test case added to mdl_sync.test.
[17 Sep 2010 8:49] 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/118442

3141 Jon Olav Hauglid	2010-09-17
      Bug #56494 Segfault in upgrade_shared_lock_to_exclusive() for
                 REPAIR of merge table
      Bug #56422 CHECK TABLE run when the table is locked reports
                 corruption along with timeout
      
      The crash happened if a table maintenance statement (ANALYZE TABLE,
      REPAIR TABLE, etc.) was executed on a MERGE table and opening and 
      locking a child table failed. This could for example happen if a child
      table did not exist or if a lock timeout happened while waiting for
      a conflicting metadata lock to disappear.
      
      Since opening and locking the MERGE table and its children failed,
      the tables would be closed and the metadata locks released.
      However, TABLE_LIST::table for the MERGE table would still be set,
      with its value invalid since the tables had been closed.
      This caused the table maintenance statement to try to continue
      and upgrade the metadata lock on the MERGE table. But since the lock
      already had been released, this caused a segfault.
      
      This patch fixes the problem by setting TABLE_LIST::table to NULL 
      if open_and_lock_tables() fails. This prevents the maintenance
      statement from continuing and trying to upgrade the metadata lock.
      
      The patch also fixes a problem where REPAIR TABLE ... USE_FRM
      would cause an assert for MERGE tables, even if child tables
      were opened successfully.
      
      Finally, the patch changes the error message from "Corrupt" to
      "Operation failed" for a number of issues not related to table
      corruption. For example "Lock wait timeout exceeded" and 
      "Deadlock found trying to get lock".
      
      Test cases added to mdl_sync.test and check.test.
[21 Sep 2010 9:48] 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/118686

3141 Jon Olav Hauglid	2010-09-21
      Bug #56494 Segfault in upgrade_shared_lock_to_exclusive() for
                 REPAIR of merge table
      Bug #56422 CHECK TABLE run when the table is locked reports
                 corruption along with timeout
      
      The crash happened if a table maintenance statement (ANALYZE TABLE,
      REPAIR TABLE, etc.) was executed on a MERGE table and opening and 
      locking a child table failed. This could for example happen if a child
      table did not exist or if a lock timeout happened while waiting for
      a conflicting metadata lock to disappear.
      
      Since opening and locking the MERGE table and its children failed,
      the tables would be closed and the metadata locks released.
      However, TABLE_LIST::table for the MERGE table would still be set,
      with its value invalid since the tables had been closed.
      This caused the table maintenance statement to try to continue
      and upgrade the metadata lock on the MERGE table. But since the lock
      already had been released, this caused a segfault.
      
      This patch fixes the problem by setting TABLE_LIST::table to NULL 
      if open_and_lock_tables() fails. This prevents maintenance
      statements from continuing and trying to upgrade the metadata lock.
      
      The patch also includes a 5.5 version of the fix for
      Bug #46339 crash on REPAIR TABLE merge table USE_FRM.
      This bug caused REPAIR TABLE ... USE_FRM to give an assert 
      when used on merge tables.
      
      Finally, the patch changes the error message from "Corrupt" to
      "Operation failed" for a number of issues not related to table
      corruption. For example "Lock wait timeout exceeded" and 
      "Deadlock found trying to get lock".
      
      Test cases added to merge.test and check.test.
[22 Sep 2010 8:17] 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/118779

3141 Jon Olav Hauglid	2010-09-22
      Bug #56494 Segfault in upgrade_shared_lock_to_exclusive() for
                 REPAIR of merge table
      Bug #56422 CHECK TABLE run when the table is locked reports
                 corruption along with timeout
      
      The crash happened if a table maintenance statement (ANALYZE TABLE,
      REPAIR TABLE, etc.) was executed on a MERGE table and opening and 
      locking a child table failed. This could for example happen if a child
      table did not exist or if a lock timeout happened while waiting for
      a conflicting metadata lock to disappear.
      
      Since opening and locking the MERGE table and its children failed,
      the tables would be closed and the metadata locks released.
      However, TABLE_LIST::table for the MERGE table would still be set,
      with its value invalid since the tables had been closed.
      This caused the table maintenance statement to try to continue
      and upgrade the metadata lock on the MERGE table. But since the lock
      already had been released, this caused a segfault.
      
      This patch fixes the problem by setting TABLE_LIST::table to NULL 
      if open_and_lock_tables() fails. This prevents maintenance
      statements from continuing and trying to upgrade the metadata lock.
      
      The patch includes a 5.5 version of the fix for
      Bug #46339 crash on REPAIR TABLE merge table USE_FRM.
      This bug caused REPAIR TABLE ... USE_FRM to give an assert 
      when used on merge tables.
      
      The patch also enables the CHECK TABLE statement for log tables.
      Before, CHECK TABLE for log tables gave ER_CANT_LOCK_LOG_TABLE,
      yet still counted the statement as successfully executed.
      With the changes to table maintenance statement error handling
      in this patch, CHECK TABLE would no longer be considered as
      successful in this case. This would have caused upgrade scripts
      to mistakenly think that the general and slow logs are corrupted
      and have to be repaired. Enabling CHECK TABLES for log tables
      prevents this from happening.
      
      Finally, the patch changes the error message from "Corrupt" to
      "Operation failed" for a number of issues not related to table
      corruption. For example "Lock wait timeout exceeded" and 
      "Deadlock found trying to get lock".
      
      Test cases added to merge.test and check.test.
[22 Sep 2010 8:18] Jon Olav Hauglid
Pushed to mysql-5.5-runtime (5.5.7-m3).
[22 Sep 2010 8:23] Jon Olav Hauglid
Bug#56516 was marked as a duplicate of this bug.
[4 Nov 2010 1:58] Paul Dubois
Noted in 5.5.7 changelog.

The server crashed if a table maintenance statement such as ANALYZE
TABLE or REPAIR TABLE was executed on a MERGE table and opening and
locking a child table failed. For example, this could happen if a
child table did not exist or if a lock timeout happened while waiting
for a conflicting metadata lock to disappear.

As a consequence of this bug fix, it is now possible to use CHECK
TABLE for log tables without producing an error.
[9 Nov 2010 19:48] Bugs System
Pushed into mysql-5.5 5.5.7-rc (revid:sunanda.menon@sun.com-20101109182959-otkxq8vo2dcd13la) (version source revid:marko.makela@oracle.com-20100824081003-v4ecy0tga99cpxw2) (merge vers: 5.1.50) (pib:21)
[13 Nov 2010 16:14] Bugs System
Pushed into mysql-trunk 5.6.99-m5 (revid:alexander.nozdrin@oracle.com-20101113155825-czmva9kg4n31anmu) (version source revid:marko.makela@oracle.com-20100824081003-v4ecy0tga99cpxw2) (merge vers: 5.1.50) (pib:21)
[13 Nov 2010 16:39] Bugs System
Pushed into mysql-next-mr (revid:alexander.nozdrin@oracle.com-20101113160336-atmtmfb3mzm4pz4i) (version source revid:marko.makela@oracle.com-20100824081003-v4ecy0tga99cpxw2) (pib:21)