Bug #70238 Memory leak in embedded server when executing prepared statements

Submitted: 4 Sep 2013 6:42 Modified: 6 Sep 2017 9:03
Reporter: Feng Guangpu Email Updates:
Status: Can't repeat Impact on me:
None 
Category:MySQL Server: Prepared statements Severity:S2 (Serious)
Version:5.6.11, 5.6.15 OS:Any
Assigned to: CPU Architecture:Any
Tags: embedded, libmysqld, memory leak

[4 Sep 2013 6:42] Feng Guangpu
Description:
The embedded server leaks memeory when executing perpared statements

part of the valgrind output:

==29639== 2,064 bytes in 1 blocks are definitely lost in loss record 3 of 4
==29639==    at 0x4A05FDE: malloc (vg_replace_malloc.c:236)
==29639==    by 0x4635E1: my_malloc (my_malloc.c:38)
==29639==    by 0x462C72: init_alloc_root (my_alloc.c:63)
==29639==    by 0x448935: mysql_stmt_init (libmysql.c:1512)
==29639==    by 0x444277: main (in /u01/mysql5611/bug62136)
==29639== 
==29639== 4,112 bytes in 1 blocks are definitely lost in loss record 4 of 4
==29639==    at 0x4A05FDE: malloc (vg_replace_malloc.c:236)
==29639==    by 0x4635E1: my_malloc (my_malloc.c:38)
==29639==    by 0x462C72: init_alloc_root (my_alloc.c:63)
==29639==    by 0x44894B: mysql_stmt_init (libmysql.c:1513)
==29639==    by 0x444277: main (in /u01/mysql5611/bug62136)
==29639== 
==29639== LEAK SUMMARY:
==29639==    definitely lost: 6,176 bytes in 2 blocks
==29639==    indirectly lost: 0 bytes in 0 blocks
==29639==      possibly lost: 0 bytes in 0 blocks
==29639==    still reachable: 568 bytes in 2 blocks
==29639==         suppressed: 0 bytes in 0 blocks
==29639== 
==29639== For counts of detected and suppressed errors, rerun with: -v
==29639== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 6 from 6)

the reason is that the assignments of stmt->mem_root in emb_read_prepare_result and stmt->result in emb_read_binary_rows without freeing the memory in MEM_ROOT.

libmysqd/lib_sql.cc

line 263:

 251   if (thd->first_data)
 252   {
 253     if (emb_read_query_result(mysql))
 254       return 1;
 255     stmt->field_count= mysql->field_count;
 256     mysql->status= MYSQL_STATUS_READY;
 257     res= thd->cur_data;
 258     thd->cur_data= NULL;
 259     if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
 260       mysql->server_status|= SERVER_STATUS_IN_TRANS;
 261 
 262     stmt->fields= mysql->fields;
 263     stmt->mem_root= res->alloc;
 264     mysql->fields= NULL;
 265     my_free(res);
 266   }

line 365:

 357 int emb_read_binary_rows(MYSQL_STMT *stmt)                                                                                                                         
 358 {
 359   MYSQL_DATA *data;
 360   if (!(data= emb_read_rows(stmt->mysql, 0, 0)))
 361   {
 362     set_stmt_errmsg(stmt, &stmt->mysql->net);
 363     return 1;
 364   }
 365   stmt->result= *data;
 366   my_free(data);
 367   set_stmt_errmsg(stmt, &stmt->mysql->net);
 368   return 0;
 369 }

How to repeat:
Test program will be attached, see the first comment.

Suggested fix:
--- libmysqld/lib_sql.cc        (revision 4360)
+++ libmysqld/lib_sql.cc        (working copy)
@@ -260,7 +260,6 @@
       mysql->server_status|= SERVER_STATUS_IN_TRANS;
 
     stmt->fields= mysql->fields;
-    stmt->mem_root= res->alloc;
     mysql->fields= NULL;
     my_free(res);
   }
@@ -362,6 +361,7 @@
     set_stmt_errmsg(stmt, &stmt->mysql->net);
     return 1;
   }
+  free_root(&(stmt->result.alloc), MYF(0));
   stmt->result= *data;
   my_free(data);
   set_stmt_errmsg(stmt, &stmt->mysql->net);

[No-Mysql@db031133.sqa.cm4 /u01/mysql_prj/PS5518/branches/mysql-5.6.11]
[4 Sep 2013 6:54] Feng Guangpu
libmysqld_prepare_statement.c

Attachment: libmysqld_prepared_statement.c (application/octet-stream, text), 3.20 KiB.

[4 Sep 2013 6:55] Feng Guangpu
contents of my_embedded.cnf:

[client]                                                                                                                                                                
socket = /u01/mysql5611/run/mysql.sock

[embedded]
sort_buffer_size=1M
core-file
#### Baes dir ####
basedir = /u01/mysql5611
datadir = /u01/mysql5611/data_embedded
tmpdir = /u01/mysql5611/tmp_embedded
socket = /u01/mysql5611/run_embedded/mysql.sock
#### Base configure info ####
port = 5611
skip-name-resolve
old_passwords = 0 
lower_case_table_names = 1 
open_files_limit = 65535
read_rnd_buffer_size = 5M
max_allowed_packet = 24M 
max_connect_errors = 500 
max_connections = 5 
max_user_connections = 4 
thread_cache_size=2
table_open_cache=16
table_definition_cache=8

server-id= 5611

#innodb
innodb_data_home_dir = /u01/mysql5611/data_embedded
default-storage-engine = INNODB
innodb_flush_method = O_DIRECT
innodb_file_per_table = 1 
innodb_flush_log_at_trx_commit = 1 
innodb_lock_wait_timeout = 100 
innodb_additional_mem_pool_size = 4M
innodb_buffer_pool_size = 64M 
innodb_log_buffer_size= 8M
innodb_log_file_size = 16M 
innodb_log_files_in_group = 4 
innodb_max_dirty_pages_pct = 75

thread_stack = 1524288
[mysqld_safe]
pid-file = /u01/mysql5611/run_embedded/mysqld.pid
[4 Sep 2013 8:25] Feng Guangpu
in mysql_stmt_init
...
  init_alloc_root(&stmt->mem_root, 2048, 2048);    // line 1512
  init_alloc_root(&stmt->result.alloc, 4096, 4096);// line 1513
...

==29639== 2,064 bytes in 1 blocks are definitely lost in loss record 3 of 4
==29639==    at 0x4A05FDE: malloc (vg_replace_malloc.c:236)
==29639==    by 0x4635E1: my_malloc (my_malloc.c:38)
==29639==    by 0x462C72: init_alloc_root (my_alloc.c:63)
==29639==    by 0x448935: mysql_stmt_init (libmysql.c:1512)
==29639==    by 0x444277: main (in /u01/mysql5611/bug62136)

2064 bytes come from: 2048 + sizeof(USED_MEM)

==29639== 4,112 bytes in 1 blocks are definitely lost in loss record 4 of 4
==29639==    at 0x4A05FDE: malloc (vg_replace_malloc.c:236)
==29639==    by 0x4635E1: my_malloc (my_malloc.c:38)
==29639==    by 0x462C72: init_alloc_root (my_alloc.c:63)
==29639==    by 0x44894B: mysql_stmt_init (libmysql.c:1513)
==29639==    by 0x444277: main (in /u01/mysql5611/bug62136)

4112 bytes come from: 4096 + sizeof(USED_MEM)
[8 Jan 2014 10:05] MySQL Verification Team
Hello Guangpu,

Thank you for the bug report and test case.

Thanks,
Umesh
[6 Sep 2017 9:03] Manyi Lu
Posted by developer:
 
Embedded mode has already been removed starting from 8.0.

Portions of this website are copyright © 2001, 2002 The PHP Group

Page generated in 0.057 sec. using MySQL 8.4.7-u6-cloud

Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the respective copyright holders.
It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.