| 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: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.

Description: The test innodb_plugin.innodb-index has valgrind leak warnings. The test passes otherwise. 14 bytes in 1 blocks are indirectly lost in loss record 1 of 5 at 0x4A05809: malloc (vg_replace_malloc.c:149) by 0x5935079: ??? by 0x587755F: ??? by 0x58F16F6: ??? by 0x589EADA: ??? by 0x6DFA95: mysql_alter_table(THD*, char*, char*, st_ha_create_information*, TABLE_LIST*, Alter_info*, unsigned, st_order*, bool) (sql_table.cc:7326) by 0x5CAB64: mysql_execute_command(THD*) (sql_parse.cc:2968) by 0x5CB66E: mysql_parse(THD*, char*, unsigned, char const**) (sql_parse.cc:6051) by 0x5CC37E: dispatch_command(enum_server_command, THD*, char*, unsigned) (sql_parse.cc:1260) by 0x5CD351: do_command(THD*) (sql_parse.cc:888) by 0x5BC7D4: handle_one_connection (sql_connect.cc:1136) by 0x328F8062F6: start_thread (in /lib64/libpthread-2.5.so) by 0x328ECD1E3C: clone (in /lib64/libc-2.5.so) 2,062 (568 direct, 1,494 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 5 at 0x4A05809: malloc (vg_replace_malloc.c:149) by 0x58BC2D8: ??? by 0x58BAE61: ??? by 0x58BAFD5: ??? by 0x587781F: ??? by 0x58F16F6: ??? by 0x589EADA: ??? by 0x6DFA95: mysql_alter_table(THD*, char*, char*, st_ha_create_information*, TABLE_LIST*, Alter_info*, unsigned, st_order*, bool) (sql_table.cc:7326) by 0x5CAB64: mysql_execute_command(THD*) (sql_parse.cc:2968) by 0x5CB66E: mysql_parse(THD*, char*, unsigned, char const**) (sql_parse.cc:6051) by 0x5CC37E: dispatch_command(enum_server_command, THD*, char*, unsigned) (sql_parse.cc:1260) by 0x5CD351: do_command(THD*) (sql_parse.cc:888) by 0x5BC7D4: handle_one_connection (sql_connect.cc:1136) by 0x328F8062F6: start_thread (in /lib64/libpthread-2.5.so) by 0x328ECD1E3C: clone (in /lib64/libc-2.5.so) 1,480 bytes in 2 blocks are indirectly lost in loss record 5 of 5 at 0x4A05809: malloc (vg_replace_malloc.c:149) by 0x58BC2D8: ??? by 0x58BAE61: ??? by 0x5877421: ??? by 0x58F16F6: ??? by 0x589EADA: ??? by 0x6DFA95: mysql_alter_table(THD*, char*, char*, st_ha_create_information*, TABLE_LIST*, Alter_info*, unsigned, st_order*, bool) (sql_table.cc:7326) by 0x5CAB64: mysql_execute_command(THD*) (sql_parse.cc:2968) by 0x5CB66E: mysql_parse(THD*, char*, unsigned, char const**) (sql_parse.cc:6051) by 0x5CC37E: dispatch_command(enum_server_command, THD*, char*, unsigned) (sql_parse.cc:1260) by 0x5CD351: do_command(THD*) (sql_parse.cc:888) by 0x5BC7D4: handle_one_connection (sql_connect.cc:1136) by 0x328F8062F6: start_thread (in /lib64/libpthread-2.5.so) by 0x328ECD1E3C: clone (in /lib64/libc-2.5.so) LEAK SUMMARY: definitely lost: 568 bytes in 1 blocks. indirectly lost: 1,494 bytes in 3 blocks. possibly lost: 0 bytes in 0 blocks. still reachable: 0 bytes in 0 blocks. suppressed: 88 bytes in 2 blocks. How to repeat: The server uses centos 5.2, valgrind 3.2.1 and gcc 4.1.2 This is from unmodified mysql 5.1.52 ./configure --enable-thread-safe-client --with-plugins=partition,csv,blackhole,myisam,heap,innodb_plugin,innobase --with-fast-mutexes --with-extra-charsets=all --with-debug C_EXTRA_FLAGS="-fno-omit-frame-pointer -fno-strict-aliasing -DHAVE_purify -DUNIV_DEBUG_VALGRIND -Wall" make ./mysql-test-run.pl innodb_plugin.innodb-index