Bug #93925 Possible memory leak in libmysqlclient20
Submitted: 15 Jan 0:18 Modified: 22 Jan 11:34
Reporter: Arjuna Del Toso Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server: C API (client library) Severity:S3 (Non-critical)
Version:5.7.24 OS:Linux
Assigned to: Bogdan Kecman CPU Architecture:Any

[15 Jan 0:18] Arjuna Del Toso
Description:
On code mostly copy/pasted from the official documentation valgrind reports the following leak

==5525== 7,272 (912 direct, 6,360 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==5525==    at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5525==    by 0x4EA1F8B: ??? (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.20.3.11)
==5525==    by 0x4E6397A: mysql_stmt_init (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.20.3.11)
==5525==    by 0x108F06: main (mysql-bug.c:46)
==5525== 
==5525== LEAK SUMMARY:
==5525==    definitely lost: 912 bytes in 1 blocks
==5525==    indirectly lost: 6,360 bytes in 3 blocks

How to repeat:
Follow these instructions on a machine with docker:

$ docker run -d --name ubu --entrypoint "tail" ubuntu -f /dev/null

$ docker cp mysql-bug.c ubu:.

$ docker exec -it ubu bash

root@d4537d06b4b8:/# apt-get update && apt-get install -y build-essential          libcurl4-openssl-dev     libmysqlclient-dev       valgrind                 clang-tools-6.0          mysql-server

root@d4537d06b4b8:/# service mysql start

root@d4537d06b4b8:/# echo 'CREATE DATABASE db CHARACTER SET utf8 COLLATE utf8_general_ci; USE db; CREATE TABLE tbl (url VARCHAR(260)); INSERT INTO tbl VALUES ("a"), ("b"), ("c");' | mysql -uroot -p

root@d4537d06b4b8:/# cc -g -O0 mysql-bug.c -o mysql-bug -I/usr/include/mysql/ -lmysqlclient

root@d4537d06b4b8:/# valgrind --leak-check=yes ./mysql-bug 2
==5525== Memcheck, a memory error detector
==5525== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5525== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5525== Command: ./mysql-bug 2
==5525== 
row: a
row: b
==5525== 
==5525== HEAP SUMMARY:
==5525==     in use at exit: 7,272 bytes in 4 blocks
==5525==   total heap usage: 80 allocs, 76 frees, 185,983 bytes allocated
==5525== 
==5525== 7,272 (912 direct, 6,360 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==5525==    at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5525==    by 0x4EA1F8B: ??? (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.20.3.11)
==5525==    by 0x4E6397A: mysql_stmt_init (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.20.3.11)
==5525==    by 0x108F06: main (mysql-bug.c:46)
==5525== 
==5525== LEAK SUMMARY:
==5525==    definitely lost: 912 bytes in 1 blocks
==5525==    indirectly lost: 6,360 bytes in 3 blocks
==5525==      possibly lost: 0 bytes in 0 blocks
==5525==    still reachable: 0 bytes in 0 blocks
==5525==         suppressed: 0 bytes in 0 blocks
==5525== 
==5525== For counts of detected and suppressed errors, rerun with: -v
==5525== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

root@d4537d06b4b8:/# dpkg -l libmysqlclient20* valgrind
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                                                  Version                         Architecture                    Description
+++-=====================================================-===============================-===============================-================================================================================================================
ii  libmysqlclient20:amd64                                5.7.24-0ubuntu0.18.04.1         amd64                           MySQL database client library
ii  valgrind                                              1:3.13.0-2ubuntu2.1             amd64                           instrumentation framework for building dynamic analysis tools

root@d4537d06b4b8:/# cc --version
cc (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

root@d4537d06b4b8:/# uname -a
Linux d4537d06b4b8 4.15.0-42-generic #45~16.04.1-Ubuntu SMP Mon Nov 19 13:02:27 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
[15 Jan 0:19] Arjuna Del Toso
The code exposing the issue

Attachment: mysql-bug.c (text/x-csrc), 2.75 KiB.

[22 Jan 11:34] Bogdan Kecman
Hi,

Thanks for report, but this is not a bug

yes, when I run your code:

[arhimed@localhost ~]$ gcc -g -O0 bug93925.c -o mysql-bug -I/home/arhimed/mysql/5.7.24/include/mysql/ -I/home/arhimed/mysql/5.7.24/include/ -L/home/arhimed/mysql/5.7.24/lib/ -lmysqlclient
[arhimed@localhost ~]$ LD_LIBRARY_PATH=/home/arhimed/mysql/5.7.24/lib ./mysql-bug 2
row: a
row: b
[arhimed@localhost ~]$ LD_LIBRARY_PATH=/home/arhimed/mysql/5.7.24/lib valgrind --leak-check=yes  ./mysql-bug 2
==67433== Memcheck, a memory error detector
==67433== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==67433== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==67433== Command: ./mysql-bug 2
==67433==
row: a
row: b
==67433==
==67433== HEAP SUMMARY:
==67433==     in use at exit: 79,976 bytes in 5 blocks
==67433==   total heap usage: 86 allocs, 81 frees, 173,176 bytes allocated
==67433==
==67433== 7,272 (912 direct, 6,360 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 5
==67433==    at 0x4C2A988: calloc (vg_replace_malloc.c:711)
==67433==    by 0x4E94D06: my_raw_malloc (my_malloc.c:189)
==67433==    by 0x4E94D06: my_malloc (my_malloc.c:54)
==67433==    by 0x4E5F22A: mysql_stmt_init (libmysql.c:1552)
==67433==    by 0x400DF7: main (bug93925.c:46)
==67433==
==67433== LEAK SUMMARY:
==67433==    definitely lost: 912 bytes in 1 blocks
==67433==    indirectly lost: 6,360 bytes in 3 blocks
==67433==      possibly lost: 0 bytes in 0 blocks
==67433==    still reachable: 0 bytes in 0 blocks
==67433==         suppressed: 72,704 bytes in 1 blocks
==67433==
==67433== For counts of detected and suppressed errors, rerun with: -v
==67433== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
[arhimed@localhost ~]$
[22 Jan 11:38] Bogdan Kecman
but when I "fix" your code:

[arhimed@localhost ~]$ diff bug93925-original.c bug93925-fixed.c
112c112,113
<   if (mysql_stmt_free_result(stmt) != 0) fwprintf(stderr, L"unable to free stmt");
---
>   if (mysql_stmt_free_result(stmt) != 0) fwprintf(stderr, L"unable to free result");
>   if (mysql_stmt_close(stmt) != 0) fwprintf(stderr, L"unable to free stmt");

as you forgot to free the statement, your error for freeing result mentions statement but actually you have to free result (you are doing it properly but with wrong error msg) and then you need to (and you forgot) free the actual statement with https://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-close.html

you get:

[arhimed@localhost ~]$ LD_LIBRARY_PATH=/home/arhimed/mysql/5.7.24/lib valgrind --leak-check=yes  ./mysql-bug 2
==67460== Memcheck, a memory error detector
==67460== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==67460== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==67460== Command: ./mysql-bug 2
==67460==
row: a
row: b
==67460==
==67460== HEAP SUMMARY:
==67460==     in use at exit: 72,704 bytes in 1 blocks
==67460==   total heap usage: 86 allocs, 85 frees, 173,176 bytes allocated
==67460==
==67460== LEAK SUMMARY:
==67460==    definitely lost: 0 bytes in 0 blocks
==67460==    indirectly lost: 0 bytes in 0 blocks
==67460==      possibly lost: 0 bytes in 0 blocks
==67460==    still reachable: 0 bytes in 0 blocks
==67460==         suppressed: 72,704 bytes in 1 blocks
==67460==
==67460== For counts of detected and suppressed errors, rerun with: -v
==67460== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

all best
Bogdan