Skip to content

Commit a876121

Browse files
committed
MDEV-23824 SIGSEGV in end_io_cache on REPAIR LOCAL TABLE for Aria table
Bugs fixed: - prepare_for_repair() didn't close all open files if table opened failed because of out-of-memory - If dd_recreate_table() failed, the data file was not properly restored from it's temporary name - Aria repair initializing code didn't properly clear all used structs before calling error, which caused crashed in memory-free calls. - maria_delete_table() didn't register if table open failed. This could calls my_error() to be called without returning 1 to the caller, which cased failures in my_ok() Note when merging to 10.5: - Remove the #if MYSQL_VERSION from sql_admin.cc
1 parent e6290a8 commit a876121

File tree

6 files changed

+91
-26
lines changed

6 files changed

+91
-26
lines changed

mysql-test/suite/maria/repair.result

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,19 @@ i
2222
1
2323
UNLOCK TABLES;
2424
DROP TABLE t1;
25+
#
26+
# MDEV-23824 SIGSEGV in end_io_cache on REPAIR LOCAL TABLE for Aria table
27+
#
28+
CREATE TABLE t1 (i INT) ENGINE=Aria;
29+
INSERT INTO t1 VALUES (1);
30+
SET max_session_mem_used=50000;
31+
REPAIR LOCAL TABLE t1 USE_FRM;
32+
Table Op Msg_type Msg_text
33+
t1 repair error Failed to open partially repaired table
34+
Warnings:
35+
Error 1290 The MariaDB server is running with the --max-thread-mem-used=50000 option so it cannot execute this statement
36+
REPAIR LOCAL TABLE t1;
37+
Table Op Msg_type Msg_text
38+
test.t1 repair Error The MariaDB server is running with the --max-thread-mem-used=50000 option so it cannot execute this statement
39+
test.t1 repair error Corrupt
40+
DROP TABLE t1;

mysql-test/suite/maria/repair.test

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,14 @@ SELECT * FROM INFORMATION_SCHEMA.TABLES;
2222
SELECT * FROM t1;
2323
UNLOCK TABLES;
2424
DROP TABLE t1;
25+
26+
--echo #
27+
--echo # MDEV-23824 SIGSEGV in end_io_cache on REPAIR LOCAL TABLE for Aria table
28+
--echo #
29+
30+
CREATE TABLE t1 (i INT) ENGINE=Aria;
31+
INSERT INTO t1 VALUES (1);
32+
SET max_session_mem_used=50000;
33+
REPAIR LOCAL TABLE t1 USE_FRM;
34+
REPAIR LOCAL TABLE t1;
35+
DROP TABLE t1;

sql/sql_admin.cc

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,10 @@ static int send_check_errmsg(THD *thd, TABLE_LIST* table,
9191
static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
9292
HA_CHECK_OPT *check_opt)
9393
{
94-
int error= 0;
94+
int error= 0, create_error= 0;
9595
TABLE tmp_table, *table;
9696
TABLE_LIST *pos_in_locked_tables= 0;
97-
TABLE_SHARE *share;
97+
TABLE_SHARE *share= 0;
9898
bool has_mdl_lock= FALSE;
9999
char from[FN_REFLEN],tmp[FN_REFLEN+32];
100100
const char **ext;
@@ -207,6 +207,23 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
207207
HA_EXTRA_NOT_USED, NULL);
208208
table_list->table= 0;
209209
}
210+
else
211+
{
212+
/*
213+
Table open failed, maybe because we run out of memory.
214+
Close all open tables and relaese all MDL locks
215+
*/
216+
#if MYSQL_VERSION < 100500
217+
tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
218+
table->s->db.str, table->s->table_name.str,
219+
TRUE);
220+
#else
221+
tdc_release_share(share);
222+
share->tdc->flush(thd, true);
223+
share= 0;
224+
#endif
225+
}
226+
210227
/*
211228
After this point we have an exclusive metadata lock on our table
212229
in both cases when table was successfully open in mysql_admin_table()
@@ -220,11 +237,8 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
220237
goto end;
221238
}
222239
if (dd_recreate_table(thd, table_list->db.str, table_list->table_name.str))
223-
{
224-
error= send_check_errmsg(thd, table_list, "repair",
225-
"Failed generating table from .frm file");
226-
goto end;
227-
}
240+
create_error= send_check_errmsg(thd, table_list, "repair",
241+
"Failed generating table from .frm file");
228242
/*
229243
'FALSE' for 'using_transactions' means don't postpone
230244
invalidation till the end of a transaction, but do it
@@ -237,6 +251,8 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
237251
"Failed restoring .MYD file");
238252
goto end;
239253
}
254+
if (create_error)
255+
goto end;
240256

241257
if (thd->locked_tables_list.locked_tables())
242258
{
@@ -264,7 +280,8 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
264280
if (table == &tmp_table)
265281
{
266282
closefrm(table);
267-
tdc_release_share(table->s);
283+
if (share)
284+
tdc_release_share(share);
268285
}
269286
/* In case of a temporary table there will be no metadata lock. */
270287
if (unlikely(error) && has_mdl_lock)
@@ -592,6 +609,12 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
592609
#endif
593610
DBUG_PRINT("admin", ("table: %p", table->table));
594611

612+
if (table->schema_table)
613+
{
614+
result_code= HA_ADMIN_NOT_IMPLEMENTED;
615+
goto send_result;
616+
}
617+
595618
if (prepare_func)
596619
{
597620
DBUG_PRINT("admin", ("calling prepare_func"));
@@ -650,12 +673,6 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
650673
goto send_result;
651674
}
652675

653-
if (table->schema_table)
654-
{
655-
result_code= HA_ADMIN_NOT_IMPLEMENTED;
656-
goto send_result;
657-
}
658-
659676
if ((table->table->db_stat & HA_READ_ONLY) && open_for_modify)
660677
{
661678
/* purecov: begin inspected */

storage/maria/ma_check.c

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2344,6 +2344,14 @@ static int initialize_variables_for_repair(HA_CHECK *param,
23442344
{
23452345
MARIA_SHARE *share= info->s;
23462346

2347+
/*
2348+
We have to clear these variables first, as the cleanup-in-case-of-error
2349+
handling may touch these.
2350+
*/
2351+
bzero((char*) sort_info, sizeof(*sort_info));
2352+
bzero((char*) sort_param, sizeof(*sort_param));
2353+
bzero(&info->rec_cache, sizeof(info->rec_cache));
2354+
23472355
if (share->data_file_type == NO_RECORD)
23482356
{
23492357
_ma_check_print_error(param,
@@ -2358,9 +2366,6 @@ static int initialize_variables_for_repair(HA_CHECK *param,
23582366
if (share->lock.update_status)
23592367
(*share->lock.update_status)(info);
23602368

2361-
bzero((char*) sort_info, sizeof(*sort_info));
2362-
bzero((char*) sort_param, sizeof(*sort_param));
2363-
23642369
param->testflag|= T_REP; /* for easy checking */
23652370
if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
23662371
param->testflag|= T_CALC_CHECKSUM;
@@ -2388,7 +2393,6 @@ static int initialize_variables_for_repair(HA_CHECK *param,
23882393
set_data_file_type(sort_info, info->s);
23892394
sort_info->org_data_file_type= share->data_file_type;
23902395

2391-
bzero(&info->rec_cache, sizeof(info->rec_cache));
23922396
info->rec_cache.file= info->dfile.file;
23932397
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
23942398

@@ -2869,9 +2873,13 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
28692873
_ma_reset_state(info);
28702874

28712875
end_io_cache(&param->read_cache);
2872-
end_io_cache(&sort_info.new_info->rec_cache);
2876+
if (sort_info.new_info)
2877+
{
2878+
end_io_cache(&sort_info.new_info->rec_cache);
2879+
sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
2880+
}
28732881
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
2874-
sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
2882+
28752883
sort_param.sort_info->info->in_check_table= 0;
28762884
/* this below could fail, shouldn't we detect error? */
28772885
if (got_error)
@@ -4086,10 +4094,13 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
40864094
maria_scan_end(sort_info.info);
40874095
_ma_reset_state(info);
40884096

4089-
end_io_cache(&sort_info.new_info->rec_cache);
4097+
if (sort_info.new_info)
4098+
{
4099+
end_io_cache(&sort_info.new_info->rec_cache);
4100+
sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
4101+
}
40904102
end_io_cache(&param->read_cache);
40914103
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
4092-
sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
40934104
if (got_error)
40944105
{
40954106
if (! param->error_printed)
@@ -4618,10 +4629,13 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
46184629
the share by remove_io_thread() or it was not yet started (if the
46194630
error happend before creating the thread).
46204631
*/
4621-
end_io_cache(&sort_info.new_info->rec_cache);
4632+
if (sort_info.new_info)
4633+
{
4634+
end_io_cache(&sort_info.new_info->rec_cache);
4635+
sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
4636+
}
46224637
end_io_cache(&param->read_cache);
46234638
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
4624-
sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
46254639
/*
46264640
Destroy the new data cache in case of non-quick repair. All slave
46274641
threads did either detach from the share by remove_io_thread()

storage/maria/ma_delete_table.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ int maria_delete_table(const char *name)
3030
{
3131
MARIA_HA *info;
3232
myf sync_dir;
33+
int got_error= 0, error;
3334
DBUG_ENTER("maria_delete_table");
3435

3536
#ifdef EXTRA_DEBUG
@@ -41,9 +42,13 @@ int maria_delete_table(const char *name)
4142
Unfortunately it is necessary to open the table just to check this. We use
4243
'open_for_repair' to be able to open even a crashed table.
4344
*/
45+
my_errno= 0;
4446
if (!(info= maria_open(name, O_RDONLY, HA_OPEN_FOR_REPAIR)))
4547
{
4648
sync_dir= 0;
49+
/* Ignore not found errors and wrong symlink errors */
50+
if (my_errno != ENOENT && my_errno != HA_WRONG_CREATE_OPTION)
51+
got_error= my_errno;;
4752
}
4853
else
4954
{
@@ -78,7 +83,9 @@ int maria_delete_table(const char *name)
7883
DBUG_RETURN(1);
7984
}
8085

81-
DBUG_RETURN(maria_delete_table_files(name, 0, sync_dir));
86+
if (!(error= maria_delete_table_files(name, 0, sync_dir)))
87+
error= got_error;
88+
DBUG_RETURN(error);
8289
}
8390

8491

storage/maria/ma_open.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,7 @@ static void setup_key_functions(register MARIA_KEYDEF *keyinfo)
13341334

13351335

13361336
/**
1337-
@brief Function to save and store the header in the index file (.MYI)
1337+
@brief Function to save and store the header in the index file (.MAI)
13381338
13391339
Operates under MARIA_SHARE::intern_lock if requested.
13401340
Sets MARIA_SHARE::MARIA_STATE_INFO::is_of_horizon if transactional table.

0 commit comments

Comments
 (0)