From ac9c38fde0d0c7f924fbca227acefc1e0fb6823b Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 12 Oct 2026 14:19:29 +0300 Subject: [PATCH] MDEV-30441 ASAN heap-use-after-free in Field_blob::pack/pack_row When InnoDB computes an indexed virtual column (e.g. the long unique hash), TABLE::update_virtual_field() walked its expression with update_vcol_processor() and recomputed every vcol it referenced, including STORED ones. innobase_allocate_row_for_vcol() saves and restores Field_blob::value only for non-stored blob vcols, so recomputing a STORED blob vcol in Field_blob::store_field() did val_str(&value) and freed the buffer that record[0] still pointed to. The row-format binlog then packed record[0] from freed memory. The buffer is allocated only when the value is converted, so the bug needs a character set conversion (e.g. BLOB to utf8mb3 TEXT). The fix skips STORED vcols in update_vcol_processor(). Their values are already in the record: InnoDB copies them as base columns of the virtual column, and the SQL layer computes them before writing. The test cases detect the bug only under ASAN or Valgrind. --- mysql-test/main/long_unique_bugs.result | 14 ++++++++++++++ mysql-test/main/long_unique_bugs.test | 16 ++++++++++++++++ sql/item.cc | 6 +++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/long_unique_bugs.result b/mysql-test/main/long_unique_bugs.result index b195e1f7995..3c2bee51fce 100644 --- a/mysql-test/main/long_unique_bugs.result +++ b/mysql-test/main/long_unique_bugs.result @@ -850,4 +850,18 @@ create table t(c int primary key, c2 blob unique) engine=innodb; insert into t values (0, ''); replace into t values (0, '123'); drop table t; +# +# MDEV-30441 ASAN heap-use-after-free in Field_blob::pack/pack_row +# +create table t1 (a blob, va mediumtext as (a) stored, b varchar(3845), +unique key (b, va(64))) +engine=innodb default charset=utf8mb3; +insert into t1 (a, b) values ('111', '222'); +delete from t1 order by b limit 1; +drop table t1; +create table t (a blob, b text as (a) stored, unique (b)) +engine=innodb character set utf8mb3 +as select 'x' as a; +delete from t; +drop table t; # End of 10.11 tests diff --git a/mysql-test/main/long_unique_bugs.test b/mysql-test/main/long_unique_bugs.test index fc171e67411..65fd56557c1 100644 --- a/mysql-test/main/long_unique_bugs.test +++ b/mysql-test/main/long_unique_bugs.test @@ -776,4 +776,20 @@ insert into t values (0, ''); replace into t values (0, '123'); drop table t; +--echo # +--echo # MDEV-30441 ASAN heap-use-after-free in Field_blob::pack/pack_row +--echo # +create table t1 (a blob, va mediumtext as (a) stored, b varchar(3845), + unique key (b, va(64))) +engine=innodb default charset=utf8mb3; +insert into t1 (a, b) values ('111', '222'); +delete from t1 order by b limit 1; +drop table t1; + +create table t (a blob, b text as (a) stored, unique (b)) +engine=innodb character set utf8mb3 +as select 'x' as a; +delete from t; +drop table t; + --echo # End of 10.11 tests diff --git a/sql/item.cc b/sql/item.cc index 2a6c98f7926..42c15193d35 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -980,7 +980,11 @@ bool Item_field::check_field_expression_processor(void *arg) bool Item_field::update_vcol_processor(void *arg) { MY_BITMAP *map= (MY_BITMAP *) arg; - if (field->vcol_info && + /* + Stored vcols are not recomputed: the caller must have their values + in the record (the engine fills them as base columns). + */ + if (!field->stored_in_db() && !bitmap_fast_test_and_set(map, field->field_index)) { field->vcol_info->expr->walk(&Item::update_vcol_processor, 0, arg);