C++ realloc troubles...

Started by
12 comments, last by skidz 14 years ago
Hi. I am having some trouble with realloc, specifically when I increase the size of a block of memory. I have a global pointer array of objects that I deal with, and those are created using 'new'. The reason I mention this array is because it is becoming corrupt from realloc. When I use realloc, it starts freeing objects in my global array and writing over them, starting at the first object and moving on. Its like realloc has no clue there is anything even there, and just writes over it. Why I think realloc is actually freeing this memory is because when I try to delete the objects of the global array it says "Free Heap block 'bla' modified at 'bla' after it was freed". Now I read that that can mean I am trying to refree something that is already freed. I am not sure though. My code looks something like this, I simplify it greatly, removed a lot of safety checks etc so I can present something here.


fillvertlist();  // Fills the global array with data from a txt file.

// Start off the model file by creating the root.
int allocated_memory = sizeof( model_t );
void *pToFile = malloc( sizeof( model_t ) );

// Create a pointer to the model.
model_t *pModel = (model_t *)pToFile;
memset( pModel, 0, sizeof( model_t ) );

// Vertex Groups
pModel->num_vertex_groups = 1;
pModel->vertex_groups_offset = allocated_memory;
allocated_memory += CreateVertexGroupBlock( &pToFile, allocated_memory );

Then I pass the pointer of pToFile into functions which realloc's and adds new memory to the end. Basically I am creating a buffer that I in the end write to a model file, which my game can load. A function could look like this.

int CreateVertexGroupBlock( void **ppToFile, int cur_alloc )
{
	int num_bytes_alloced = 0;
	byte *pCurFilePos = ((byte*)*ppToFile);

	if ( !*ppToFile )
		return 0;

	// Move everything forward.
	num_bytes_alloced += sizeof(vertex_groups_t);
	pCurFilePos = (pCurFilePos + cur_alloc );

	// realloc new memory size, and create the object.
	*ppToFile = realloc( *ppToFile, cur_alloc + num_bytes_alloced );
	vertex_groups_t *vert_group = (vertex_groups_t*)pCurFilePos;
	memset( vert_group, 0, sizeof( vertex_groups_t ) );

	// Vert Group Variables
	strncpy( vert_group->name, "Default", 7 );
	vert_group->meshes_offset = sizeof( vertex_groups_t );

	//Move forward for next blocks
	//cur_byte_pos += sizeof( vertex_groups_t );
	pCurFilePos = (pCurFilePos + sizeof( vertex_groups_t ) );

	// A bunch of other stuff happens, stores all the objects from the global array etc...

	return num_bytes_alloced;
}

That is an example of sticking a vertex_groups_t object on the end of the data buffer. Again this was all working great until just recently when I tried reallocing more memory for storing a collision model as well. One thing to note is that I am deleting all the global array objects since they aren't needed anymore, and filling them up again with the collision model data so it can be written in the same manner as the models real verts. I wonder if passing the pointer to functions is causing realloc to not understand exactly how much is allocated, or where it is in memory. Or is deleting the objects in the global array while that buffer is still getting written, is causing realloc to not understand where the global array data is, and its just writing over top obliviously. Its hard to describe my thoughts on the matter to be honest. I wonder if after creating the data in the global array, I should copy the malloc'd block in front of it so it doesn't overwrite the global array, but I thought realloc was designed to know when it was too large and move itself. Anyway, I hope I was specific enough, and I will post all the code if it's really needed, but there is a lot. So in conclusion, the problem is that I don't understand why realloc is writing over already stored memory (The stuff being pointed to by the global pointer array).
Advertisement
Can I use realloc() on pointers allocated via new?


Quote:
I have a global pointer array of objects that I deal with, and those are created using 'new'.


Is there a strong reason why you're not using std::vector?

I am not using realloc on a pointer allocated via new. I am using it on a void pointer allocated using malloc.

void *pToFile = malloc( sizeof( model_t ) );

Why am I not using a vector? It really isn't needed. We are talking about a list of triangles that NEVER changes, is very static. Sure when I load a new vertex file the array gets completely deleted and replaced with the triangles of the new polyhedra, but still why would I need a vector when it really doesn't need all that extra overhead.

The array of pointers isn't the issue, its that a completely different way of allocating memory, malloc and realloc, is overwriting data pointed to by this array of pointers. It shouldn't be doing that, but it is, as if realloc has no clue anything even exists where it is overwriting.
Don't mix C++ and C code when it comes to memory management. Their approaches are totally different. C sees structures as contiguous blocks you can copy willy-nilly, and typically uses bitwise copies. This is a recipe for disaster with C++ objects, as they focus on contextual operations between objects.

Quote:...overwriting data pointed to by this array of pointers. It shouldn't be doing that, but it is, as if realloc has no clue anything even exists where it is overwriting.


realloc() may move blocks.
And here's your error:

byte *pCurFilePos = ((byte*)*ppToFile);// Move everything forward.num_bytes_alloced += sizeof(vertex_groups_t);pCurFilePos = (pCurFilePos + cur_alloc ); // pCurFilePos now points to past-end of *ppToFile// realloc new memory size, and create the object.*ppToFile = realloc( *ppToFile, cur_alloc + num_bytes_alloced );vertex_groups_t *vert_group = (vertex_groups_t*)pCurFilePos; // <-- If *ppToFile was moved to another part of memory, vert_group will point to the past-end of already freed memory!memset( vert_group, 0, sizeof( vertex_groups_t ) ); // <-- ??% chance of exploding!
Thanks _fastcall, that is a huge oversight on my part. :D
And with that the issue is solved, and I learnt something new!
I also realized the way I was going about some of this isn't exactly safe, so I have to rethink some things for sure.

Thanks again for the help guys, I really appreciate it! :)
Quote:Original post by skidz
but still why would I need a vector when it really doesn't need all that extra overhead.

What overhead? vector does exactly what you do manually -- hold a pointer and keep track of size and capacity. In release builds, reading from a vector isn't slower than any solution you would come up with yourself.

The central idea of C++ is that abstractions don't have any artificial cost. For example, virtual functions aren't slower than your own dynamic dispatch solution. This is opposed to, say, Java, where every additional object requires one additional indirection, which is less efficient in both space and time.
std::vector hands down
Quote:Original post by DevFred
Quote:Original post by skidz
but still why would I need a vector when it really doesn't need all that extra overhead.

What overhead? vector does exactly what you do manually -- hold a pointer and keep track of size and capacity. In release builds, reading from a vector isn't slower than any solution you would come up with yourself.
That's not quite true, for one thing I didn't notice any exponential growth in the OPs code.
More to the point the equivalent C version would malloc() a new buffer to copy the new data into, and finally free() the original. An good realloc implementation on the other hand might resize the buffer in-place, use memory mapping tricks avoid copying (as glibc does), not to mention need 30% less memory.

I'm not saying this is a big enough reason to forgo the convenience of std::vector but for huge one-off buffers it certainly is worth considering.

This topic is closed to new replies.

Advertisement