[MDEV-29600] Memory leak in row_log_table_apply_update(), in UPDATE involving BLOB, during online table rebuild Created: 2022-09-21  Updated: 2024-02-07  Resolved: 2022-09-22

Status: Closed
Project: MariaDB Server
Component/s: Storage Engine - InnoDB
Affects Version/s: 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 10.10
Fix Version/s: 10.3.37, 10.4.27, 10.5.18, 10.6.11, 10.7.7, 10.8.6, 10.9.4, 10.10.2

Type: Bug Priority: Major
Reporter: Elena Stepanova Assignee: Marko Mäkelä
Resolution: Fixed Votes: 1
Labels: ASAN, leak, upstream

Issue Links:
Relates
relates to MDEV-29977 Memory leak in rec_copy_prefix_to_buf... Closed

 Description   

Note: The test case is non-deterministic, run with --repeat=N. It usually fails for me within ~5 attempts. The test case is rr-able.
The restart in the test case is not a part of the test itself, it is mainly there to capture LeakSanitizer errors right away; otherwise the test would run all N attempts before reporting the failure which is only seen on shutdown.

--source include/have_innodb.inc
 
CREATE TABLE t (pk INT PRIMARY KEY, f TEXT) ENGINE=InnoDB;
INSERT INTO t(pk) VALUES (1);
 
--connect (con1,localhost,root,,test)
--send
  ALTER TABLE t FORCE;
 
--connection default
DROP TABLE IF EXISTS non_existing;
UPDATE t SET f = REPEAT('a',10000);
 
--source include/restart_mysqld.inc
 
--connection default
DROP TABLE t;

10.3 b6bf7cd1

==3197705==ERROR: LeakSanitizer: detected memory leaks
 
Direct leak of 10 byte(s) in 1 object(s) allocated from:
    #0 0x7f66010bee8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x56473333dc2c in rec_copy_prefix_to_buf(unsigned char const*, dict_index_t const*, unsigned long, unsigned char**, unsigned long*) /data/src/10.3/storage/innobase/rem/rem0rec.cc:2002
    #2 0x564733650dbe in btr_pcur_store_position(btr_pcur_t*, mtr_t*) /data/src/10.3/storage/innobase/btr/btr0pcur.cc:200
    #3 0x564733645c1c in btr_blob_log_check_t::check() /data/src/10.3/storage/innobase/btr/btr0cur.cc:7189
    #4 0x56473363e951 in btr_store_big_rec_extern_fields(btr_pcur_t*, unsigned short*, big_rec_t const*, mtr_t*, blob_op) /data/src/10.3/storage/innobase/btr/btr0cur.cc:7390
    #5 0x564733417aaf in row_log_table_apply_update /data/src/10.3/storage/innobase/row/row0log.cc:2327
    #6 0x56473341a4bc in row_log_table_apply_op /data/src/10.3/storage/innobase/row/row0log.cc:2669
    #7 0x56473341e8fa in row_log_table_apply_ops /data/src/10.3/storage/innobase/row/row0log.cc:3039
    #8 0x56473341f76e in row_log_table_apply(que_thr_t*, dict_table_t*, TABLE*, ut_stage_alter_t*, dict_table_t*) /data/src/10.3/storage/innobase/row/row0log.cc:3148
    #9 0x56473315f716 in ha_innobase::inplace_alter_table(TABLE*, Alter_inplace_info*) /data/src/10.3/storage/innobase/handler/handler0alter.cc:7223
    #10 0x56473264c815 in handler::ha_inplace_alter_table(TABLE*, Alter_inplace_info*) (/mnt8t/bld/10.3-asan-nightly/bin/mysqld+0x12a8815)
    #11 0x56473262fcf2 in mysql_inplace_alter_table /data/src/10.3/sql/sql_table.cc:7773
    #12 0x564732640afd in mysql_alter_table(THD*, st_mysql_const_lex_string const*, st_mysql_const_lex_string const*, HA_CREATE_INFO*, TABLE_LIST*, Alter_info*, unsigned int, st_order*, bool) /data/src/10.3/sql/sql_table.cc:10111
    #13 0x5647327a887b in Sql_cmd_alter_table::execute(THD*) /data/src/10.3/sql/sql_alter.cc:512
    #14 0x5647323f6745 in mysql_execute_command(THD*) /data/src/10.3/sql/sql_parse.cc:6076
    #15 0x5647324025fb in mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool) /data/src/10.3/sql/sql_parse.cc:7871
    #16 0x5647323d9ba1 in dispatch_command(enum_server_command, THD*, char*, unsigned int, bool, bool) /data/src/10.3/sql/sql_parse.cc:1852
    #17 0x5647323d677d in do_command(THD*) /data/src/10.3/sql/sql_parse.cc:1398
    #18 0x564732798159 in do_handle_one_connection(CONNECT*) /data/src/10.3/sql/sql_connect.cc:1403
    #19 0x564732797a55 in handle_one_connection /data/src/10.3/sql/sql_connect.cc:1308
    #20 0x564733d42ae6 in pfs_spawn_thread /data/src/10.3/storage/perfschema/pfs.cc:1869
    #21 0x7f660081cea6 in start_thread nptl/pthread_create.c:477
 
SUMMARY: AddressSanitizer: 10 byte(s) leaked in 1 allocation(s).

Reproducible on all of 10.3-10.10, also on at least 2 last releases of 10.3.



 Comments   
Comment by Marko Mäkelä [ 2022-09-22 ]

Indeed, it looks like even after MDEV-15250, the memory will be leaked in 10.6 and later:

10.6 ca51c9fd596268900e466e26e5d3c2a3c6db9cb3

Direct leak of 10 byte(s) in 1 object(s) allocated from:
    #0 0x7f3b64ab89cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x55fb7d0a4026 in rec_copy_prefix_to_buf(unsigned char const*, dict_index_t const*, unsigned long, unsigned char**, unsigned long*) /mariadb/10.6/storage/innobase/rem/rem0rec.cc:2118
    #2 0x55fb7ce0c6db in btr_pcur_store_position(btr_pcur_t*, mtr_t*) /mariadb/10.6/storage/innobase/btr/btr0pcur.cc:215
    #3 0x55fb7ccc70f5 in btr_blob_log_check_t::check() /mariadb/10.6/storage/innobase/btr/btr0cur.cc:6823
    #4 0x55fb7cca7e25 in btr_store_big_rec_extern_fields(btr_pcur_t*, unsigned short*, big_rec_t const*, mtr_t*, blob_op) /mariadb/10.6/storage/innobase/btr/btr0cur.cc:7011
    #5 0x55fb7d13441c in row_log_table_apply_update /mariadb/10.6/storage/innobase/row/row0log.cc:2053
    #6 0x55fb7d135fb8 in row_log_table_apply_op /mariadb/10.6/storage/innobase/row/row0log.cc:2388
    #7 0x55fb7d139519 in row_log_table_apply_ops /mariadb/10.6/storage/innobase/row/row0log.cc:2758
    #8 0x55fb7d13a1f6 in row_log_table_apply(que_thr_t*, dict_table_t*, TABLE*, ut_stage_alter_t*, dict_table_t*) /mariadb/10.6/storage/innobase/row/row0log.cc:2866
    #9 0x55fb7cecbd60 in alter_rebuild_apply_log /mariadb/10.6/storage/innobase/handler/handler0alter.cc:10912
    #10 0x55fb7cef068b in ha_innobase::commit_inplace_alter_table(TABLE*, Alter_inplace_info*, bool) /mariadb/10.6/storage/innobase/handler/handler0alter.cc:11133

Comment by Marko Mäkelä [ 2022-09-22 ]

For every replicated UPDATE that involves off-page storage, btr_pcur_t::old_rec_buf will be leaded by row_log_table_apply_update().

I also checked how row_log_table_apply_insert_low() is managing off-page records. It invokes row_ins_clust_index_entry_low(), which will free the pcur.old_rec_buf in its local variable before returning. So, there was no leak in the INSERT case.

As far as I can tell, this memory leak was inherited from MySQL 5.7.5 to MariaDB Server 10.2.2.

Generated at Thu Feb 08 10:09:51 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.