Skip to content

Commit 350e46a

Browse files
committed
MDEV-18546 ASAN heap-use-after-free in innobase_get_computed_value / row_purge
the bug was already fixed in MDEV-17005, so now only test is added
1 parent b393e2c commit 350e46a

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed

mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,48 @@ set global debug_dbug= @saved_dbug;
233233
drop table t1;
234234
set debug_sync=reset;
235235
SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency;
236+
#
237+
# MDEV-18546 ASAN heap-use-after-free
238+
# in innobase_get_computed_value / row_purge
239+
#
240+
CREATE TABLE t1 (
241+
pk INT AUTO_INCREMENT,
242+
b BIT(15),
243+
v BIT(15) AS (b) VIRTUAL,
244+
PRIMARY KEY(pk),
245+
UNIQUE(v)
246+
) ENGINE=InnoDB;
247+
INSERT IGNORE INTO t1 (b) VALUES
248+
(NULL),(b'011'),(b'000110100'),
249+
(b'01101101010'),(b'01111001001011'),(NULL);
250+
SET GLOBAL innodb_debug_sync = "ib_clust_v_col_before_row_allocated "
251+
"SIGNAL before_row_allocated "
252+
"WAIT_FOR flush_unlock";
253+
SET GLOBAL innodb_debug_sync = "ib_open_after_dict_open "
254+
"SIGNAL purge_open "
255+
"WAIT_FOR select_open";
256+
set @saved_dbug= @@global.debug_dbug;
257+
set global debug_dbug= "+d,ib_purge_virtual_index_callback";
258+
connect purge_waiter,localhost,root;
259+
SET debug_sync= "now WAIT_FOR before_row_allocated";
260+
connection default;
261+
REPLACE INTO t1 (pk, b) SELECT pk, b FROM t1;
262+
connection purge_waiter;
263+
connection default;
264+
disconnect purge_waiter;
265+
FLUSH TABLES;
266+
SET GLOBAL innodb_debug_sync = reset;
267+
SET debug_sync= "now SIGNAL flush_unlock WAIT_FOR purge_open";
268+
SET GLOBAL innodb_debug_sync = reset;
269+
SET debug_sync= "ib_open_after_dict_open SIGNAL select_open";
270+
SELECT * FROM t1;
271+
pk b v
272+
1 NULL NULL
273+
2  
274+
3 4 4
275+
4 j j
276+
5 K K
277+
6 NULL NULL
278+
DROP TABLE t1;
279+
SET debug_sync= reset;
280+
set global debug_dbug= @saved_dbug;

mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,3 +323,67 @@ drop table t1;
323323
--source include/wait_until_count_sessions.inc
324324
set debug_sync=reset;
325325
SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency;
326+
327+
--echo #
328+
--echo # MDEV-18546 ASAN heap-use-after-free
329+
--echo # in innobase_get_computed_value / row_purge
330+
--echo #
331+
332+
CREATE TABLE t1 (
333+
pk INT AUTO_INCREMENT,
334+
b BIT(15),
335+
v BIT(15) AS (b) VIRTUAL,
336+
PRIMARY KEY(pk),
337+
UNIQUE(v)
338+
) ENGINE=InnoDB;
339+
INSERT IGNORE INTO t1 (b) VALUES
340+
(NULL),(b'011'),(b'000110100'),
341+
(b'01101101010'),(b'01111001001011'),(NULL);
342+
343+
SET GLOBAL innodb_debug_sync = "ib_clust_v_col_before_row_allocated "
344+
"SIGNAL before_row_allocated "
345+
"WAIT_FOR flush_unlock";
346+
SET GLOBAL innodb_debug_sync = "ib_open_after_dict_open "
347+
"SIGNAL purge_open "
348+
"WAIT_FOR select_open";
349+
350+
# In 10.2 trx_undo_roll_ptr_is_insert(t_roll_ptr) condition never pass in purge,
351+
# so this condition is forced to pass in row_vers_old_has_index_entry
352+
set @saved_dbug= @@global.debug_dbug;
353+
set global debug_dbug= "+d,ib_purge_virtual_index_callback";
354+
355+
# The purge starts from REPLACE command. To avoid possible race, separate
356+
# connection is used.
357+
--connect(purge_waiter,localhost,root)
358+
--send
359+
SET debug_sync= "now WAIT_FOR before_row_allocated";
360+
361+
--connection default
362+
REPLACE INTO t1 (pk, b) SELECT pk, b FROM t1;
363+
364+
--connection purge_waiter
365+
# Now we will definitely catch ib_clust_v_col_before_row_allocated
366+
--reap
367+
--connection default
368+
--disconnect purge_waiter
369+
370+
# purge hangs on the sync point. table is purged, ref_count is set to 0
371+
FLUSH TABLES;
372+
373+
# Avoid hang on repeating purge.
374+
# Reset Will be applied after first record is purged
375+
SET GLOBAL innodb_debug_sync = reset;
376+
377+
SET debug_sync= "now SIGNAL flush_unlock WAIT_FOR purge_open";
378+
379+
# Avoid hang on repeating purge
380+
SET GLOBAL innodb_debug_sync = reset;
381+
382+
# select unblocks purge thread
383+
SET debug_sync= "ib_open_after_dict_open SIGNAL select_open";
384+
SELECT * FROM t1;
385+
386+
# Cleanup
387+
DROP TABLE t1;
388+
SET debug_sync= reset;
389+
set global debug_dbug= @saved_dbug;

storage/innobase/row/row0vers.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ row_vers_build_clust_v_col(
467467
vcol_info->set_used();
468468
maria_table = vcol_info->table();
469469
}
470+
DEBUG_SYNC(current_thd, "ib_clust_v_col_before_row_allocated");
470471

471472
innobase_allocate_row_for_vcol(thd, index,
472473
&local_heap,

0 commit comments

Comments
 (0)