Bug #59143 | valgrind leak warning from innodb_plugin.innodb-index for mysql 5.1.52 | ||
---|---|---|---|
Submitted: | 24 Dec 2010 0:13 | Modified: | 21 Jan 2011 16:56 |
Reporter: | Mark Callaghan | Email Updates: | |
Status: | Duplicate | Impact on me: | |
Category: | MySQL Server: InnoDB Plugin storage engine | Severity: | S2 (Serious) |
Version: | 5.1.52, 5.5, 5.6 | OS: | Any |
Assigned to: | Assigned Account | CPU Architecture: | Any |
Tags: | innodb, Leak, plugin, valgrind |
[24 Dec 2010 0:13]
Mark Callaghan
[24 Dec 2010 0:39]
Mark Callaghan
full stacks from 5.1.52 with the facebook patch ==30290== 14 bytes in 1 blocks are still reachable in loss record 1 of 3 ==30290== at 0x4A05809: malloc (vg_replace_malloc.c:149) ==30290== by 0x8F2FC7: ut_malloc_low (ut0mem.c:106) ==30290== by 0x8F3384: ut_malloc (ut0mem.c:244) ==30290== by 0x940EAC: dict_mem_table_create (dict0mem.c:71) ==30290== by 0x8B50F0: row_merge_create_temporary_table (row0merge.c:2249) ==30290== by 0x859B48: ha_innobase::add_index(st_table*, st_key*, unsigned) (handler0alter.cc:741) ==30290== by 0x782B5F: mysql_alter_table(THD*, char*, char*, st_ha_create_information*, TABLE_LIST*, Alter_info*, unsigned, st_order*, bool) (sql_table.cc:7377) ==30290== by 0x613175: mysql_execute_command(THD*, unsigned long long*) (sql_parse.cc:3276) ==30290== by 0x61A46D: mysql_parse(THD*, char*, unsigned, char const**, unsigned long long*) (sql_parse.cc:6470) ==30290== by 0x61C769: dispatch_command(enum_server_command, THD*, char*, unsigned) (sql_parse.cc:1321) ==30290== by 0x61DFC4: do_command(THD*) (sql_parse.cc:935) ==30290== by 0x608BF4: handle_one_connection (sql_connect.cc:1184) ==30290== by 0x31EF2062F6: start_thread (in /lib64/libpthread-2.5.so) ==30290== by 0x31EE6D1E3C: clone (in /lib64/libc-2.5.so) ==30290== ==30290== ==30290== 2,552 bytes in 3 blocks are still reachable in loss record 3 of 3 ==30290== at 0x4A05809: malloc (vg_replace_malloc.c:149) ==30290== by 0x87B4E4: mem_area_alloc (mem0pool.c:380) ==30290== by 0x879EB5: mem_heap_create_block (mem0mem.c:333) ==30290== by 0x878D5C: mem_heap_create_func (mem0mem.ic:443) ==30290== by 0x940E40: dict_mem_table_create (dict0mem.c:64) ==30290== by 0x8B50F0: row_merge_create_temporary_table (row0merge.c:2249) ==30290== by 0x859B48: ha_innobase::add_index(st_table*, st_key*, unsigned) (handler0alter.cc:741) ==30290== by 0x782B5F: mysql_alter_table(THD*, char*, char*, st_ha_create_information*, TABLE_LIST*, Alter_info*, unsigned, st_order*, bool) (sql_table.cc:7377) ==30290== by 0x613175: mysql_execute_command(THD*, unsigned long long*) (sql_parse.cc:3276) ==30290== by 0x61A46D: mysql_parse(THD*, char*, unsigned, char const**, unsigned long long*) (sql_parse.cc:6470) ==30290== by 0x61C769: dispatch_command(enum_server_command, THD*, char*, unsigned) (sql_parse.cc:1321) ==30290== by 0x61DFC4: do_command(THD*) (sql_parse.cc:935) ==30290== by 0x608BF4: handle_one_connection (sql_connect.cc:1184) ==30290== by 0x31EF2062F6: start_thread (in /lib64/libpthread-2.5.so) ==30290== by 0x31EE6D1E3C: clone (in /lib64/libc-2.5.so)
[24 Dec 2010 1:11]
Mark Callaghan
This is a reproduction case: -- source include/have_innodb_plugin.inc create table t1(a int not null, b int, c char(10) not null, d varchar(20)) engine = innodb; insert into t1 values (5,5,'oo','oo'),(4,4,'tr','tr'),(3,4,'ad','ad'),(2,3,'ak','ak'); commit; # Check how existing tables interfere with temporary tables. CREATE TABLE `t1#1`(a INT PRIMARY KEY) ENGINE=InnoDB; --error 156 alter table t1 add unique index (c), add index (d); ------ and I assume error handling in here is incomplete row_merge_create_temporary_table( /*=============================*/ const char* table_name, /*!< in: new table name */ const merge_index_def_t*index_def, /*!< in: the index definition of the primary key */ const dict_table_t* table, /*!< in: old table definition */ trx_t* trx) /*!< in/out: transaction (sets error_state) */ { ulint i; dict_table_t* new_table = NULL; ulint n_cols = dict_table_get_n_user_cols(table); ulint error; mem_heap_t* heap = mem_heap_create(1000); ut_ad(table_name); ut_ad(index_def); ut_ad(table); ut_ad(mutex_own(&dict_sys->mutex)); new_table = dict_mem_table_create(table_name, 0, n_cols, table->flags); for (i = 0; i < n_cols; i++) { const dict_col_t* col; const char* col_name; col = dict_table_get_nth_col(table, i); col_name = dict_table_get_col_name(table, i); dict_mem_table_add_col(new_table, heap, col_name, col->mtype, row_merge_col_prtype(col, col_name, index_def), col->len); } error = row_create_table_for_mysql(new_table, trx); mem_heap_free(heap); if (error != DB_SUCCESS) { trx->error_state = error; new_table = NULL; } return(new_table); }
[24 Dec 2010 1:12]
Mark Callaghan
Is this missing a call to dict_mem_table_free?
[24 Dec 2010 7:14]
MySQL Verification Team
mysql-trunk has same problem.
Attachment: bug59143_5.6.1_valgrind_memory_leaks.txt (text/plain), 8.03 KiB.
[24 Dec 2010 7:32]
MySQL Verification Team
verified on todays mysql-5.5-innodb tree [sbester@levovo mysql-5.5-innodb]$ bzr revno 3264
[21 Jan 2011 12:16]
Vasil Dimov
This is a duplicate of Bug#56947 InnoDB leaks memory when failing to create a table and has already been fixed in 5.1 in these two changesets: ------------------------------------------------------------ revno: 3452.13.3 revision-id: marko.makela@oracle.com-20101011081800-sby6kmb8n1mnryfq parent: marko.makela@oracle.com-20101011080147-72nory5su5bo9j9k committer: Marko M?kel? <marko.makela@oracle.com> timestamp: Mon 2010-10-11 11:18:00 +0300 message: Bug #56947 InnoDB leaks memory when failing to create a table row_create_table_for_mysql(): When the table creation fails, free the dict_table_t object. ------------------------------------------------------------ revno: 3452.13.2 revision-id: marko.makela@oracle.com-20101011080147-72nory5su5bo9j9k parent: sunanda.menon@sun.com-20101007132514-yrhckyu0eltsytrt committer: Marko M?kel? <marko.makela@oracle.com> timestamp: Mon 2010-10-11 11:01:47 +0300 message: Bug #56947 InnoDB leaks memory when failing to create a table No mysql-test case. Tested by creating a table, removing a *.frm file and attempting to create the table again. Code coverage tested by instrumentation. Tested with Valgrind. ------------------------------------------------------------
[21 Jan 2011 13:42]
Mark Callaghan
Does 56947 need to be marked private?
[21 Jan 2011 14:13]
Vasil Dimov
Not anymore
[21 Jan 2011 16:45]
Mark Callaghan
I found those patches from the 5.1 launchpad branch. They are for storage/innobase not storage/innodb_plugin. From reading the bug text this bug was only in the plugin. Why was the built-in InnoDB changed?
[21 Jan 2011 16:52]
Vasil Dimov
Mark, which patches? The bug exists/existed only in 5.1/storage/innodb_plugin. Notice that in 5.5 there is just one InnoDB and it lives under 5.5/storage/innobase which is based on 5.1/storage/innodb_plugin so it also has this bug. Maybe you were looking at some 5.5 patches?
[21 Jan 2011 16:56]
Mark Callaghan
I don't understand why this wasn't fixed by changing row_merge_create_temporary_table. That code in the 5.1 launchpad branch still doesn't call dict_mem_table_free on error. There were two commits listed. One changes built-in code, the other changes plug-in code. I will test the plug-in change. new_table = dict_mem_table_create(table_name, 0, n_cols, table->flags); for (i = 0; i < n_cols; i++) { const dict_col_t* col; const char* col_name; col = dict_table_get_nth_col(table, i); col_name = dict_table_get_col_name(table, i); dict_mem_table_add_col(new_table, heap, col_name, col->mtype, row_merge_col_prtype(col, col_name, index_def), col->len); } error = row_create_table_for_mysql(new_table, trx); mem_heap_free(heap); if (error != DB_SUCCESS) { trx->error_state = error; new_table = NULL; } return(new_table);
[21 Jan 2011 16:59]
Vasil Dimov
patch1
Attachment: 5.1-marko.makela@oracle.com-20101011080147-72nory5su5bo9j9k.diff (text/x-patch), 550 bytes.
[21 Jan 2011 17:00]
Vasil Dimov
patch2
Attachment: 5.1-marko.makela@oracle.com-20101011081800-sby6kmb8n1mnryfq.diff (text/x-patch), 4.00 KiB.
[21 Jan 2011 17:03]
Vasil Dimov
It was not fixed by changing row_merge_create_temporary_table() because row_create_table_for_mysql() is supposed to free new_table. But it did not do it always. If we have added the free to the caller then sometimes we would get double free bug.