Bug #50944 Memory leak in C API
Submitted: 5 Feb 2010 14:15 Modified: 6 Feb 2010 6:04
Reporter: Scott Johnson Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server: C API (client library) Severity:S2 (Serious)
Version: mysql-server-5.1.42-7.fc12.i686, 5.1 OS:Linux (Fedora Core 12)
Assigned to: CPU Architecture:Any
Tags: memory leak valgrind c api

[5 Feb 2010 14:15] Scott Johnson
Description:
I've been playing around with this for a while.  I've read other bug reports with similar issues but I'm almost convinced that it's a MySQL issue now.

Take this code for example:
int
Main( void )
{
   	char szQuery[80];
	MYSQL *conn = NULL;
	MYSQL_RES *res = NULL;
	MYSQL_ROW row;	

	const char *server = "10.1.1.109";
	const char *user = "testdb";
	const char *password = "1234567890";
	const char *database = "dbtest";   			
	
	sprintf( szQuery, "select * from tblControl LIMIT 1" ); 
	  	
	if( mysql_library_init( 0, NULL, NULL) )
	{
		syslog( LOG_INFO, "MySQL: library is unable to initialize.");
		exit(1);
	}
	mysql_init(conn);
	
	if (!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) 
	{
	      syslog(LOG_INFO, "MySQL: %s", mysql_error(conn));
	      exit(1);
	}	
	
	syslog( LOG_INFO, szQuery );
	
	if( mysql_query( conn, "select * from tblControl LIMIT 1") )	
		syslog( LOG_INFO, "MySQL: SQL Query Error: %d", mysql_error(conn) );
	res = mysql_store_result( conn );	
	row = mysql_fetch_row(res);
  	printf("%s \n", row[0]);		
  	
	mysql_free_result(res);     
	 
	syslog( LOG_INFO, "Closing mysql" );
	mysql_close(conn);	
	return TRUE;
}

Valgrind reports that I've lost a block of memory.  

==30989== LEAK SUMMARY:
==30989==    definitely lost: 964 bytes in 1 blocks
==30989==    indirectly lost: 0 bytes in 0 blocks
==30989==      possibly lost: 0 bytes in 0 blocks
==30989==    still reachable: 16 bytes in 1 blocks

I've played around with this a lot and one of the things I did was change the variable type of 
MySQL *conn; 
  to
MySQL conn;

==30989== LEAK SUMMARY:
==30989==    definitely lost: 0 bytes in 0 blocks
==30989==    indirectly lost: 0 bytes in 0 blocks
==30989==      possibly lost: 53,144 bytes in 13 blocks
==30989==    still reachable: 8,192 bytes in 3 blocks

From reading the docs on mysql_init; it's supposed to create assign an object when the variable is set to NULL so I should not need to use a new() on it.  I also set up a mysql_free_result on what I get back.  Oh, also, I don't think it has to do with the result.  If I take off the query and just leave the mysql initialization portions on I get the leak as well.  I think it's not freeing up the connection object properly.

Then replaced the pointers in the function to &conn.  It works better but I still get possible lost memory.

This would be all fine and dandy and I wouldn't worry too much about it if the program just ran then quit.  This function is part of a Daemon that will be running 24x7x365.  I don't want to worry about shutting down and restarting the process.

How to repeat:
See above
[5 Feb 2010 18:48] Sveta Smirnova
Thank you for the report.

Verified as described.

Shorter test to repeat:

$cat bug50944.c 
#include <stdio.h>
#include <mysql.h>

int
main( void )
{
        MYSQL conn;

        const char *server = "win2003-x86";
        const char *user = "root";
        const char *password = "";
        const char *database = "sbtest";   

        mysql_init(&conn);

        if (!mysql_real_connect(&conn, server, user, password, database, 33051, NULL, 0)) 
        {
                return 1;
        }

        mysql_close(&conn);

        return 0;
}

Valgrind output:

$valgrind --leak-check=full  ./bug50944
==13378== Memcheck, a memory error detector
==13378== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==13378== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==13378== Command: ./bug50944
==13378== 
==13378== 
==13378== HEAP SUMMARY:
==13378==     in use at exit: 44,728 bytes in 12 blocks
==13378==   total heap usage: 77 allocs, 65 frees, 94,545 bytes allocated
==13378== 
==13378== 4,060 bytes in 1 blocks are possibly lost in loss record 4 of 7
==13378==    at 0x4A05E13: malloc (vg_replace_malloc.c:195)
==13378==    by 0x4C89922: my_once_alloc (my_once.c:61)
==13378==    by 0x4C8A6DC: add_collation (charset.c:229)
==13378==    by 0x4C99964: cs_leave (ctype.c:205)
==13378==    by 0x4CB4EC0: my_xml_leave (xml.c:252)
==13378==    by 0x4CB535F: my_xml_parse (xml.c:374)
==13378==    by 0x4C99EA3: my_parse_charset_xml (ctype.c:306)
==13378==    by 0x4C8AC48: my_read_charset_file (charset.c:346)
==13378==    by 0x4C8AF2E: init_available_charsets (charset.c:426)
==13378==    by 0x4C8B477: get_charset_by_csname (charset.c:562)
==13378==    by 0x4CBC462: mysql_init_character_set (client.c:1805)
==13378==    by 0x4CBD5FA: mysql_real_connect (client.c:2222)
==13378== 
==13378== 4,060 bytes in 1 blocks are possibly lost in loss record 5 of 7
==13378==    at 0x4A05E13: malloc (vg_replace_malloc.c:195)
==13378==    by 0x4C89922: my_once_alloc (my_once.c:61)
==13378==    by 0x4C89A34: my_once_strdup (my_once.c:86)
==13378==    by 0x4C8A330: cs_copy_data (charset.c:146)
==13378==    by 0x4C8A7FF: add_collation (charset.c:245)
==13378==    by 0x4C99964: cs_leave (ctype.c:205)
==13378==    by 0x4CB4EC0: my_xml_leave (xml.c:252)
==13378==    by 0x4CB535F: my_xml_parse (xml.c:374)
==13378==    by 0x4C99EA3: my_parse_charset_xml (ctype.c:306)
==13378==    by 0x4C8AC48: my_read_charset_file (charset.c:346)
==13378==    by 0x4C8AF2E: init_available_charsets (charset.c:426)
==13378==    by 0x4C8B477: get_charset_by_csname (charset.c:562)
==13378== 
==13378== 12,180 bytes in 3 blocks are possibly lost in loss record 6 of 7
==13378==    at 0x4A05E13: malloc (vg_replace_malloc.c:195)
==13378==    by 0x4C89922: my_once_alloc (my_once.c:61)
==13378==    by 0x4C89F82: init_state_maps (charset.c:65)
==13378==    by 0x4C8AECF: init_available_charsets (charset.c:420)
==13378==    by 0x4C8B477: get_charset_by_==13378==    by 0x4C89922: my_once_alloc (my_once.c:61)
==13378==    by 0x4C89F82: init_state_maps (charset.c:65)
==13378==    by 0x4C8AECF: init_available_charsets (charset.c:420)
==13378==    by 0x4C8B477: get_charset_by_csname (charset.c:562)
==13378==    by 0x4CBC462: mysql_init_character_set (client.c:1805)
==13378==    by 0x4CBD5FA: mysql_real_connect (client.c:2222)
==13378==    by 0x40086A: main (bug50944.c:16)
==13378== 
==13378== 16,240 bytes in 4 blocks are possibly lost in loss record 7 of 7
==13378==    at 0x4A05E13: malloc (vg_replace_malloc.c:195)
==13378==    by 0x4C89922: my_once_alloc (my_once.c:61)
==13378==    by 0x4C89F51: init_state_maps (charset.c:62)
==13378==    by 0x4C8AECF: init_available_charsets (charset.c:420)
==13378==    by 0x4C8B477: get_charset_by_csname (charset.c:562)
==13378==    by 0x4CBC462: mysql_init_character_set (client.c:1805)
==13378==    by 0x4CBD5FA: mysql_real_connect (client.c:2222)
==13378==    by 0x40086A: main (bug50944.c:16)
==13378== 
==13378== LEAK SUMMARY:
==13378==    definitely lost: 0 bytes in 0 blocks
==13378==    indirectly lost: 0 bytes in 0 blocks
==13378==      possibly lost: 36,540 bytes in 9 blocks
==13378==    still reachable: 8,188 bytes in 3 blocks
==13378==         suppressed: 0 bytes in 0 blocks
==13378== Reachable blocks (those to which a pointer was found) are not shown.
==13378== To see them, rerun with: --leak-check=full --show-reachable=yes
==13378== 
==13378== For counts of detected and suppressed errors, rerun with: -v
==13378== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 8 from 8)
[6 Feb 2010 4:05] Georg Richter
Hi,

this looks like a duplicate of #45002.
Example code doesn't call mysql_library_end().
[6 Feb 2010 6:04] Sveta Smirnova
Georg,

thank you for the update. You are right: duplicate of bug #45002 and not a bug.