Bug #45962 memory leak after 'sort aborted' errors
Submitted: 6 Jul 2009 8:39 Modified: 16 Sep 2009 0:54
Reporter: Shane Bester (Platinum Quality Contributor) Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: DML Severity:S2 (Serious)
Version:5.0.84, 5.1.37, 6.0.12 OS:Any
Assigned to: Georgi Kodinov
Tags: Leak, memory leak, sort aborted
Triage: Triaged: D2 (Serious)

[6 Jul 2009 8:39] Shane Bester
Description:
This testcase is identical to bug #35477 however during the testcase,
KILL <id> causes an incomplete free of allocated memory.

74,218 bytes in 5 blocks are definitely lost in loss record 3 of 3
at: malloc (vg_replace_malloc.c:149)
by: my_malloc (my_malloc.c:34)
by: init_dynamic_array2 (array.c:66)
by: Unique::Unique(int (*) (uniques.cc:63)
by: QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() (opt_range.cc:8053)
by: QUICK_INDEX_MERGE_SELECT::reset() (opt_range.cc:1220)
by: find_all_keys  (filesort.cc:543)
by: filesort (filesort.cc:243)
by: create_sort_index (sql_select.cc:13489)
by: JOIN::exec() (sql_select.cc:2142)
by: mysql_select (sql_select.cc:2386)
by: handle_select (sql_select.cc:268)

How to repeat:
Run mysqld under valgrind, similar to this:

valgrind --tool=memcheck --leak-check=full --db-attach=no -v --show-reachable=yes  ./bin/mysqld --skip-grant-tables --skip-name-resolve --basedir=. --datadir=./data 

Execute the testcase:

delimiter ;
drop table if exists `t1`;
create table `t1` (`a` varchar(255),`b` varchar(255),`c`
varchar(255),key(`a`),key(`b`),key(`c`)) engine=myisam;
insert into `t1`values ('1','2','3'),('4','5','6'),('7','8','9');
set @a=1,@b=1,@c=1;
insert into `t1` select @a:=@a+1,@b:=@b+2,@c:=@c+3 from `t1` a,`t1`
b,`t1` c;
insert into `t1` select @a:=@a+1,@b:=@b+2,@c:=@c+3 from `t1` a,`t1`
b;

drop procedure if exists `p1`;
delimiter //
create procedure `p1`(`numtimes` int)
begin

        declare `i` int default '0';
        repeat
                select * from `t1` where `a` like '5%' or 
                `b` like '5%' order by `c` limit 1 into @a,@b,@c;
                if(`i` % 100 =0) then select `i` as repetition; end if;
                set `i`=`i`+1;
        until `i`>`numtimes` end repeat;

end//

delimiter ;

set session sort_buffer_size=1024;

call `p1`(50000);

#now in another connection run the sql "kill <id>" to kill the query.
Notice valgrind errors after shutting down server.
[6 Jul 2009 8:40] Shane Bester
in the error log, you should see sort aborted error message:

090619 11:11:53 [ERROR] ./bin/mysqld: Sort aborted
090619 11:11:57 [Note] ./bin/mysqld: Normal shutdown
[6 Jul 2009 9:08] Sveta Smirnova
Thank you for the report.

Verified as described:

==5638== 2,048 bytes in 1 blocks are still reachable in loss record 3 of 4
==5638==    at 0x4A05809: malloc (vg_replace_malloc.c:149)
==5638==    by 0x4A05883: realloc (vg_replace_malloc.c:306)
==5638==    by 0x3429E06D19: pthread_create@@GLIBC_2.2.5 (in /lib64/libpthread-2.5.so)
==5638==    by 0x88635D: my_thread_global_i= 1,008 bytes in 1 blocks are definitely lost in loss record 2 of 4
==5638==    at 0x4A05809: malloc (vg_replace_malloc.c:149)
==5638==    by 0x86E291: my_malloc (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x646669: Unique::get(st_table*) (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x687EB4: QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x69BC9E: filesort(THD*, st_table*, st_sort_field*, unsigned, SQL_SELECT*, unsigned long, bool, unsigned long*) (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x622C4B: _ZL17create_sort_indexP3THDP4JOINP8st_ordermmb (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x62B0A2: JOIN::exec() (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x62C751: mysql_select(THD*, Item***, TABLE_LIST*, unsigned, List<Item>&, Item*, unsigned, st_order*, st_order*, It= 1,008 bytes in 1 blocks are definitely lost in loss record 2 of 4
==5638==    at 0x4A05809: malloc (vg_replace_malloc.c:149)
==5638==    by 0x86E291: my_malloc (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x646669: Unique::get(st_table*) (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x687EB4: QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x69BC9E: filesort(THD*, st_table*, st_sort_field*, unsigned, SQL_SELECT*, unsigned long, bool, unsigned long*) (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x622C4B: _ZL17create_sort_indexP3THDP4JOINP8st_ordermmb (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x62B0A2: JOIN::exec() (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x62C751: mysql_select(THD*, Item***, TABLE_LIST*, unsigned, List<Item>&, Item*, unsigned, st_order*, st_order*, It= 1,008 bytes in 1 blocks are definitely lost in loss record 2 of 4
==5638==    at 0x4A05809: malloc (vg_replace_malloc.c:149)
==5638==    by 0x86E291: my_malloc (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x646669: Unique::get(st_table*) (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x687EB4: QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x69BC9E: filesort(THD*, st_table*, st_sort_field*, unsigned, SQL_SELECT*, unsigned long, bool, unsigned long*) (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x622C4B: _ZL17create_sort_indexP3THDP4JOINP8st_ordermmb (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x62B0A2: JOIN::exec() (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x62C751: mysql_select(THD*, Item***, TABLE_LIST*, unsigned, List<Item>&, Item*, unsigned, st_order*, st_order*, It= 1,008 bytes in 1 blocks are definitely lost in loss record 2 of 4
==5638==    at 0x4A05809: malloc (vg_replace_malloc.c:149)
==5638==    by 0x86E291: my_malloc (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x646669: Unique::get(st_table*) (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x687EB4: QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x69BC9E: filesort(THD*, st_table*, st_sort_field*, unsigned, SQL_SELECT*, unsigned long, bool, unsigned long*) (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x622C4B: _ZL17create_sort_indexP3THDP4JOINP8st_ordermmb (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x62B0A2: JOIN::exec() (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x62C751: mysql_select(THD*, Item***, TABLE_LIST*, unsigned, List<Item>&, Item*, unsigned, st_order*, st_order*, It= 1,008 bytes in 1 blocks are definitely lost in loss record 2 of 4
==5638==    at 0x4A05809: malloc (vg_replace_malloc.c:149)
==5638==    by 0x86E291: my_malloc (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x646669: Unique::get(st_table*) (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x687EB4: QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x69BC9E: filesort(THD*, st_table*, st_sort_field*, unsigned, SQL_SELECT*, unsigned long, bool, unsigned long*) (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x622C4B: _ZL17create_sort_indexP3THDP4JOINP8st_ordermmb (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x62B0A2: JOIN::exec() (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x62C751: mysql_select(THD*, Item***, TABLE_LIST*, unsigned, List<Item>&, Item*, unsigned, st_order*, st_order*, Item*, st_order*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*) (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x62D1D3: handle_select(THD*, st_lex*, select_result*, unsigned long) (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x5BCD29: _ZL21execute_sqlcom_selectP3THDP10TABLE_LIST (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x5C1CC2: mysql_execute_command(THD*) (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x70A64B: sp_instr_stmt::exec_core(THD*, unsigned*) (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638== 
==5638== 
==5638== 2,048 bytes in 1 blocks are still reachable in loss record 3 of 4
==5638==    at 0x4A05809: malloc (vg_replace_malloc.c:149)
==5638==    by 0x4A05883: realloc (vg_replace_malloc.c:306)
==5638==    by 0x3429E06D19: pthread_create@@GLIBC_2.2.5 (in /lib64/libpthread-2.5.so)
==5638==    by 0x88635D: my_thread_global_init (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x866573: my_init (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
==5638==    by 0x5B4023: main (in /users/ssmirnova/blade12/build/mysql-5.1/libexec/mysqld)
[9 Jul 2009 12:05] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/78276

3016 Georgi Kodinov	2009-07-09
      Bug #45962: memory leak after 'sort aborted' errors
      
      When the function exits with an error it was not
      freeing the local Unique class instance.
      Fixed my making sure all the places where the function
      returns from are freeing the Unique instance
[19 Aug 2009 15:22] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/81092

3073 Georgi Kodinov	2009-07-09
      Bug #45962: memory leak after 'sort aborted' errors
      
      When the function exits with an error it was not
      freeing the local Unique class instance.
      Fixed my making sure all the places where the function
      returns from are freeing the Unique instance
[2 Sep 2009 16:41] Bugs System
Pushed into 5.1.39 (revid:joro@sun.com-20090902154533-8actmfcsjfqovgsb) (version source revid:joro@sun.com-20090709120530-32st2vp5vvsbswzv) (merge vers: 5.1.39) (pib:11)
[14 Sep 2009 16:05] Bugs System
Pushed into 5.4.4-alpha (revid:alik@sun.com-20090914155317-m1g9wodmndzdj4l1) (version source revid:alik@sun.com-20090914155317-m1g9wodmndzdj4l1) (merge vers: 5.4.4-alpha) (pib:11)
[16 Sep 2009 0:54] Paul Dubois
Noted in 5.1.39, 5.4.4 changelogs.

Killing a query that was performing a sort could result in a memory leak.
[1 Oct 2009 5:59] Bugs System
Pushed into 5.1.39-ndb-6.3.28 (revid:jonas@mysql.com-20091001055605-ap2kiaarr7p40mmv) (version source revid:jonas@mysql.com-20091001055605-ap2kiaarr7p40mmv) (merge vers: 5.1.39-ndb-6.3.28) (pib:11)
[1 Oct 2009 7:25] Bugs System
Pushed into 5.1.39-ndb-7.0.9 (revid:jonas@mysql.com-20091001072547-kv17uu06hfjhgjay) (version source revid:jonas@mysql.com-20091001071652-irejtnumzbpsbgk2) (merge vers: 5.1.39-ndb-7.0.9) (pib:11)
[1 Oct 2009 13:25] Bugs System
Pushed into 5.1.39-ndb-7.1.0 (revid:jonas@mysql.com-20091001123013-g9ob2tsyctpw6zs0) (version source revid:jonas@mysql.com-20091001123013-g9ob2tsyctpw6zs0) (merge vers: 5.1.39-ndb-7.1.0) (pib:11)
[5 Oct 2009 10:50] Bugs System
Pushed into 5.1.39-ndb-6.2.19 (revid:jonas@mysql.com-20091005103850-dwij2dojwpvf5hi6) (version source revid:jonas@mysql.com-20090930185117-bhud4ek1y0hsj1nv) (merge vers: 5.1.39-ndb-6.2.19) (pib:11)
[7 Oct 2009 16:27] Paul Dubois
The 5.4 fix has been pushed to 5.4.3.