This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Libstdc++-v3 memory leakage?


I encountered some memory leakage using "gcc version 3.2.2 (mingw special 20030208-1)", and I reduced it to the following simple test case:

--- begin test.cpp ---
#include <vector>
#include "debug_new.h"

using std::vector;

int main()
{
	vector<int> v;
//	v.reserve(33);
	v.push_back(1);
	v.push_back(2);
}
---  end test.cpp  ---

debug_new.cpp and debug_new.h are my simple leakage detector. They are not directly related to this problem. One may use any leakage detector, I suppose. For the ease of reproducing the problem, I attached them here. The command line I use is simply "g++ test.cpp debug_new.cpp".

One point to notice is that if I uncomment the "reserve" line, the leak is gone. If I change 33 to 32, the leak comes back.

I know that not all kind of memory leakage will cause problems, but 1) I need to be assured of the harmlessness; and 2) the leakage report defeats my purpose to easily catch my own memory leaks, because it is hard to tell which is caused by which.

This problem does not seem to exist in the libstdc++ w/ GCC 2.95.3, nor in SGI STL or STLport.

I never posted to libstdc++, and apologize for any ignorances. I searched for leakage in the list but did not find any relevant infomation.

Best regards,

Wu Yongwei
/*
 * debug_new.cpp	1.7 2003/02/09
 *
 * Implementation of debug versions of new and delete to check leakage
 *
 * By Wu Yongwei
 *
 */

#include <stdio.h>
#include <stdlib.h>

#ifdef _MSC_VER
#pragma warning(disable: 4073)
#pragma init_seg(lib)
#endif

#ifndef DEBUG_NEW_HASHTABLESIZE
#define DEBUG_NEW_HASHTABLESIZE 16384
#endif

#ifndef DEBUG_NEW_HASH
#define DEBUG_NEW_HASH(p) (((unsigned)(p) >> 8) % DEBUG_NEW_HASHTABLESIZE)
#endif

struct new_ptr_list_t
{
	new_ptr_list_t*		next;
	const char*			file;
	int					line;
	size_t				size;
};

static new_ptr_list_t* new_ptr_list[DEBUG_NEW_HASHTABLESIZE];

bool new_verbose_flag = false;
bool new_autocheck_flag = true;

bool check_leaks()
{
	bool fLeaked = false;
	for (int i = 0; i < DEBUG_NEW_HASHTABLESIZE; ++i)
	{
		new_ptr_list_t* ptr = new_ptr_list[i];
		if (ptr == NULL)
			continue;
		fLeaked = true;
		while (ptr)
		{
			printf("Leaked object at %p (size %u, %s:%d)\n",
					(char*)ptr + sizeof(new_ptr_list_t),
					ptr->size,
					ptr->file,
					ptr->line);
			ptr = ptr->next;
		}
	}
	if (fLeaked)
		return true;
	else
		return false;
}

void* operator new(size_t size, const char* file, int line)
{
	size_t s = size + sizeof(new_ptr_list_t);
	new_ptr_list_t* ptr = (new_ptr_list_t*)malloc(s);
	if (ptr == NULL)
	{
		fprintf(stderr, "new:  out of memory when allocating %u bytes\n",
				size);
		abort();
	}
	void* pointer = (char*)ptr + sizeof(new_ptr_list_t);
	size_t hash_index = DEBUG_NEW_HASH(pointer);
	ptr->next = new_ptr_list[hash_index];
	ptr->file = file;
	ptr->line = line;
	ptr->size = size;
	new_ptr_list[hash_index] = ptr;
	if (new_verbose_flag)
		printf("new:  allocated  %p (size %u, %s:%d)\n",
				pointer, size, file, line);
	return pointer;
}

void* operator new[](size_t size, const char* file, int line)
{
	return operator new(size, file, line);
}

void* operator new(size_t size)
{
	return operator new(size, "<Unknown>", 0);
}

void* operator new[](size_t size)
{
	return operator new(size);
}

void operator delete(void* pointer)
{
	if (pointer == NULL)
		return;
	size_t hash_index = DEBUG_NEW_HASH(pointer);
	new_ptr_list_t* ptr = new_ptr_list[hash_index];
	new_ptr_list_t* ptr_last = NULL;
	while (ptr)
	{
		if ((char*)ptr + sizeof(new_ptr_list_t) == pointer)
		{
			if (new_verbose_flag)
				printf("delete: freeing  %p (size %u)\n", pointer, ptr->size);
			if (ptr_last == NULL)
				new_ptr_list[hash_index] = ptr->next;
			else
				ptr_last->next = ptr->next;
			free(ptr);
			return;
		}
		ptr_last = ptr;
		ptr = ptr->next;
	}
	fprintf(stderr, "delete: invalid pointer %p\n", pointer);
	abort();
}

void operator delete[](void* pointer)
{
	operator delete(pointer);
}

// Some older compilers like Borland C++ Compiler 5.5.1 and Digital Mars
// Compiler 8.29 do not support placement delete operators.
// NO_PLACEMENT_DELETE needs to be defined when using such compilers.
// Also note that in that case memory leakage will occur if an exception
// is thrown in the initialization (constructor) of a dynamically
// created object.
#ifndef NO_PLACEMENT_DELETE
void operator delete(void* pointer, const char* file, int line)
{
	if (new_verbose_flag)
		printf("new:  exception thrown on initializing object at %p (%s:%d)\n",
				pointer, file, line);
	operator delete(pointer);
}

void operator delete[](void* pointer, const char* file, int line)
{
	operator delete(pointer, file, line);
}
#endif // NO_PLACEMENT_DELETE

// Proxy class to automatically call check_leaks if new_autocheck_flag is set
class new_check_t
{
public:
	new_check_t() {}
	~new_check_t()
	{
		if (new_autocheck_flag)
		{
			// Check for leakage.
			// If any leaks are found, set new_verbose_flag so that any
			// delete operations in the destruction of global/static
			// objects will display information to compensate for
			// possible false leakage reports.
			if (check_leaks())
				new_verbose_flag = true;
		}
	}
};
static new_check_t new_check_object;
/*
 * debug_new.h	1.4 2002/12/16
 *
 * Header file for checking leakage by operator new
 *
 * By Wu Yongwei
 *
 */

#ifndef _DEBUG_NEW_H
#define _DEBUG_NEW_H

#include <new>

/* Prototypes */
bool check_leaks();
void* operator new(size_t size, const char* file, int line);
void* operator new[](size_t size, const char* file, int line);
#ifndef NO_PLACEMENT_DELETE
void operator delete(void* pointer, const char* file, int line);
void operator delete[](void* pointer, const char* file, int line);
#endif // NO_PLACEMENT_DELETE
void operator delete[](void*);	// MSVC 6 requires this declaration

/* Macros */
#define new DEBUG_NEW
#define DEBUG_NEW new(__FILE__, __LINE__)
#ifdef EMULATE_DEBUG_MALLOC
#include <stdlib.h>
#define malloc(s) ((void*)(new char[s]))
#define free(p) delete[] (char*)(p)
#endif // EMULATE_DEBUG_MALLOC

/* Control flags */
extern bool new_verbose_flag;	// default to false: no verbose information
extern bool new_autocheck_flag;	// default to true: call check_leaks() on exit

#endif // _DEBUG_NEW_H

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]