| Bug #96472 | Memory leak after 'innodb.alter_crash' | ||
|---|---|---|---|
| Submitted: | 8 Aug 2019 13:05 | Modified: | 8 Aug 2019 16:24 |
| Reporter: | Yura Sorokin (OCA) | Email Updates: | |
| Status: | Verified | Impact on me: | |
| Category: | MySQL Server: InnoDB storage engine | Severity: | S7 (Test Cases) |
| Version: | 5.7.27 | OS: | Any |
| Assigned to: | CPU Architecture: | Any | |
[8 Aug 2019 16:24]
MySQL Verification Team
Thank you for the bug report.
[12 Aug 2019 13:19]
Erlend Dahl
Posted by developer: Repeatable with clang 7 on recent 5.7. Not repeatable on 8.0.
[14 Jan 2020 13:16]
Marcelo Altmann
If online alter fails to allocate undo log, heap memory allocated to the index object won't be freed. This can be simulated by using debug point 'ib_create_table_fail_too_many_trx' prior to an alter table. To fix it, prior to set index pointer to null at row_merge_create_index, we should call dict_mem_index_free to correctly free memory objects allocated by the index.
[14 Jan 2020 13:17]
Marcelo Altmann
Suggested fix:
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index 5d0919a..c626c50 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -4209,6 +4209,7 @@ row_merge_create_index(
this index, to ensure read consistency. */
ut_ad(index->trx_id == trx->id);
} else {
+ dict_mem_index_free(index);
index = NULL;
}
[17 Jan 2020 11:40]
Marcelo Altmann
(*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.
[8 Apr 2020 13:49]
Marcelo Altmann
an enhanced version of the fix to avoid double free:
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index 5d0919a322b..29f2ea993f1 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -4209,6 +4209,11 @@ row_merge_create_index(
this index, to ensure read consistency. */
ut_ad(index->trx_id == trx->id);
} else {
+ /* In case we were unable to assign an undo record for this index
+ we won't free index memory object */
+ if (err == DB_TOO_MANY_CONCURRENT_TRXS) {
+ dict_mem_index_free(index);
+ }
index = NULL;
}
(*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.

Description: The following Address Sanitizer log is generated after running 'innodb.alter_crash' MTR test case Indirect leak of 2208 byte(s) in 1 object(s) allocated from: #0 0x7f26f4429f00 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xedf00) #1 0x558b89812179 in ut_allocator<unsigned char>::allocate(unsigned long, unsigned char const*, char const*, bool, bool) /home/yura/addon/local/percona-server/storage/innobase/include/ut0new.h:359 #2 0x558b89812179 in mem_heap_create_block_func(mem_block_info_t*, unsigned long, char const*, unsigned long, unsigned long) /home/yura/addon/local/percona-server/storage/innobase/mem/mem0mem.cc:302 #3 0x558b89813519 in mem_heap_add_block(mem_block_info_t*, unsigned long) /home/yura/addon/local/percona-server/storage/innobase/mem/mem0mem.cc:407 #4 0x558b89813a18 in mem_heap_alloc /home/yura/addon/local/percona-server/storage/innobase/include/mem0mem.ic:204 #5 0x558b89813a18 in mem_heap_dup(mem_block_info_t*, void const*, unsigned long) /home/yura/addon/local/percona-server/storage/innobase/mem/mem0mem.cc:59 #6 0x558b89813bb0 in mem_heap_strdup(mem_block_info_t*, char const*) /home/yura/addon/local/percona-server/storage/innobase/mem/mem0mem.cc:46 #7 0x558b89e12640 in dict_mem_fill_index_struct /home/yura/addon/local/percona-server/storage/innobase/include/dict0mem.ic:51 #8 0x558b89e12640 in dict_mem_index_create(char const*, char const*, unsigned long, unsigned long, unsigned long) /home/yura/addon/local/percona-server/storage/innobase/dict/dict0mem.cc:692 #9 0x558b8996439f in row_merge_create_index(trx_t*, dict_table_t*, index_def_t const*, dict_add_v_col_t const*) /home/yura/addon/local/percona-server/storage/innobase/row/row0merge.cc:4282 #10 0x558b896ea4cc in prepare_inplace_alter_table_dict /home/yura/addon/local/percona-server/storage/innobase/handler/handler0alter.cc:4963 #11 0x558b896f91ec in ha_innobase::prepare_inplace_alter_table(TABLE*, Alter_inplace_info*) /home/yura/addon/local/percona-server/storage/innobase/handler/handler0alter.cc:6382 #12 0x558b876b81dd in handler::ha_prepare_inplace_alter_table(TABLE*, Alter_inplace_info*) /home/yura/addon/local/percona-server/sql/handler.cc:5140 #13 0x558b88b5c58c in mysql_inplace_alter_table /home/yura/addon/local/percona-server/sql/sql_table.cc:7838 #14 0x558b88b75d0b in mysql_alter_table(THD*, char const*, char const*, st_ha_create_information*, TABLE_LIST*, Alter_info*) /home/yura/addon/local/percona-server/sql/sql_table.cc:10317 #15 0x558b890b8809 in Sql_cmd_alter_table::execute(THD*) /home/yura/addon/local/percona-server/sql/sql_alter.cc:348 #16 0x558b889ca5d3 in mysql_execute_command(THD*, bool) /home/yura/addon/local/percona-server/sql/sql_parse.cc:5136 #17 0x558b889d2535 in mysql_parse(THD*, Parser_state*, bool) /home/yura/addon/local/percona-server/sql/sql_parse.cc:5905 #18 0x558b889d77d2 in dispatch_command(THD*, COM_DATA const*, enum_server_command) /home/yura/addon/local/percona-server/sql/sql_parse.cc:1532 #19 0x558b889ddbd0 in do_command(THD*) /home/yura/addon/local/percona-server/sql/sql_parse.cc:1053 #20 0x558b88cdda44 in handle_connection /home/yura/addon/local/percona-server/sql/conn_handler/connection_handler_per_thread.cc:318 #21 0x558b89471607 in pfs_spawn_thread /home/yura/addon/local/percona-server/storage/perfschema/pfs.cc:2190 #22 0x7f26f41246da in start_thread /build/glibc-OTsEL5/glibc-2.27/nptl/pthread_create.c:463 How to repeat: build MySQL Server with gcc-8 and with Address Sanitizer enabled (-DWITH_ASAN=ON) CC=gcc-8 CXX=g++-8 cmake -DWITH_ASAN=ON ... run ./mysql-test/mtr --big-test --debug-server --sanitize innodb.alter_crash