Bug #45002 memory leak in libmysqlclient.so
Submitted: 21 May 2009 7:55 Modified: 16 Oct 2009 9:01
Reporter: Liviu Vasut Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server: C API (client library) Severity:S3 (Non-critical)
Version:5.0.77, 5.0, 5.1, 6.0 bzr OS:Linux (2.6.27.21-170.2.56.fc10.i686 #1 SMP Mon Mar 23 23:37:54 EDT 2009 i686 i686 i386 GNU/Linux)
Assigned to: CPU Architecture:Any
Tags: C API, Leak, libmysqlclient, Memory
Triage: Triaged: D3 (Medium)

[21 May 2009 7:55] Liviu Vasut
Description:
this is similar to bug #33807 which was supposed to be fixed in versions later than 5.0.67, but it's not. I'm using 5.0.77 and there still is a leak.

this is the valgrind report:

$ valgrind --leak-check=full --show-reachable=yes ./mybug          
==1660== Memcheck, a memory error detector.                                    
==1660== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.       
==1660== Using LibVEX rev 1804, a library for dynamic binary translation.
==1660== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==1660== Using valgrind-3.3.0, a dynamic binary instrumentation framework.
==1660== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==1660== For more details, rerun with: -v
==1660==
selected value: this is a test
==1660==
==1660== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 31 from 1)
==1660== malloc/free: in use at exit: 61,336 bytes in 16 blocks.
==1660== malloc/free: 125 allocs, 109 frees, 136,301 bytes allocated.
==1660== For counts of detected errors, rerun with: -v
==1660== searching for pointers to 16 not-freed blocks.
==1660== checked 761,960 bytes.
==1660==
==1660== 16 bytes in 1 blocks are still reachable in loss record 1 of 2
==1660==    at 0x4006AEE: malloc (vg_replace_malloc.c:207)
==1660==    by 0x4B69D1C: my_malloc (in /usr/lib/mysql/libmysqlclient.so.15.0.0)
==1660==    by 0x4B6AACA: my_error_register (in /usr/lib/mysql/libmysqlclient.so.15.0.0)
==1660==    by 0x4B6992F: init_client_errs (in /usr/lib/mysql/libmysqlclient.so.15.0.0)
==1660==    by 0x4B68278: mysql_server_init (in /usr/lib/mysql/libmysqlclient.so.15.0.0)
==1660==    by 0x4B907C8: mysql_init (in /usr/lib/mysql/libmysqlclient.so.15.0.0)
==1660==    by 0x80487E1: main (in /home/li/dev/ajax/mybug)
==1660==
==1660==
==1660== 61,320 bytes in 15 blocks are still reachable in loss record 2 of 2
==1660==    at 0x4006AEE: malloc (vg_replace_malloc.c:207)
==1660==    by 0x4B71502: my_once_alloc (in /usr/lib/mysql/libmysqlclient.so.15.0.0)
==1660==    by 0x4B71BDA: (within /usr/lib/mysql/libmysqlclient.so.15.0.0)
==1660==    by 0x4B72671: (within /usr/lib/mysql/libmysqlclient.so.15.0.0)
==1660==    by 0x4B7288F: get_charset_by_csname (in /usr/lib/mysql/libmysqlclient.so.15.0.0)
==1660==    by 0x4B90582: mysql_init_character_set (in /usr/lib/mysql/libmysqlclient.so.15.0.0)
==1660==    by 0x4B9268D: mysql_real_connect (in /usr/lib/mysql/libmysqlclient.so.15.0.0)
==1660==    by 0x8048827: main (in /home/li/dev/ajax/mybug)
==1660==
==1660== LEAK SUMMARY:
==1660==    definitely lost: 0 bytes in 0 blocks.
==1660==      possibly lost: 0 bytes in 0 blocks.
==1660==    still reachable: 61,336 bytes in 16 blocks.
==1660==         suppressed: 0 bytes in 0 blocks.

this is the source of mybug program:

/*                                                                                                          
 * =====================================================================================                    
 *                                                                                                          
 *       Filename:  mybug.c                                                                                 
 *                                                                                                          
 *    Description:  mysql memory leak test case                                                             
 *                                                                                                          
 *        Created:  05/21/2009 09:57:48 AM EEST                                                             
 *       Compiler:  gcc                                                                                     
 *                                                                                                          
 * =====================================================================================                    
 */                                                                                                         

#include <stdio.h>
#include <string.h>
#include "/usr/include/mysql/mysql.h"

int main(){
        MYSQL my_connection;
        MYSQL_RES *result;
        MYSQL_ROW row;
        unsigned int success;
        char cmd[]="select 'this is a test'";

        mysql_init(&my_connection);
        if (!mysql_real_connect(&my_connection,"localhost","root","pass","test",0,NULL,0))
        {
                fprintf(stderr, "Failed to connect to database: Error: %s\n",
                                mysql_error(&my_connection));
        }
        else{
                if (mysql_real_query(&my_connection,cmd,strlen(cmd)))
                        success=mysql_errno(&my_connection);
                else
                {
                        result = mysql_store_result(&my_connection);
                        if (result)
                        {
                                if((row=mysql_fetch_row(result)))
                                        printf("selected value: %s\n", row[0]?row[0]:"null");
                                mysql_free_result(result);
                        }
                        else
                        {
                                if(mysql_field_count(&my_connection) == 0)
                                        success=0;
                                else
                                        success=mysql_errno(&my_connection);
                        }
                }
                mysql_close(&my_connection);
        }

        return 0;
}
/* end of mybug.c */

My system is:
Linux localhost.localdomain 2.6.27.21-170.2.56.fc10.i686 #1 SMP Mon Mar 23 23:37:54 EDT 2009 i686 i686 i386 GNU/Linux

How to repeat:
1. create a c source file (eg. mybug.c) and copy the contents from above; make sure to change host, user, password, database to fit your configuration.
2. compile with: gcc mybug.c -o mybug -L/usr/lib/mysql -lmysqlclient
3. run through valgrind with: valgrind --leak-check=full --show-reachable=yes ./mybug

Thanks for your time.
Liviu
[21 May 2009 8:38] Sveta Smirnova
Thank you for the report.

I can not repeat described behavior with current development sources.

Please indicate which version of valgrind do you use and exact MySQL package do you use (file name). Also worth trying to check it with current version 5.0.81 in your environment.
[22 May 2009 6:59] Liviu Vasut
Hello.

Here are my packages (these are the newest in the fedora 10 repository):

$ rpm -q valgrind mysql-devel mysql glibc
valgrind-3.3.0-4.i386
mysql-devel-5.0.77-1.fc10.i386
mysql-5.0.77-1.fc10.i386
glibc-2.9-3.i686

I also tested the same thing on a Fedora 9 system, same packages version and same behaviour.

Following your advice, I downloaded mysql version 5.0.81. The problem still persists.

These are my steps:

$ tar xzf mysql-5.0.81-linux-i686.tar.gz
$ cd mysql-5.0.81-linux-i686
$ ./configure
...configure output...
$ gcc mybug.c -o mybug -Llib -lmysqlclient
$ valgrind ./mybug
==6869== Memcheck, a memory error detector.      
==6869== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==6869== Using LibVEX rev 1804, a library for dynamic binary translation.
==6869== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.       
==6869== Using valgrind-3.3.0, a dynamic binary instrumentation framework.
==6869== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.  
==6869== For more details, rerun with: -v                                 
==6869==                                                                  
selected value: this is a test                                            
==6869==                                                                  
==6869== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 31 from 1)  
==6869== malloc/free: in use at exit: 61,336 bytes in 16 blocks.          
==6869== malloc/free: 125 allocs, 109 frees, 136,301 bytes allocated.     
==6869== For counts of detected errors, rerun with: -v                    
==6869== searching for pointers to 16 not-freed blocks.                   
==6869== checked 762,008 bytes.                                           
==6869==                                                                  
==6869== LEAK SUMMARY:                                                    
==6869==    definitely lost: 0 bytes in 0 blocks.                         
==6869==      possibly lost: 0 bytes in 0 blocks.                         
==6869==    still reachable: 61,336 bytes in 16 blocks.                   
==6869==         suppressed: 0 bytes in 0 blocks.                         
==6869== Rerun with --leak-check=full to see details of leaked memory.
[25 May 2009 9:16] Sveta Smirnova
Thank you for the feedback.

Sorry: missed "still reachable" part.

Verified as described.
[30 Sep 2009 20:02] Chad Phillips
this is still an issue with the latest libmysqlclient.so (5.0.86).  i recompiled MySQL with debugging symbols so that valgrind would give us some better detail, and used the same test file as above:

valgrind --leak-check=full --leak-resolution=high --show-reachable=yes ./mybug
==16518== Memcheck, a memory error detector.
==16518== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==16518== Using LibVEX rev 1658, a library for dynamic binary translation.
==16518== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==16518== Using valgrind-3.2.1, a dynamic binary instrumentation framework.
==16518== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==16518== For more details, rerun with: -v
==16518== 
selected value: this is a test
==16518== 
==16518== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 16 from 1)
==16518== malloc/free: in use at exit: 61,336 bytes in 16 blocks.
==16518== malloc/free: 82 allocs, 66 frees, 115,692 bytes allocated.
==16518== For counts of detected errors, rerun with: -v
==16518== searching for pointers to 16 not-freed blocks.
==16518== checked 371,920 bytes.
==16518== 
==16518== 16 bytes in 1 blocks are still reachable in loss record 1 of 3
==16518==    at 0x40053C0: malloc (vg_replace_malloc.c:149)
==16518==    by 0x8052E7C: my_malloc (my_malloc.c:34)
==16518==    by 0x805356D: my_error_register (my_error.c:173)
==16518==    by 0x8052B0F: init_client_errs (errmsg.c:229)
==16518==    by 0x804F848: mysql_server_init (libmysql.c:128)
==16518==    by 0x806CB21: mysql_init (client.c:1512)
==16518==    by 0x804B2C8: main (in /root/mybug)
==16518== 
==16518== 
==16518== 28,616 bytes in 7 blocks are still reachable in loss record 2 of 3
==16518==    at 0x40053C0: malloc (vg_replace_malloc.c:149)
==16518==    by 0x8055405: my_once_alloc (my_once.c:61)
==16518==    by 0x8055BEC: init_state_maps (charset.c:65)
==16518==    by 0x80565E6: init_available_charsets (charset.c:435)
==16518==    by 0x8056761: get_charset_by_csname (charset.c:577)
==16518==    by 0x806C092: mysql_init_character_set (client.c:1783)
==16518==    by 0x806D674: mysql_real_connect (client.c:2184)
==16518==    by 0x804B30E: main (in /root/mybug)
==16518== 
==16518== 
==16518== 32,704 bytes in 8 blocks are still reachable in loss record 3 of 3
==16518==    at 0x40053C0: malloc (vg_replace_malloc.c:149)
==16518==    by 0x8055405: my_once_alloc (my_once.c:61)
==16518==    by 0x8055BCA: init_state_maps (charset.c:62)
==16518==    by 0x80565E6: init_available_charsets (charset.c:435)
==16518==    by 0x8056761: get_charset_by_csname (charset.c:577)
==16518==    by 0x806C092: mysql_init_character_set (client.c:1783)
==16518==    by 0x806D674: mysql_real_connect (client.c:2184)
==16518==    by 0x804B30E: main (in /root/mybug)
==16518== 
==16518== LEAK SUMMARY:
==16518==    definitely lost: 0 bytes in 0 blocks.
==16518==      possibly lost: 0 bytes in 0 blocks.
==16518==    still reachable: 61,336 bytes in 16 blocks.
==16518==         suppressed: 0 bytes in 0 blocks.

i believe our company is being bitten by this issue, and we would probably be willing to fund somebody to fix it.  any takers?  :)
[4 Oct 2009 23:11] R H
Hello

I have the same problem with a memory leak in the client library.
I have today downloaded the latest version of MySQL for windows xp, and I use the LibMySQL.dll from this installation. I am running applications on Delphi 7 and on Lazarus/FPC. I have a memory leak in both environments.

My problem is, when I call MySQL_Free_Result, sometimes the memory is deallocated and sometimes not. I can see this by debugging through my application and at the same time looking at memory consumption (private bytes and working set) in Process Viewer (http://www.teamcti.com/pview/prcview.htm)

I can also see that whenever MySQL_Free_Result fails to free the memory, subsequent repeated calls to MySQL_Query will eventually free the memory. But these calls must be done on same connection and from same thread.

Is there anyway arround this ? 

To reproduce:
1. Use Delphi 7 and get the MySQL.pas (translation of the c headers) from http://www.audio-data.de/mysql.html.'
2. Now startup loading and initializing the library etc
3. call MySQL_Query with a select sentence (something that returns large result so you can see impact on system memory)
4. call MySQL_Store_Result
5. make repeated calls to MySQL_Fetch_Row, until you get all rows
6. call MySQL_Free_result

Repeat the above step2 3-6 several times, and you will see that sometimes the memory is not freed!!

Kind regards
[16 Oct 2009 4:32] Bogdan Degtyariov
marked as affecting a paying customer
[16 Oct 2009 6:06] Georg Richter
The example code is buggy, mysql_library_end call is missing at the end.
See http://dev.mysql.com/doc/refman/5.0/en/mysql-library-end.html
[16 Oct 2009 6:24] Liviu Vasut
Thanks Georg for your comment. Indeed the example code was buggy. After adding mysql_library_end(); right under mysql_close(&my_connection); valgrind reports everything ok.
It's strange nobody noticed that before (including me :) ). I gues I can mark this "bug" as closed.
Thanks again.
[16 Oct 2009 9:01] Georg Richter
changed status