Bug #68070 Maybe there existed memory leak in code
Submitted: 11 Jan 2013 3:01 Modified: 20 Jan 2014 6:29
Reporter: wang huai Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server: Replication Severity:S2 (Serious)
Version:5.6.9 OS:Any
Assigned to: CPU Architecture:Any
Tags: memory leak

[11 Jan 2013 3:01] wang huai
Description:
in version 5.6.9, there maybe  existed memory leak in code, in file sql/binlog.cc, in function THD.decide_logging_format, line 7336, the binlog_accessed_db_names variable is set null, but if it is not null, the memory pointed is lost, and then in function add_to_binlog_accessed_dbs, it is malloced agian, so it is leaked.

How to repeat:
Code inspection.

Suggested fix:
free the binlog_accessed_db_names's memory when it is not null
[11 Jan 2013 12:34] Erlend Dahl
The replication developers can't see that there is a leak. All memory is freed properly.

Please provide a stack trace, test case or a Valgrind report to prove your claim.
[12 Feb 2013 1:00] Bugs System
No feedback was provided for this bug for over a month, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
[17 Nov 2013 12:42] MySQL Verification Team
heap profile for 5.6.14.

Attachment: go.pdf (application/pdf, text), 11.91 KiB.

[20 Jan 2014 6:28] Venkatesh Duggirala
Posted by developer:
 
There is no memory leak with `binlog_accessed_db_names` variable. Please note that the variable `binlog_accessed_db_names` is allocated in MEM_ROOT (performance related reasons) and the MEM_ROOT will be deleted at the end of the query execution (Individual memory locations from a MEM_ROOT cannot be deleted)

However, as shown in the above attached profiler, there was a problem with the memory consumption of this variable in big procedures
which was fixed in 5.6.16.

Prior to 5.6.16, MEM_ROOT used to store this variable was "main_mem_root" which was changed to "execute_mem_root"
to avoid "increasing memory consumption in case of big procedures contains huge number of create/drop tables"
[3 Feb 2014 10:41] Laurynas Biveinis
5.6$ bzr log -r 5646
------------------------------------------------------------
revno: 5646
committer: Venkatesh Duggirala<venkatesh.duggirala@oracle.com>
branch nick: mysql-5.6
timestamp: Mon 2013-11-25 16:52:57 +0530
message:
  Bug #17806014 INCREASING MEMORY/MEMORY LEAK WITH CREATING/DROPPING
  TMP TABLES
  
  Problem: Memory consumption in THD::add_to_binlogged_db_names()
  is growing while executing big procedures.
  
  Analysis: In THD::add_to_binlogged_db_names() function,
  binlog_accessed_db_names list is used to maintain the database                       
  names which are referenced in a given query.
  The mem root used to store this list was 'main_mem_root'.
  The 'main_mem_root' scope is till the end of the given command.
  Hence it caused increasing memory consumption                     
  problem in big procedures like the ones mentioned below.                        
  Eg: "CALL p1()" where p1 is having 1,00,000 create and drop tables.                
  'main_mem_root' is freed only at the end of the command "CALL p1()"'s               
  execution. But binlog_accessed_db_names list scope is only till the              
  individual statements specified the procedure(create/drop statements).          
  Hence the memory allocated in 'main_mem_root' was left uncleared                
  until the p1's completion, even though it is not required after                 
  completion of individual statements.                                            
  
  Fix:                                                                                
  Instead of using 'main_mem_root' whose scope is complete query execution,       
  now the memroot is changed to use 'thd->mem_root' whose scope is untill the      
  individual statement in CALL p1(). 'thd->mem_root' is set to 'execute_mem_root'  
  in the context of procedure and it's scope is till the individual statement     
  in CALL p1() and thd->memroot is equal to 'main_mem_root' in the context        
  of a normal 'top level query'.                                                   
                                                                                  
  Eg: a) create table t1(i int); => If this function is called while              
  processing this statement, thd->memroot is equal to &main_mem_root                         
  which will be freed immediately after executing this statement.                                       
  b) CALL p1() -> p1 contains create table t1(i int); => If this function                                       
  is called while processing create table statement which is inside               
  a stored procedure, then thd->memroot is equal to 'execute_mem_root'                                                     
  which will be freed immediately after executing this statement.                 
  In both a and b case, thd->memroot will be freed immediately and will not       
  increase memory consumption.                                                    
                                                                                                                                                 
  A special case(stored functions/triggers):                                      
  Consider the following example:                                                                                                                    
  create function f1(i int) returns int                                           
  begin                                                                                                                                                  
  insert into db1.t1 values (1);                                                  
  insert into db2.t1 values (2);                                                  
  end;                                                                                                                                                       
  When we are processing SELECT f1(), the list should contain db1, db2 names.     
  Since thd->memroot contains 'execute_mem_root' in the context of         
  stored function, the mem root will be freed after adding db1 in                 
  the list and when we are processing the second statement and when we try      
  to add 'db2' in the db1's list, it will lead to crash as db1's memory           
  is already freed. To handle this special case, if in_sub_stmt is set                                                                                                 
  (which is true incase of stored functions/triggers), we use &main_mem_root,
  if not set we will use thd->memroot which changes it's value to                 
  'execute_mem_root' or '&main_mem_root' depends on the context.  
  Hence considering this specical case, fix will be to make 
  used_memroot= in_sub_stmt ? &main_mem_root: memroot.