Jump to content

  • Log In with Google      Sign In   
  • Create Account

14 years ago on June 15th Gamedev.net was first launched! We want to thank all of you for being part of our community and hope the best years are ahead of us. Happy birthday Gamedev.net!

Heap Corruption!


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
12 replies to this topic

#1 justin12343   Members   -  Reputation: 169

Like
0Likes
Like

Posted 17 June 2012 - 10:36 PM

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();

Edited by justin12343, 17 June 2012 - 10:38 PM.


Sponsor:

#2 fastcall22   Members   -  Reputation: 1907

Like
0Likes
Like

Posted 18 June 2012 - 12:00 AM

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.

Edited by fastcall22, 18 June 2012 - 12:12 AM.


#3 mhagain   Members   -  Reputation: 4028

Like
0Likes
Like

Posted 18 June 2012 - 04:11 AM

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.

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#4 CyberRascal   Members   -  Reputation: 194

Like
0Likes
Like

Posted 18 June 2012 - 05:32 AM

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.

#5 mhagain   Members   -  Reputation: 4028

Like
0Likes
Like

Posted 18 June 2012 - 05:47 AM

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.

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#6 CyberRascal   Members   -  Reputation: 194

Like
0Likes
Like

Posted 18 June 2012 - 06:01 AM

The program is clearly D3D9.


Quite obviously it is, indeed. Sorry bout that. Rest of the post should apply though.

#7 justin12343   Members   -  Reputation: 169

Like
0Likes
Like

Posted 18 June 2012 - 08:06 AM

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.Attached File  results.txt   8.5MB   25 downloads

#8 hupsilardee   Members   -  Reputation: 449

Like
0Likes
Like

Posted 18 June 2012 - 08:06 AM

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?

#9 CyberRascal   Members   -  Reputation: 194

Like
0Likes
Like

Posted 18 June 2012 - 10:25 AM

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.

Edited by CyberRascal, 18 June 2012 - 10:27 AM.


#10 alnite   Members   -  Reputation: 1528

Like
0Likes
Like

Posted 19 June 2012 - 12:59 PM

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...

#11 justin12343   Members   -  Reputation: 169

Like
0Likes
Like

Posted 19 June 2012 - 07:11 PM

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...

That was a simple copy/paste error. ReadTileset looks almost the same as ReadSound so I just copied and pasted and changed the way the data was used.

I think I'm getting closer to the problem. I noticed that new Sprite was being called twice in the create_sprite_from_data function though a call to new is only there once, But in the disassembly its clearly there twice. The first time it is called every thing seems fine except it doesn't go through the rest of the function. The second time, the whole renderer class goes invalid before and then new is called. I'll post the disassembly so you guys can see.

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)
{
013FF680  push		ebp
013FF681  mov		 ebp,esp
013FF683  sub		 esp,28h
013FF686  mov		 eax,dword ptr [___security_cookie (16774E8h)]
013FF68B  xor		 eax,ebp
013FF68D  mov		 dword ptr [ebp-4],eax
013FF690  mov		 eax,dword ptr [ebp+8]
013FF693  push		ebx
013FF694  push		esi
013FF695  push		edi
013FF696  mov		 edi,dword ptr [ebp+0Ch]
Sprite *spr = new Sprite;
013FF699  push		60h
013FF69B  mov		 dword ptr [ebp-24h],ecx
spr->FrameHeight = FrameHeight == -1 ? info.Height : FrameHeight;
013FF69E  mov		 dword ptr [ebp-28h],eax
013FF6A1  call		operator new (15686AEh)
013FF6A6  xor		 ebx,ebx
013FF6A8  add		 esp,4
013FF6AB  cmp		 eax,ebx
013FF6AD  je		  DX9RenderEngine::create_sprite_from_data+78h (13FF6F8h)
Sprite *spr = new Sprite;
013FF6AF  fldz
013FF6B1  mov		 dword ptr [eax],offset Sprite::`vftable' (15F73D4h)
013FF6B7  mov		 dword ptr [eax+18h],0Fh
013FF6BE  mov		 dword ptr [eax+14h],ebx
013FF6C1  mov		 byte ptr [eax+4],bl
013FF6C4  fst		 dword ptr [eax+40h]
013FF6C7  fstp		dword ptr [eax+44h]
013FF6CA  mov		 byte ptr [eax+20h],bl
013FF6CD  mov		 dword ptr [eax+24h],ebx
013FF6D0  mov		 dword ptr [eax+28h],ebx
013FF6D3  mov		 dword ptr [eax+2Ch],ebx
013FF6D6  mov		 dword ptr [eax+30h],ebx
013FF6D9  mov		 dword ptr [eax+34h],ebx
013FF6DC  mov		 dword ptr [eax+38h],ebx
013FF6DF  mov		 dword ptr [eax+3Ch],ebx
013FF6E2  mov		 dword ptr [eax+48h],ebx
013FF6E5  mov		 byte ptr [eax+4Ch],bl
013FF6E8  mov		 dword ptr [eax+50h],ebx
013FF6EB  mov		 dword ptr [eax+54h],ebx
013FF6EE  mov		 dword ptr [eax+58h],ebx
013FF6F1  mov		 byte ptr [eax+4Dh],bl
013FF6F4  mov		 esi,eax
013FF6F6  jmp		 DX9RenderEngine::create_sprite_from_data+7Ah (13FF6FAh)
013FF6F8  xor		 esi,esi
D3DXIMAGE_INFO info;
D3DXGetImageInfoFromFileInMemory( data, size, &info);
013FF6FA  mov		 edx,dword ptr [ebp-28h]
013FF6FD  lea		 ecx,[ebp-20h]
013FF700  push		ecx
013FF701  push		edi
013FF702  push		edx
013FF703  call		D3DXGetImageInfoFromFileInMemory (15566A4h)
spr->fname = "";
013FF708  push		ebx
013FF709  push		offset string "" (1631574h)
013FF70E  lea		 ecx,[esi+4]
013FF711  call		std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign (13C0210h)
spr->ImageWidth = info.Width;
013FF716  mov		 eax,dword ptr [ebp-20h]
spr->ImageHeight = info.Height;
spr->FrameCount = FrameCount;
013FF719  mov		 edx,dword ptr [ebp+10h]
013FF71C  mov		 dword ptr [esi+2Ch],eax
013FF71F  mov		 ecx,dword ptr [ebp-1Ch]
spr->FrameWidth = FrameWidth == -1 ? info.Width : FrameWidth;
013FF722  mov		 eax,dword ptr [ebp+14h]
013FF725  mov		 dword ptr [esi+30h],ecx
013FF728  mov		 dword ptr [esi+34h],edx
013FF72B  cmp		 eax,0FFFFFFFFh
013FF72E  jne		 DX9RenderEngine::create_sprite_from_data+0B3h (13FF733h)
013FF730  mov		 eax,dword ptr [ebp-20h]
013FF733  mov		 dword ptr [esi+38h],eax
spr->FrameHeight = FrameHeight == -1 ? info.Height : FrameHeight;
013FF736  mov		 eax,dword ptr [ebp+18h]
013FF739  cmp		 eax,0FFFFFFFFh
013FF73C  jne		 DX9RenderEngine::create_sprite_from_data+0C1h (13FF741h)
013FF73E  mov		 eax,dword ptr [ebp-1Ch]
spr->CenterX = CenterX;
013FF741  fld		 dword ptr [ebp+1Ch]
spr->CenterY = CenterY;
spr->ColorKey = colkey;
spr->preload = preload;
013FF744  mov		 cl,byte ptr [ebp+28h]
013FF747  fstp		dword ptr [esi+40h]
013FF74A  mov		 dword ptr [esi+3Ch],eax
013FF74D  mov		 eax,dword ptr [ebp+24h]
013FF750  fld		 dword ptr [ebp+20h]
spr->fromData = true;
spr->data = new unsigned char[size];
013FF753  push		edi
013FF754  fstp		dword ptr [esi+44h]
013FF757  mov		 dword ptr [esi+48h],eax
013FF75A  mov		 byte ptr [esi+4Ch],cl
013FF75D  mov		 byte ptr [esi+20h],1
013FF761  call		operator new[] (1568308h)
memcpy( spr->data, data, size);
013FF766  mov		 edx,dword ptr [ebp-28h]
013FF769  push		edi
013FF76A  push		edx
013FF76B  push		eax
013FF76C  mov		 dword ptr [esi+28h],eax
013FF76F  call		memcpy (1568696h)
013FF774  add		 esp,10h
spr->dataSize = size;
013FF777  mov		 dword ptr [esi+24h],edi
if (preload)
{
  InitializeSprite( spr);
013FF77A  mov		 edi,dword ptr [ebp-24h]
013FF77D  cmp		 byte ptr [ebp+28h],bl
013FF780  je		  DX9RenderEngine::create_sprite_from_data+10Fh (13FF78Fh)
013FF782  mov		 eax,dword ptr [edi]
013FF784  mov		 edx,dword ptr [eax+88h]
013FF78A  push		esi
013FF78B  mov		 ecx,edi
013FF78D  call		edx
}
return append_sprite( spr);
013FF78F  push		esi
013FF790  mov		 ecx,edi
013FF792  call		Renderer::append_sprite (142DF30h)
}


#12 alnite   Members   -  Reputation: 1528

Like
0Likes
Like

Posted 20 June 2012 - 02:23 PM

That was a simple copy/paste error. ReadTileset looks almost the same as ReadSound so I just copied and pasted and changed the way the data was used.

Ok, but how and where do you call that method? I have a suspicion that's where the problem is.

#13 justin12343   Members   -  Reputation: 169

Like
0Likes
Like

Posted 20 June 2012 - 04:41 PM


That was a simple copy/paste error. ReadTileset looks almost the same as ReadSound so I just copied and pasted and changed the way the data was used.

Ok, but how and where do you call that method? I have a suspicion that's where the problem is.


int ResourceManager::ReadTileset( Resource *resource)
{
ResourceTileset *res = reinterpret_cast<ResourceTileset*>( resource);
FILE *file = NULL;
std::string fname = WorkingDir + res->Filename;
file = fopen( fname.c_str(), "rb");
if (file == NULL)
{
  printf( "Could not read tileset.\n");
  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);
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;
}
int index = renderEngine->create_tileset_from_data( dest, destSize, res->TileWidth, res->TileHeight, res->XOffset, res->YOffset, res->XSpacing, res->YSpacing);

delete[] srcData;
delete[] dest;
if (index == -1)
{
  printf( "Error loading tileset.\n");
  res->failed = true;
  return -1;
}
res->srcId = index;
res->loaded = true;
return index;
}





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS