Skip to content

Commit 4d412e9

Browse files
committed
MDEV-24758 heap-use-after-poison in innobase_add_instant_try/rec_copy
This is a backport of commit fd9ca2a (MDEV-23295) and commit 9a156e1 (MDEV-23345) to 10.3. An instant ADD/DROP/reorder column could create a dummy table object with the wrong ROW_FORMAT when innodb_default_row_format was changed between CREATE TABLE and ALTER TABLE. prepare_inplace_alter_table_dict(): If we had promised that ALGORITHM=INPLACE is supported, we must preserve the ROW_FORMAT. The rest of the changes are related to adding Alter_inplace_info::inplace_supported to cache the return value of handler::check_if_supported_inplace_alter().
1 parent 391f1aa commit 4d412e9

File tree

7 files changed

+56
-19
lines changed

7 files changed

+56
-19
lines changed

mysql-test/suite/innodb/r/default_row_format_alter.result

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,14 @@ SHOW TABLE STATUS LIKE 't1';
8282
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary
8383
t1 InnoDB # Compact # # # # # # NULL # # NULL latin1_swedish_ci NULL 0 N
8484
DROP TABLE t1;
85+
#
86+
# MDEV-24758 heap-use-after-poison in innobase_add_instant_try/rec_copy
87+
#
88+
CREATE TABLE t1 (pk INT PRIMARY KEY) CHARACTER SET utf8 ENGINE=InnoDB;
89+
INSERT INTO t1 VALUES (1);
90+
SET GLOBAL innodb_default_row_format = REDUNDANT;
91+
ALTER TABLE t1 ADD a CHAR(8) DEFAULT '';
92+
DROP TABLE t1;
93+
SET GLOBAL innodb_default_row_format = @row_format;
94+
# End of 10.3 tests
8595
SET GLOBAL innodb_default_row_format = @row_format;

mysql-test/suite/innodb/t/default_row_format_alter.test

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
--source include/have_innodb.inc
2+
--source include/innodb_row_format.inc
23

34
SET @row_format = @@GLOBAL.innodb_default_row_format;
45

@@ -95,4 +96,17 @@ ALTER TABLE t1 DROP INDEX k1;
9596
SHOW TABLE STATUS LIKE 't1';
9697
DROP TABLE t1;
9798

99+
--echo #
100+
--echo # MDEV-24758 heap-use-after-poison in innobase_add_instant_try/rec_copy
101+
--echo #
102+
103+
CREATE TABLE t1 (pk INT PRIMARY KEY) CHARACTER SET utf8 ENGINE=InnoDB;
104+
INSERT INTO t1 VALUES (1);
105+
SET GLOBAL innodb_default_row_format = REDUNDANT;
106+
ALTER TABLE t1 ADD a CHAR(8) DEFAULT '';
107+
DROP TABLE t1;
108+
SET GLOBAL innodb_default_row_format = @row_format;
109+
110+
--echo # End of 10.3 tests
111+
98112
SET GLOBAL innodb_default_row_format = @row_format;

sql/handler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,6 +2347,9 @@ class Alter_inplace_info
23472347
/** true for online operation (LOCK=NONE) */
23482348
bool online;
23492349

2350+
/** which ALGORITHM and LOCK are supported by the storage engine */
2351+
enum_alter_inplace_result inplace_supported;
2352+
23502353
/**
23512354
Can be set by handler to describe why a given operation cannot be done
23522355
in-place (HA_ALTER_INPLACE_NOT_SUPPORTED) or why it cannot be done

sql/sql_alter.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2-
Copyright (c) 2016, 2018, MariaDB Corporation
2+
Copyright (c) 2016, 2020, MariaDB Corporation
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License as published by
@@ -127,10 +127,10 @@ const char* Alter_info::lock() const
127127
}
128128

129129

130-
bool Alter_info::supports_algorithm(THD *thd, enum_alter_inplace_result result,
130+
bool Alter_info::supports_algorithm(THD *thd,
131131
const Alter_inplace_info *ha_alter_info)
132132
{
133-
switch (result) {
133+
switch (ha_alter_info->inplace_supported) {
134134
case HA_ALTER_INPLACE_EXCLUSIVE_LOCK:
135135
case HA_ALTER_INPLACE_SHARED_LOCK:
136136
case HA_ALTER_INPLACE_NO_LOCK:
@@ -171,10 +171,10 @@ bool Alter_info::supports_algorithm(THD *thd, enum_alter_inplace_result result,
171171
}
172172

173173

174-
bool Alter_info::supports_lock(THD *thd, enum_alter_inplace_result result,
174+
bool Alter_info::supports_lock(THD *thd,
175175
const Alter_inplace_info *ha_alter_info)
176176
{
177-
switch (result) {
177+
switch (ha_alter_info->inplace_supported) {
178178
case HA_ALTER_INPLACE_EXCLUSIVE_LOCK:
179179
// If SHARED lock and no particular algorithm was requested, use COPY.
180180
if (requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED &&

sql/sql_alter.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* Copyright (c) 2010, 2014, Oracle and/or its affiliates.
2-
Copyright (c) 2013, 2018, MariaDB Corporation.
2+
Copyright (c) 2013, 2020, MariaDB Corporation.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License as published by
@@ -204,29 +204,26 @@ class Alter_info
204204
with the specified user alter algorithm.
205205
206206
@param thd Thread handle
207-
@param result Operation supported for inplace alter
208207
@param ha_alter_info Structure describing changes to be done
209208
by ALTER TABLE and holding data during
210209
in-place alter
211210
@retval false Supported operation
212211
@retval true Not supported value
213212
*/
214-
bool supports_algorithm(THD *thd, enum_alter_inplace_result result,
213+
bool supports_algorithm(THD *thd,
215214
const Alter_inplace_info *ha_alter_info);
216215

217216
/**
218217
Check whether the given result can be supported
219218
with the specified user lock type.
220219
221-
@param result Operation supported for inplace alter
222220
@param ha_alter_info Structure describing changes to be done
223221
by ALTER TABLE and holding data during
224222
in-place alter
225223
@retval false Supported lock type
226224
@retval true Not supported value
227225
*/
228-
bool supports_lock(THD *thd, enum_alter_inplace_result result,
229-
const Alter_inplace_info *ha_alter_info);
226+
bool supports_lock(THD *thd, const Alter_inplace_info *ha_alter_info);
230227

231228
/**
232229
Return user requested algorithm. If user does not specify

sql/sql_table.cc

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7549,7 +7549,6 @@ static bool is_inplace_alter_impossible(TABLE *table,
75497549
@param ha_alter_info Structure describing ALTER TABLE to be carried
75507550
out and serving as a storage place for data
75517551
used during different phases.
7552-
@param inplace_supported Enum describing the locking requirements.
75537552
@param target_mdl_request Metadata request/lock on the target table name.
75547553
@param alter_ctx ALTER TABLE runtime context.
75557554
@@ -7574,7 +7573,6 @@ static bool mysql_inplace_alter_table(THD *thd,
75747573
TABLE *table,
75757574
TABLE *altered_table,
75767575
Alter_inplace_info *ha_alter_info,
7577-
enum_alter_inplace_result inplace_supported,
75787576
MDL_request *target_mdl_request,
75797577
Alter_table_ctx *alter_ctx)
75807578
{
@@ -7585,6 +7583,8 @@ static bool mysql_inplace_alter_table(THD *thd,
75857583
Alter_info *alter_info= ha_alter_info->alter_info;
75867584
bool reopen_tables= false;
75877585
bool res;
7586+
const enum_alter_inplace_result inplace_supported=
7587+
ha_alter_info->inplace_supported;
75887588

75897589
DBUG_ENTER("mysql_inplace_alter_table");
75907590

@@ -10006,27 +10006,27 @@ do_continue:;
1000610006
if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE)
1000710007
ha_alter_info.online= true;
1000810008
// Ask storage engine whether to use copy or in-place
10009-
enum_alter_inplace_result inplace_supported=
10009+
ha_alter_info.inplace_supported=
1001010010
table->file->check_if_supported_inplace_alter(altered_table,
1001110011
&ha_alter_info);
1001210012

10013-
if (alter_info->supports_algorithm(thd, inplace_supported, &ha_alter_info) ||
10014-
alter_info->supports_lock(thd, inplace_supported, &ha_alter_info))
10013+
if (alter_info->supports_algorithm(thd, &ha_alter_info) ||
10014+
alter_info->supports_lock(thd, &ha_alter_info))
1001510015
{
1001610016
thd->drop_temporary_table(altered_table, NULL, false);
1001710017
goto err_new_table_cleanup;
1001810018
}
1001910019

1002010020
// If SHARED lock and no particular algorithm was requested, use COPY.
10021-
if (inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK &&
10021+
if (ha_alter_info.inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK &&
1002210022
alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED &&
1002310023
alter_info->algorithm(thd) ==
1002410024
Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT &&
1002510025
thd->variables.alter_algorithm ==
1002610026
Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT)
1002710027
use_inplace= false;
1002810028

10029-
if (inplace_supported == HA_ALTER_INPLACE_NOT_SUPPORTED)
10029+
if (ha_alter_info.inplace_supported == HA_ALTER_INPLACE_NOT_SUPPORTED)
1003010030
use_inplace= false;
1003110031

1003210032
if (use_inplace)
@@ -10038,7 +10038,7 @@ do_continue:;
1003810038
*/
1003910039
Check_level_instant_set check_level_save(thd, CHECK_FIELD_WARN);
1004010040
int res= mysql_inplace_alter_table(thd, table_list, table, altered_table,
10041-
&ha_alter_info, inplace_supported,
10041+
&ha_alter_info,
1004210042
&target_mdl_request, &alter_ctx);
1004310043
my_free(const_cast<uchar*>(frm.str));
1004410044

storage/innobase/handler/handler0alter.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5003,6 +5003,19 @@ prepare_inplace_alter_table_dict(
50035003

50045004
user_table = ctx->new_table;
50055005

5006+
switch (ha_alter_info->inplace_supported) {
5007+
default: break;
5008+
case HA_ALTER_INPLACE_INSTANT:
5009+
case HA_ALTER_INPLACE_NOCOPY_LOCK:
5010+
case HA_ALTER_INPLACE_NOCOPY_NO_LOCK:
5011+
/* If we promised ALGORITHM=NOCOPY or ALGORITHM=INSTANT,
5012+
we must retain the original ROW_FORMAT of the table. */
5013+
flags = (user_table->flags & (DICT_TF_MASK_COMPACT
5014+
| DICT_TF_MASK_ATOMIC_BLOBS))
5015+
| (flags & ~(DICT_TF_MASK_COMPACT
5016+
| DICT_TF_MASK_ATOMIC_BLOBS));
5017+
}
5018+
50065019
trx_start_if_not_started_xa(ctx->prebuilt->trx, true);
50075020

50085021
if (ha_alter_info->handler_flags

0 commit comments

Comments
 (0)