Bug #8370 Memory leak when using fstream
Submitted: 8 Feb 2005 15:48 Modified: 11 Feb 2005 19:33
Reporter: Peter Hooper Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server Severity:S3 (Non-critical)
Version:4.1.9-nt OS:Windows (Windows 2000 Pro)
Assigned to: Jim Winstead CPU Architecture:Any

[8 Feb 2005 15:48] Peter Hooper
Description:
When using a simple program (code to follow) which uses an fstream a memory leak occurs. However, this leak only occurs if a connection to a database has been established using mysql_real_connect. I have only made a empirical study and not sought to investigate the code.

How to repeat:
Using Microsoft VC6 create a win32 console app with the code (see below). Running the exe as it stands without uncommenting the mysql_real_connect, results in steady memory usage for the application. Running the code with the connect in results in a steady climb in memory usage. This application is not meant to _do_ anything except illustrate the problem I have in a more complex application.

(NOTE: Connection settings will need to be changed to connect to a database that you have available)
---------------------------------------------

// fstream2.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <fstream>

#include <winsock2.h>
#include "mysql.h"

using namespace std;

int main(int argc, char* argv[])
{
	MYSQL * pMySQL = mysql_init(NULL);
/*
	mysql_real_connect(pMySQL, "localhost",
					   "root",
					   "password",
					   "transerv",
					   0,
					   NULL,
					   0);*/

	while(1)
	{
		fstream x("C:\\boot.ini", ios::in);
		x.close();
	}

	return 0;
}

Suggested fix:
I'm going to have a look at the code now. Thought this was important enough to raise immediately though.
[8 Feb 2005 16:50] Peter Hooper
1) I have played round with the include order, leaks still occur.
2) I have disconnected before entering the infinite loop, leaks still occur.
3) I have passed in parameters to a non-existing database, leaks still occur.

I conclude this is down to the fact that mysql_real_connect has been called, and is in no way related to the connection status.
[8 Feb 2005 17:10] Peter Hooper
Without having the source code, I have looked at the fstream object in memory. It appears as thought the virtual function pointer table is different in the two cases. On playing with the case that does not leak, I can make it leak by changing the v-table. It appears as though the offending function is the virtual destructor for basic_fstream().

I assume then this is over-ridden by MySQL?
[8 Feb 2005 17:25] MySQL Verification Team
Thank you for the bug report. I did the test against Purify and the relevant
informations are:

[I] Starting Purify'd bug8370.exe at 08/02/2005 15:20:24
        Instrumented executable: D:\Arquivos de programas\Rational\PurifyPlus\cache\bug8370$Purify_C_temp.exe
        Working directory:       C:\temp
        Command line arguments:  <none>
        Process ID:              0x474
        Thread ID: 0xf4c
[I] Starting main
[E] ABR: Array bounds read in memcmp {1 occurrence}
        Reading 4 bytes from 0x02544370 (1 byte at 0x02544373 illegal)
        Address 0x02544370 is argument #1 of memcmp
        Address 0x02544370 is 17144 bytes into a 17147 byte block at 0x02540078
        Address 0x02544370 points to a malloc'd block in heap 0x003c0000
        Thread ID: 0xf4c
        Error location
            memcmp         [memcmp.asm:60]
            my_xml_scan    [xml.c:84]
            my_xml_parse   [xml.c:226]
            my_parse_charset_xml [ctype.c:314]
            my_read_charset_file [charset.c:314]
            init_available_charsets [charset.c:404]
            get_charset_by_csname [charset.c:549]
            mysql_real_connect [client.c:1882]
        Allocation location
            malloc         [dbgheap.c:129]
            my_malloc      [my_malloc.c:35]
            my_read_charset_file [charset.c:303]
            init_available_charsets [charset.c:404]
            get_charset_by_csname [charset.c:549]
            mysql_real_connect [client.c:1882]
[[<cut>

[W] MLK: Memory leak of 4 bytes from 1 block allocated in putenv_lk [LIBMYSQL.dll]
        Distribution of leaked blocks
                 4 bytes from 1 block of 4 bytes (0x003c58b0) 
        Allocation location
            malloc_dbg     [dbgheap.c:164]
            putenv_lk      [putenv.c:127]
            putenv         [putenv.c:78]
            my_win_init    [my_init.c:250]
            my_init        [my_init.c:102]
            libmysql_init  [dll.c:35]
            LibMain        [dll.c:62]
            DllMain        [dll.c:94]
            DllMainCRTStartup [dllcrt0.c:237]
[9 Feb 2005 9:09] Peter Hooper
I do not know if this is the same problem. I get a 6-byte leak everytime I use the fstream object. Hopefully fixing this issue will resolve this leak too, but I think assuming they are related is a little premature without more investigation.
[10 Feb 2005 15:26] Peter Hooper
I have narrowed the problem down even further (and removed MySQL as the source of the problem). It appears as thought there is a memory leak in the STL after using setlocale(). The code below does not leak if setlocale() is not called, however in its current state when setlocale() is called it leaks. Can anyone please help !?!!!

#include <fstream>
#include <locale.h>

using namespace std;

int main(int argc, char* argv[])
{
	int n = 0;

	setlocale(LC_CTYPE, "");

	while(n < 100)
	{
		n++;
		fstream x("c:\\boot.ini");
		x.close();
	}

	return 0;
}
[10 Feb 2005 15:50] MySQL Verification Team
How the Purify report showed, it is in my_win_init, exactly in the 
below line:

_putenv( "TZ=" ); 

and not setlocale.
[10 Feb 2005 16:06] Peter Hooper
Yes, I recommend using :
SetEnvironmentVariable as the call to _putenv will allocate memory that is not freed
[10 Feb 2005 16:16] MySQL Verification Team
My recommendation is to remove that line of code since it
was added for to avoid the VC++ 6.0 compiler bugs which
makes the server takes 100% CPU when the environment
variable TZ was configured. Removing the line of code and
compiling the server with VC++ 2002/03 the issue is fixed.
Then to document the TZ issue and recommend the compilation
with VC++ 2002/03 for whom needs TZ variable.
[10 Feb 2005 16:17] Peter Hooper
Ooops! The last message was sent before I finished...

I suggest using:
  SetEnvironmentVariable("TZ", NULL)
because the call to _putenv will allocate memory that is not freed.

It appears this could crash in XP if the value does not exist, see link:
http://groups.google.co.uk/groups?hl=en&lr=&safe=vss&selm=030101c37249%24f6480540%24a30128...

Hope this helps, however it will not fix my issue with the STL and setlocale :(
[11 Feb 2005 19:33] Jim Winstead
The _putenv('TZ=') leak that Miguel pointed out only exists when the server is compiled with VC6, because that code is not included otherwise, and the leak exists solely to fix a bug in the runtime libraries used by VC6, so there's nothing we can do about it.