Bug #57448 mysql_close must be called after failed mysql_real_connect when mysql_init(NULL)
Submitted: 14 Oct 2010 7:53 Modified: 18 Oct 2010 19:50
Reporter: Shane Bester (Platinum Quality Contributor) Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server: C API (client library) Severity:S3 (Non-critical)
Version:5.1.53 OS:Any
Assigned to: CPU Architecture:Any

[14 Oct 2010 7:53] Shane Bester
Description:
some places in mysql server and client utils forget to call mysql_close after a failed mysql_real_connect and mysql_init had allocated the connection object.

the attached .c file demonstrates the problem.

For example, this leaks memory when mysql_real_connect fails;

MYSQL *dbc=NULL;
dbc=mysql_init(NULL);
if (!mysql_real_connect(dbc,host,username,password,NULL,port,0))
{
  printf("failed");
}
else
{
  mysql_close(dbc);
}
mysql_library_end();

How to repeat:
.

Suggested fix:
This could be documented in the API docs.
And fixed in the server/client utils where needed.
[14 Oct 2010 7:55] MySQL Verification Team
compile and run in valgrind with/without the commented mysql_close option.

Attachment: testcase.c (text/x-csrc), 1.16 KiB.

[14 Oct 2010 9:16] MySQL Verification Team
some code that could be fixed to prevent this issue:

mysql.cc sig_handler handle_sigint(int sig)
mysqlslap.c slap_connect(MYSQL *mysql)
slave.cc connect_to_master(THD* thd, MYSQL* mysql, Master_info* mi,

The one in slave.cc might be a problem when master-connect-retry is set to a low number and the connection to the master repeatedly fails many times.
[14 Oct 2010 10:03] Sveta Smirnova
Thank you for the report.

Please provide valgrind output in your environment: I get only

==5487== HEAP SUMMARY:
==5487==     in use at exit: 1,319,592 bytes in 1,006 blocks
==5487==   total heap usage: 3,063 allocs, 2,057 frees, 18,037,765 bytes allocated
==5487== 
==5487== LEAK SUMMARY:
==5487==    definitely lost: 0 bytes in 0 blocks
==5487==    indirectly lost: 0 bytes in 0 blocks
==5487==      possibly lost: 0 bytes in 0 blocks
==5487==    still reachable: 1,319,592 bytes in 1,006 blocks
==5487==         suppressed: 0 bytes in 0 blocks
==5487== Rerun with --leak-check=full to see details of leaked memory
==5487== 
==5487== For counts of detected and suppressed errors, rerun with: -v
==5487== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 7 from 7)

With mysql_close:

==6035== HEAP SUMMARY:
==6035==     in use at exit: 3,592 bytes in 6 blocks
==6035==   total heap usage: 3,063 allocs, 3,057 frees, 18,037,765 bytes allocated
==6035== 
==6035== LEAK SUMMARY:
==6035==    definitely lost: 0 bytes in 0 blocks
==6035==    indirectly lost: 0 bytes in 0 blocks
==6035==      possibly lost: 0 bytes in 0 blocks
==6035==    still reachable: 3,592 bytes in 6 blocks
==6035==         suppressed: 0 bytes in 0 blocks
==6035== Rerun with --leak-check=full to see details of leaked memory
==6035== 
==6035== For counts of detected and suppressed errors, rerun with: -v
==6035== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 7 from 7)
[14 Oct 2010 10:05] MySQL Verification Team
run it like this.

valgrind -v --show-reachable=yes --leak-check=full ./testcase

==5812== 1,272 bytes in 1 blocks are still reachable in loss record 1 of 3
==5812==    at 0x4A0515D: malloc (vg_replace_malloc.c:195)
==5812==    by 0x4C53491: my_malloc (in /usr/lib64/mysql/libmysqlclient_r.so.16.0.0)
==5812==    by 0x4C7AF9E: mysql_init (in /usr/lib64/mysql/libmysqlclient_r.so.16.0.0)
==5812==    by 0x400973: main (testcase.c:28)
==5812== 
==5812== 13,992 bytes in 11 blocks are possibly lost in loss record 2 of 3
==5812==    at 0x4A0515D: malloc (vg_replace_malloc.c:195)
==5812==    by 0x4C53491: my_malloc (in /usr/lib64/mysql/libmysqlclient_r.so.16.0.0)
==5812==    by 0x4C7AF9E: mysql_init (in /usr/lib64/mysql/libmysqlclient_r.so.16.0.0)
==5812==    by 0x400973: main (testcase.c:28)
==5812== 
==5812== 1,256,736 bytes in 988 blocks are definitely lost in loss record 3 of 3
==5812==    at 0x4A0515D: malloc (vg_replace_malloc.c:195)
==5812==    by 0x4C53491: my_malloc (in /usr/lib64/mysql/libmysqlclient_r.so.16.0.0)
==5812==    by 0x4C7AF9E: mysql_init (in /usr/lib64/mysql/libmysqlclient_r.so.16.0.0)
==5812==    by 0x400973: main (testcase.c:28)
==5812== 
==5812== LEAK SUMMARY:
==5812==    definitely lost: 1,256,736 bytes in 988 blocks
==5812==    indirectly lost: 0 bytes in 0 blocks
==5812==      possibly lost: 13,992 bytes in 11 blocks
==5812==    still reachable: 1,272 bytes in 1 blocks
==5812==         suppressed: 0 bytes in 0 blocks
[14 Oct 2010 10:18] Sveta Smirnova
Thank you for the feedback.

Verified as described:

...
==7430== 2,048 bytes in 1 blocks are still reachable in loss record 6 of 7
==7430==    at 0x4A06168: malloc (vg_replace_malloc.c:236)
==7430==    by 0x4A061E2: realloc (vg_replace_malloc.c:525)
==7430==    by 0x3429E06D19: pthread_create@@GLIBC_2.2.5 (in /lib64/libpthread-2.5.so)
==7430==    by 0x4C8813A: my_thread_global_init (my_thr_init.c:115)
==7430==    by 0x4C7F4EB: my_init (my_init.c:81)
==7430==    by 0x4C72FE0: mysql_server_init (libmysql.c:126)
==7430==    by 0x4CC04CE: mysql_init (client.c:1535)
==7430==    by 0x400AFC: main (in /users/ssmirnova/blade12/src/bugs/bug57448/testcase)
==7430== 
==7430== 1,316,000 bytes in 1,000 blocks are still reachable in loss record 7 of 7
==7430==    at 0x4A06168: malloc (vg_replace_malloc.c:236)
==7430==    by 0x4C8400F: _mymalloc (safemalloc.cbc_dlopen_mode (in /lib64/libc-2.5.so)
==7430==    by 0x3429E0E40B: pthread_cancel_init (in /lib64/libpthread-2.5.so)
==7430==    by 0x3429E0E51F: _Unwind_ForcedUnwind (in /lib64/libpthread-2.5.so)
==7430== 
==7430== 2,048 bytes in 1 blocks are still reachable in loss record 6 of 7
==7430==    at 0x4A06168: malloc (vg_replace_malloc.c:236)
==7430==    by 0x4A061E2: realloc (vg_replace_malloc.c:525)
==7430==    by 0x3429E06D19: pthread_create@@GLIBC_2.2.5 (in /lib64/libpthread-2.5.so)
==7430==    by 0x4C8813A: my_thread_global_init (my_thr_init.c:115)
==7430==    by 0x4C7F4EB: my_init (my_init.c:81)
==7430==    by 0x4C72FE0: mysql_server_init (libmysql.c:126)
==7430==    by 0x4CC04CE: mysql_init (client.c:1535)
==7430==    by 0x400AFC: main (in /users/ssmirnova/blade12/src/bugs/bug57448/testcase)
...
[14 Oct 2010 11:26] MySQL Verification Team
just to clarify what this bug is about.  in most cases throughout the codebase, the mysql_close is called after a failed mysql_real_connect.  this is a request to verify that all cases are correctly handled.  of course, mostly importantly are the ones in the server, such as replication code.
[18 Oct 2010 19:50] Konstantin Osipov
There is no issue in slave.cc, the MYSQL structure is properly destroyed.
A memory leak in a client tool is not as problematic since upon any connect error our utilities terminate, and the memory is reclaimed by the operating system.

Sveta, btw: verifying that a merely demonstrative test case reproduces the problem is not very relevant to the issue at hand.