Heap Corruption!

Started by
11 comments, last by justin12343 11 years, 10 months ago
I'm having trouble locating the cause of a heap corruption I've been getting for last few days. When I debug the corruption doesn't happen in the same place. Visual Studio breaks in a zlib decompression function or in a random fmod call and with Application Verifier, it runs normally, but then breaks in a D3DXSprite call when the player gets to a certain point in the level. I don't even know when this error came up because the debug build never caught it at all. I became aware when someone reported that it wouldn't run on their machine, but it ran fine on mine until I switched to capability mode (I tried all of the options) and I also tried to run it on another machine. I've been trying to solve this for about two weeks now. I tried commenting out portions of code to kind of isolate the problem, but the same thing shows up randomly somewhere else. Any advice will be much appreciated.

Without App Verifier:

int ResourceManager::Uncompress( const unsigned char *src, long srcSize, unsigned char *dst, long destSize)
{
z_stream strm = {0};
strm.total_in = strm.avail_in = srcSize;
strm.total_out = strm.avail_out = destSize;
strm.next_in = (Bytef *) src;
strm.next_out = (Bytef *) dst;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
int err = -1;
int ret = -1;
err = inflateInit2(&strm, (15));
if (err == Z_OK)
{
err = inflate(&strm, Z_FINISH);
if (err == Z_STREAM_END)
{
ret = strm.total_out;
}
else
{
inflateEnd(&strm);
return err;
}
}
else
{
inflateEnd(&strm);
return err;
}
inflateEnd(&strm); //<-------Breaks In This Function. SEE BELOW
return ret;
}


int ResourceManager::ReadSound( Resource *resource)
{
ResourceSound *res = reinterpret_cast<ResourceSound*>( resource);
FILE *file = NULL;
string fname = WorkingDir + res->Filename;
file = fopen( fname.c_str(), "rb");
if (file == NULL)
{
printf( "Could not read tileset.\n");
res->failed = true;
return -1;
}
long srcSize;
fseek( file, 0, SEEK_END);
srcSize = ftell( file);
fseek( file, 0, SEEK_SET);
unsigned char *srcData = new unsigned char[srcSize];
fread( srcData, 1, srcSize, file);

fclose( file);
long destSize = (srcData[0] << 24) | (srcData[1] << 16) | (srcData[2] << 8) | (srcData[3]);
unsigned char *dest = new unsigned char[destSize];
int uSize = Uncompress( srcData+4, srcSize-4, dest, destSize);//<---------------------- Called Here
if (uSize != destSize)
{
std::string errStr = "For " + res->Name + ", decompressed size of data not equal size written!\n";
printf( errStr.c_str());
res->failed = true;
delete[] srcData;
delete[] dest;
return -1;
}
res->srcId = audioEngine->create_sound_from_data( (char*)dest, destSize, res->Preload);
delete[] srcData;
delete[] dest;
return res->srcId;
}


Sometimes it breaks in a FMODEX call which I can't debug.

With App Verifier:

int DX9RenderEngine::create_sprite_from_data( const unsigned char* data, UINT size, int FrameCount, int FrameWidth, int FrameHeight, float CenterX, float CenterY, Color colkey, bool preload)
{
Sprite *spr = new Sprite;
spr->preload = preload;
D3DXIMAGE_INFO info;
D3DXGetImageInfoFromFileInMemory( data, size, &info); //<------- Breaks in this function
spr->fname = "";
spr->ImageWidth = info.Width;
spr->ImageHeight = info.Height;
spr->FrameCount = FrameCount;
spr->FrameWidth = FrameWidth == -1 ? info.Width : FrameWidth;
spr->FrameHeight = FrameHeight == -1 ? info.Height : FrameHeight;
spr->CenterX = CenterX;
spr->CenterY = CenterY;
spr->ColorKey = colkey;
spr->fromData = true;
spr->data = new unsigned char[size];
memcpy( spr->data, data, size);
spr->dataSize = size;
if (preload)
{
InitializeSprite( spr);
}
return append_sprite( spr);
}


if not there it eventually breaks on D3DXSprite::End();
Advertisement


long destSize = (srcData[0] << 24) | (srcData[1] << 16) | (srcData[2] << 8) | (srcData[3]);



Is your machine big-endian? Most machines are little-endian, meaning 0xDEADBEEF is stored as 0xEF 0xBE 0xAD 0xDE. It's quite possible that you have a destination size that is actually larger than what you are interpreting, therefore stomping a good chunk of memory. (For example, a the size of a 65536-byte file is written to the file as 0x00010000, but is interpreted as 0x00000100 when read with the code above.)

Possible solution:

long destSize = ((long*)srcData)[0];


It is also possible the seemingly unrelated errors stem from this problem as well.
For D3D9 endianness is highly unlikely to be a factor. My money's on an uninitialized pointer or bad pointer being passed to a function. Random breaks/etc would match that behaviour.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Run your program through a memory analysis tool. It'll tell you what you are doing wrong (most likely!). If you can compile on *nix, try valgrind. Otherwise, maybe Dr. Memory could help you (on Windows). I maintain a linux build just because of the great tooling support for C++ dev.

Run your program through a memory analysis tool. It'll tell you what you are doing wrong (most likely!). If you can compile on *nix, try valgrind. Otherwise, maybe Dr. Memory could help you (on Windows). I maintain a linux build just because of the great tooling support for C++ dev.

The program is clearly D3D9.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.


The program is clearly D3D9.


Quite obviously it is, indeed. Sorry bout that. Rest of the post should apply though.
I ran it through Dr. Memory and there were a lot of uninitialized reads. Could that be the problem? I attached the results.txt that it saved.[attachment=9520:results.txt]
I get problems like this a lot when I "delete" something that was never "new"ed, is this the kind of thing that a memory analyser would catch?
Uninitialized reads means that you read something without zeroing or assigning it - in other words, you are probably reading scrap memory. It is memory that is allocated (so no segfault or exception) but if you take actions based on that value, it could possibly do different things depending on mostly compiler versions. (if the compiler version changes the layout of the memory somehow you will read other scrap memory).

Unaddressable accesses are a big no-no. It means that you are reading or writing to invalid locations (which could kill your heap, or stack, for example). You've got

110 unique, 1294243 total unaddressable access(es).

The sad thing is that it's not trivially easy to know which errors are your own fault, and which errors are library errors that shouldn't be reported. But invalid accesses are invalid accesses, and shouldn't occur at all.

Invalid heap argument means that you are trying to delete an invalid area - either an invalid address, an already deleted pointer, or probably also (hupsilardee's question) non-dynamically allocated pointer deletion.

The Dr Memory output seems to suggest that your application is either explicitly trampling memory (i.e your fault) or implicitly (i.e a library that you have no control over)

Focus on unaddressable accesses and invalid heap arguments. Try running your program for a shorter time to get less non-unique output, or if Dr Memory supports it only report unique errors.

Cheers.
How do you call ResourceManager::ReadSound(Resource*) ?

I'm very curious why you printf("could not read tileset") inside a method that's called ReadSound...

This topic is closed to new replies.

Advertisement