From 9a897335eb4387980aed7698b832a893dbaa3d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 26 Jul 2022 16:45:10 +0300 Subject: [PATCH] MDEV-26420 Buffer overflow on instant ADD/DROP of generated column prepare_inplace_add_virtual(): Over-estimate the size of the arrays by not subtracting table->s->virtual_fields (which may refer to stored, not virtual generated columns). InnoDB only distinguishes virtual columns. --- mysql-test/suite/innodb/r/instant_alter_bugs.result | 7 +++++++ mysql-test/suite/innodb/t/instant_alter_bugs.test | 9 +++++++++ storage/innobase/handler/handler0alter.cc | 13 ++++++------- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/innodb/r/instant_alter_bugs.result b/mysql-test/suite/innodb/r/instant_alter_bugs.result index 0c82ee8f070..2d667737a99 100644 --- a/mysql-test/suite/innodb/r/instant_alter_bugs.result +++ b/mysql-test/suite/innodb/r/instant_alter_bugs.result @@ -458,3 +458,10 @@ f4 INT NOT NULL, f5 INT NOT NULL), CHANGE COLUMN f1 f1 CHAR(10) DEFAULT NULL; DROP TABLE t1; SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency; +# +# MDEV-26420 Buffer overflow on instant ADD/DROP of generated column +# +CREATE TABLE t1 (i int AS (0) STORED, j INT) ENGINE=InnoDB; +ALTER TABLE t1 ADD COLUMN i INT GENERATED ALWAYS AS (1), DROP COLUMN i; +DROP TABLE t1; +# End of 10.4 tests diff --git a/mysql-test/suite/innodb/t/instant_alter_bugs.test b/mysql-test/suite/innodb/t/instant_alter_bugs.test index b22d4bbbae1..74e5949818b 100644 --- a/mysql-test/suite/innodb/t/instant_alter_bugs.test +++ b/mysql-test/suite/innodb/t/instant_alter_bugs.test @@ -476,3 +476,12 @@ ALTER TABLE t1 ADD COLUMN(f2 INT NOT NULL, f3 INT NOT NULL, CHANGE COLUMN f1 f1 CHAR(10) DEFAULT NULL; DROP TABLE t1; SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency; + +--echo # +--echo # MDEV-26420 Buffer overflow on instant ADD/DROP of generated column +--echo # +CREATE TABLE t1 (i int AS (0) STORED, j INT) ENGINE=InnoDB; +ALTER TABLE t1 ADD COLUMN i INT GENERATED ALWAYS AS (1), DROP COLUMN i; +DROP TABLE t1; + +--echo # End of 10.4 tests diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 8c51f80f1d3..82d945e6414 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -5016,20 +5016,18 @@ prepare_inplace_add_virtual( { ha_innobase_inplace_ctx* ctx; ulint i = 0; - ulint j = 0; ctx = static_cast (ha_alter_info->handler_ctx); - ctx->num_to_add_vcol = altered_table->s->virtual_fields - + ctx->num_to_drop_vcol - table->s->virtual_fields; + ulint j = altered_table->s->virtual_fields + ctx->num_to_drop_vcol; ctx->add_vcol = static_cast( - mem_heap_zalloc(ctx->heap, ctx->num_to_add_vcol - * sizeof *ctx->add_vcol)); + mem_heap_zalloc(ctx->heap, j * sizeof *ctx->add_vcol)); ctx->add_vcol_name = static_cast( - mem_heap_alloc(ctx->heap, ctx->num_to_add_vcol - * sizeof *ctx->add_vcol_name)); + mem_heap_alloc(ctx->heap, j * sizeof *ctx->add_vcol_name)); + + j = 0; for (const Create_field& new_field : ha_alter_info->alter_info->create_list) { @@ -5110,6 +5108,7 @@ prepare_inplace_add_virtual( j++; } + ctx->num_to_add_vcol = j; return(false); }