Weird behaviour.... optimizer error?

Get answers to all your basic programming questions. No Ogre questions, please!
Post Reply
User avatar
mkultra333
Gold Sponsor
Gold Sponsor
Posts: 1894
Joined: Sun Mar 08, 2009 5:25 am
x 114

Weird behaviour.... optimizer error?

Post by mkultra333 »

One of my projects is an algorithmic dungeon constructor, using VC9. For one little routine I created a simple struct like this:

Code: Select all

#define MAXCONSTRUCT				16	// same as max for a P_COLLECTION, since constructions are built from collections
#define MAXCONSTRUCTLEVEL		16	// multiple levels in a construct, for instance stacked going from floor to roof.

typedef struct
{
	int MaxFurn[MAXCONSTRUCTLEVEL] ; // how many pieces of furniture in each level
	int FurnType[MAXCONSTRUCTLEVEL][MAXCONSTRUCT] ; // furniture type
	float PosX[MAXCONSTRUCTLEVEL][MAXCONSTRUCT] ;
	float PosY[MAXCONSTRUCTLEVEL][MAXCONSTRUCT] ;
	float PosZ[MAXCONSTRUCTLEVEL][MAXCONSTRUCT] ;
	
	int OriX[MAXCONSTRUCTLEVEL][MAXCONSTRUCT] ;
	int OriY[MAXCONSTRUCTLEVEL][MAXCONSTRUCT] ;
	int OriZ[MAXCONSTRUCTLEVEL][MAXCONSTRUCT] ;
	
}
CONSTRUCT ;
Its just a very simple struct to temporarily hold some data when I'm building some other things. But I started getting very odd results from it. There's a piece of code that does this:

Code: Select all

		nFurnCount=Construct.MaxFurn[nFloorLevel] ;
		Construct.FurnType[nFloorLevel][nFurnCount]=DEFAULTPREFABSCHEMATIC_FURNITURE+FURNTYPE_PIPETRI ;
		Construct.PosX[nFloorLevel][nFurnCount]=flBlockPosX*BLOCKSCALE -flPrefabMidX/UNIT ;
		Construct.PosY[nFloorLevel][nFurnCount]=flBlockPosY*BLOCKSCALE ;
		Construct.PosZ[nFloorLevel][nFurnCount]=flBlockPosZ*BLOCKSCALE -flPrefabMidZ/UNIT ;
		Construct.OriX[nFloorLevel][nFurnCount]=0 ;
		Construct.OriY[nFloorLevel][nFurnCount]=180 ;
		Construct.OriZ[nFloorLevel][nFurnCount]=0 ;
		Construct.MaxFurn[nFloorLevel]++ ;
This gets executed four times in a row with slightly different position and orientation data, and .MaxFurn gets incremented each time so the data goes to the next position in the array. Think of it as holding a bunch of positions and orientations for pieces of furniture on the floor.

Unfortunately the numbers coming out did not match the numbers going in, they were messed up. I coulnd't work out what the issue was, so I ran it in debug... and the problem vanished, the numbers came back out correct. So I ran it again in Release mode, but this time I printed out the values stored just before I did the final "Construct.MaxFurn[nFloorLevel]++ ;" for each piece. Again, the problem disappeard.

It was a Heisenbug... it only appeared when you weren't looking at it.

So I disabled code optimization. The bug disappeared again. This leads me to think the optimizer is getting confused somehow and messing it up. Why, I don't know. Turning optimization back on, I changed the code to the following:

Code: Select all

		nFurnCount=Construct.MaxFurn[nFloorLevel] ;
		Construct.FurnType[nFloorLevel][nFurnCount]=DEFAULTPREFABSCHEMATIC_FURNITURE+FURNTYPE_PIPETRI ;
		Construct.PosX[nFloorLevel][nFurnCount]=flBlockPosX*BLOCKSCALE -flPrefabMidX/UNIT ;
		Construct.PosY[nFloorLevel][nFurnCount]=flBlockPosY*BLOCKSCALE ;
		Construct.PosZ[nFloorLevel][nFurnCount]=flBlockPosZ*BLOCKSCALE -flPrefabMidZ/UNIT ;
		Construct.OriX[nFloorLevel][nFurnCount]=0 ;
		Construct.OriY[nFloorLevel][nFurnCount]=180 ;
		Construct.OriZ[nFloorLevel][nFurnCount]=0 ;

		nFurnCount++ ;
		Construct.MaxFurn[nFloorLevel]=nFurnCount ;
The only difference is the way I increment Construct.MaxFurn[nFloorLevel]. But now the code works again.

Tried another thing, went back to the old way of doing the increment, but declared Construct to be volatile, because I read this disables optimization for that variable. Sure enough, the bug vanished again.

Weird...

Of course, it could be I've got some bad pointer or something elsewhere in the code, and this is just the first time it has clashed with other code.
"In theory there is no difference between practice and theory. In practice, there is." - Psychology Textbook.
User avatar
tod
Troll
Posts: 1394
Joined: Wed Aug 02, 2006 9:41 am
Location: Bucharest
x 94
Contact:

Re: Weird behaviour.... optimizer error?

Post by tod »

I would guess you write more data than allocated in some buffer. Look at what you allocate just before those structures, and check what you put in it. You could also run some static code checker to see if there's anything wrong.
I won't bet on optimization error for this case.
User avatar
Ausir
Gnoblar
Posts: 4
Joined: Thu Feb 10, 2011 11:11 pm

Re: Weird behaviour.... optimizer error?

Post by Ausir »

Could it be that you don't initialize MaxFurn to contain only zeroes?
That struct is allocated as you would expect in debug builds, resulting in {0, 0, ..., 0}, but with in release it just gets a memory location with whatever data was already at that location. I guess that if you print the content of all those arrays as soon as you allocate the struct, you would find a lot of... undesired stuff.
By setting explicitly the MaxFurn you bypass that.
User avatar
syedhs
Silver Sponsor
Silver Sponsor
Posts: 2703
Joined: Mon Aug 29, 2005 3:24 pm
Location: Kuala Lumpur, Malaysia
x 51

Re: Weird behaviour.... optimizer error?

Post by syedhs »

tod wrote:I would guess you write more data than allocated in some buffer.
Yes that sounds like it.. I can't pinpoint which line is it as sometimes I myself stared at only a few lines of code, only to spot the error hours (or days) later.. What I mean by sounds like it is the code is quite similar to mine (many array variables) and suffers from weird problems too..
A willow deeply scarred, somebody's broken heart
And a washed-out dream
They follow the pattern of the wind, ya' see
Cause they got no place to be
That's why I'm starting with me
User avatar
mkultra333
Gold Sponsor
Gold Sponsor
Posts: 1894
Joined: Sun Mar 08, 2009 5:25 am
x 114

Re: Weird behaviour.... optimizer error?

Post by mkultra333 »

Removed this post. It was long and wrong, since I thought I'd found the problem. I hadn't.
Last edited by mkultra333 on Fri Jan 10, 2014 10:59 am, edited 1 time in total.
"In theory there is no difference between practice and theory. In practice, there is." - Psychology Textbook.
User avatar
mkultra333
Gold Sponsor
Gold Sponsor
Posts: 1894
Joined: Sun Mar 08, 2009 5:25 am
x 114

Re: Weird behaviour.... optimizer error?

Post by mkultra333 »

So I thought that using ZeroMemory on the struct, which is just Plain Old Data, would fix the problem. At first it appeared to work, but then the same bug appeared in a new location, basically the same operations. So I decided to strip things back and try and hunt this down.

I created a copy of the CONSTRUCT struct and a function to test it and log the results. I then call this function right on startup, after Ogre's log is initialized but before the rest of the Ogre initialization and before my own functions to anything, to try and reduce the risk of bad pointers or the like from the rest of the code. I could reproduce the error, so I set about cutting the struct and code down, looking at the changes that made the bug disappear.

I ended up getting it down to this:

Code: Select all

// This is a stripped down version of the original CONSTRUCT.  This seems to be the minimal representation
// that manifests the bug.
#define MAX_ELEMENT 				2
#define MAX_GROUP					2
struct SIMPLECONSTRUCT
{
	int MaxElement[MAX_GROUP] ;

	float ValueA[MAX_GROUP][MAX_ELEMENT] ;
	float ValueB[MAX_GROUP][MAX_ELEMENT] ;

	
};

// Here are some simple operations on a SIMPLECONSTRUCT.  
// We get an error in ValueB[1][1] under the below circumstance, but minor and seemingly irrelevant changes to
// the code make the bug disappear.

void CArchatron::SimpleConstructTest()
{

	Ogre::LogManager::getSingleton().logMessage("") ;
	Ogre::LogManager::getSingleton().logMessage("******* Start Construct Test ********") ;
	Ogre::LogManager::getSingleton().logMessage("") ;

	// This array is unused, except to be initialized with -1.
	// If it is removed, the bug disappears.  
	// If the array size is less than 11, the bug disappears.
	// If the array isn't initialized with any values, the bug disappears.

	int nUnusedArray[11] ;
	for(int nGroup=0 ; nGroup<11 ; nGroup++)
		nUnusedArray[nGroup]=-1 ;


		// for debug output.
		char chMessage[1024] ;

		// we'll only be writing to ValueA[GROUP][0], ValueA[GROUP][1], ValueB[GROUP][0], ValueB[GROUP][1]
		// and GROUP is a constant.
		const int GROUP=1 ;  

		int nFurnCount=0 ;
		SIMPLECONSTRUCT Construct ;

		// since CONSTRUCT is just POD, isn't it supposed to be ok to ZeroMemory it?
		// After this, every element in Construct should be zero
		ZeroMemory((void*)&Construct, sizeof(SIMPLECONSTRUCT)) ;


		// here we put values 1 and 2 into ValueA and ValueB.  
		// nFurnCount should be 0, since we zero-ed out Construct above.
		// Attempts to log nFurnCount confirm this... but also make the bug disappear.

		nFurnCount=Construct.MaxElement[GROUP] ;
		Construct.ValueA[GROUP][nFurnCount]=1 ;
		Construct.ValueB[GROUP][nFurnCount]=2 ;
		Construct.MaxElement[GROUP]++ ; // we increment the elements, so this should now be 1.

		// Log the values we just put in.  These come out correct.
		// But the bug will appear further down.
		// Note that if we remove this logging here, the bug disappears.

		sprintf(chMessage, "TEST 0: Values X %f, Y %f", Construct.ValueA[GROUP][0], Construct.ValueB[GROUP][0]) ;
		Ogre::LogManager::getSingleton().logMessage(chMessage) ;

		// here we put values 3 and 4 into ValueA and ValueB.  
		// nFurnCount should be 1, from the above increment.
		// Attempts to log nFurnCount confirm this... but also make the bug disappear.

		nFurnCount=Construct.MaxElement[GROUP] ;
		Construct.ValueA[GROUP][nFurnCount]=3 ;
		Construct.ValueB[GROUP][nFurnCount]=4 ; // <--- COMES OUT 0 INSTEAD OF 4
		Construct.MaxElement[GROUP]++ ;

		// Log the values we just put in... AND VALUEB[GROUP][1] COMES OUT WRONG!  
		// It comes out as 0 instead of 4 ;

		sprintf(chMessage, "TEST 1: Values X %f, Y %f", Construct.ValueA[GROUP][1], Construct.ValueB[GROUP][1]) ;
		Ogre::LogManager::getSingleton().logMessage(chMessage) ;


	Ogre::LogManager::getSingleton().logMessage("") ;
	Ogre::LogManager::getSingleton().logMessage("******* End Construct Test ********") ;
	Ogre::LogManager::getSingleton().logMessage("") ;
}
The above code is incredibly simple, I can't see where I've made any errors such as accessing beyond the ends of arrays. It works in debug mode, and as noted in the code, a number of very small changes make it work again. So it's a mystery to me.

The only thing I can think of now is that ZeroMemory is messing it up somehow. If I replace the ZeroMemory with the following alternative initialization, the bug disappears:

Code: Select all

		for(int nLoopA=0 ; nLoopA<MAX_GROUP ; nLoopA++)
		{
			Construct.MaxElement[nLoopA]=0 ;
			for(int nLoopB=0 ; nLoopB<MAX_ELEMENT ; nLoopB++)
			{
				Construct.ValueA[nLoopA][nLoopB]=0 ;
				Construct.ValueB[nLoopA][nLoopB]=0 ;
			}
		}
... but then so many things make the bug disappear, it's hard to be very confident. And if ZeroMemory is the problem, how come it disappears in debug mode, or if I try logging nFurnCount, or any of a myriad other things?

Again, I execute the above test code before almost any other code. I do it just after I create an Ogre log, and before I do any other ogre initialization or call any of my other code, so the chance that this is some bad code from elsewhere having an effect seems minimal.
"In theory there is no difference between practice and theory. In practice, there is." - Psychology Textbook.
User avatar
c6burns
Beholder
Posts: 1512
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 138

Re: Weird behaviour.... optimizer error?

Post by c6burns »

ZeroMemory is known to exhibit undesired effects under optimization. It's the first thing mentioned in MSDN:
http://msdn.microsoft.com/en-us/library ... 85%29.aspx
User avatar
mkultra333
Gold Sponsor
Gold Sponsor
Posts: 1894
Joined: Sun Mar 08, 2009 5:25 am
x 114

Re: Weird behaviour.... optimizer error?

Post by mkultra333 »

Interesting, I was unaware of that. I think I'll check for other places I may have used ZeroMemory and change them, just in case.
"In theory there is no difference between practice and theory. In practice, there is." - Psychology Textbook.
User avatar
c6burns
Beholder
Posts: 1512
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 138

Re: Weird behaviour.... optimizer error?

Post by c6burns »

Honestly ZeroMemory should just be an alias to SecureZeroMemory, but oh well. Personally I don't trust either of em :)
User avatar
mkultra333
Gold Sponsor
Gold Sponsor
Posts: 1894
Joined: Sun Mar 08, 2009 5:25 am
x 114

Re: Weird behaviour.... optimizer error?

Post by mkultra333 »

I gave SecureZeroMemory a go, and it worked fine. I tried some other variations, like manually overriting all the memory locations with a pointer and a loop, and they didn't work.

The optimizer is allowed to remove writes to memory that don't get read back, apparently. (Although how it arrives at that conclusion in my code, I can't understand.)
Since SecureZeroMemory isn't cross platform AFAIK, this seems to me like an area prone to problems. I don't know what the standard way of handling this is, and it seems like a difficult issue to catch. One site I looked at suggested always examining the assembly code to check it's correct, which seems just a bit unrealistic.

Perhaps using "volatile" is a better option.

Edit: I'm trying the following variant I wrote, seems to work so far.

Code: Select all

// alternate zero memory, because the compiler optimizer was messing things up.
void CArchatron::Safe_ZeroMemory(void* pMemStart, int nSize)
{
	volatile char *pMem=(char*)pMemStart ;
	for(int nPos=0 ; nPos<nSize ; nPos++)
	{
		*pMem=0 ;
		pMem++ ;
	}
}
"In theory there is no difference between practice and theory. In practice, there is." - Psychology Textbook.
User avatar
c6burns
Beholder
Posts: 1512
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 138

Re: Weird behaviour.... optimizer error?

Post by c6burns »

Ah ye olde thyme dead store removal :( I've seen this come up in "secure" applications that scrub data out of memory. They have to dereference the data after setting it with memset. I think what you've done there with volatile is fine, but it probably feels wrong to you.

I think examining the assembly is a very valid suggestion, but I'd make a macro or inline to do the memset+deref and examine that to make sure it's fine. Then you don't have to worry about it anymore. Although if it works and you aren't scrubbing stuff out of memory for security purposes I can see skipping the examination of compiler output.
User avatar
AlexeyKnyshev
Goblin
Posts: 213
Joined: Sat May 26, 2012 10:37 am
Location: Russia
x 13

Re: Weird behaviour.... optimizer error?

Post by AlexeyKnyshev »

I tried some other variations, like manually overriting all the memory locations with a pointer and a loop, and they didn't work.

The optimizer is allowed to remove writes to memory that don't get read back, apparently.
Quite strange, seems to be compiler's memory access analyzer bug.

Take a look a this. This is not quite related to subject, but you can find something interesting for u. There's a answer about inserting empty asm("") in code, which prevents compiler (gcc in this case) from optimizing out write instructions, without using (and getting overheard) from volatile qualifier. In this case compiler really have had a rights to strip w-access to memory.

Best regards, Alexey Knyshev
Voltage Engine - boost your ogre project with realtime physics and interactive scripting!
OgreBullet & CMake - easy to use bullet physics integration.
User avatar
mkultra333
Gold Sponsor
Gold Sponsor
Posts: 1894
Joined: Sun Mar 08, 2009 5:25 am
x 114

Re: Weird behaviour.... optimizer error?

Post by mkultra333 »

c6burns, examining assembly is a bit outside my area of expertise. :) I know this because I actually tried it when this first happened, I ran the debugger on the release version and had a look at the assembly for that section of code, but it was totally incomprehensible to me. Maybe with a bit of practice...

Alexey, thanks for the link.
"In theory there is no difference between practice and theory. In practice, there is." - Psychology Textbook.
User avatar
c6burns
Beholder
Posts: 1512
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 138

Re: Weird behaviour.... optimizer error?

Post by c6burns »

mkultra333 wrote:c6burns, examining assembly is a bit outside my area of expertise. :)
Well there's certainly no shame in that. I've never had to do so with a C++ program, and while I'm not a religious person I pray that I never have to. I'm a hopeless C coder who merely pretends to understand C++ :lol:
User avatar
mkultra333
Gold Sponsor
Gold Sponsor
Posts: 1894
Joined: Sun Mar 08, 2009 5:25 am
x 114

Re: Weird behaviour.... optimizer error?

Post by mkultra333 »

Just for the lulz, here's the dissassembly window from the buggy release version that uses ZeroMemory.

Code: Select all

// Here are some simple operations on a SIMPLECONSTRUCT.  
// We get an error in ValueB[1][1] under the below circumstance, but minor and seemingly irrelevant changes to
// the code make the bug disappear.

void OgreFramework::SimpleConstructTest()
{
01448CE0  push        0FFFFFFFFh 
01448CE2  push        offset __ehhandler$?SimpleConstructTest@OgreFramework@@QAEXXZ (148F580h) 
01448CE7  mov         eax,dword ptr fs:[00000000h] 
01448CED  push        eax  
01448CEE  sub         esp,464h 
01448CF4  mov         eax,dword ptr [___security_cookie (14B301Ch)] 
01448CF9  xor         eax,esp 
01448CFB  mov         dword ptr [esp+460h],eax 
01448D02  push        ebx  
01448D03  push        ebp  
01448D04  push        esi  
01448D05  push        edi  
01448D06  mov         eax,dword ptr [___security_cookie (14B301Ch)] 
01448D0B  xor         eax,esp 
01448D0D  push        eax  
01448D0E  lea         eax,[esp+478h] 
01448D15  mov         dword ptr fs:[00000000h],eax 

	Ogre::LogManager::getSingleton().logMessage("") ;
01448D1B  push        offset string "" (14A0246h) 
01448D20  lea         ecx,[esp+18h] 
01448D24  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (149206Ch)] 
01448D2A  push        0    
01448D2C  lea         eax,[esp+18h] 
01448D30  mov         dword ptr [esp+484h],0 
01448D3B  mov         esi,dword ptr [__imp_Ogre::LogManager::getSingleton (1492640h)] 
01448D41  push        2    
01448D43  push        eax  
01448D44  call        esi  
01448D46  mov         edi,dword ptr [__imp_Ogre::LogManager::logMessage (1492644h)] 
01448D4C  mov         ecx,eax 
01448D4E  call        edi  
01448D50  or          ebx,0FFFFFFFFh 
01448D53  lea         ecx,[esp+14h] 
01448D57  mov         dword ptr [esp+480h],ebx 
01448D5E  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (1492070h)] 
	Ogre::LogManager::getSingleton().logMessage("******* Start Construct Test ********") ;
01448D64  push        offset string "******* Start Construct Test ***"... (14A07D0h) 
01448D69  lea         ecx,[esp+18h] 
01448D6D  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (149206Ch)] 
01448D73  push        0    
01448D75  lea         ecx,[esp+18h] 
01448D79  push        2    
01448D7B  push        ecx  
01448D7C  mov         dword ptr [esp+48Ch],1 
01448D87  call        esi  
01448D89  mov         ecx,eax 
01448D8B  call        edi  
01448D8D  lea         ecx,[esp+14h] 
01448D91  mov         dword ptr [esp+480h],ebx 
01448D98  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (1492070h)] 
	Ogre::LogManager::getSingleton().logMessage("") ;
01448D9E  push        offset string "" (14A0246h) 
01448DA3  lea         ecx,[esp+18h] 
01448DA7  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (149206Ch)] 
01448DAD  push        0    
01448DAF  lea         edx,[esp+18h] 
01448DB3  push        2    
01448DB5  push        edx  
01448DB6  mov         dword ptr [esp+48Ch],2 
01448DC1  call        esi  
01448DC3  mov         ecx,eax 
01448DC5  call        edi  
01448DC7  lea         ecx,[esp+14h] 
01448DCB  mov         dword ptr [esp+480h],ebx 
01448DD2  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (1492070h)] 

	// This array is unused, except to be initialized with -1.
	// If it is removed, the bug disappears.  
	// If the array size is less than 11, the bug disappears.
	// If the array isn't initialized with any values, the bug disappears.

	int nUnusedArray[11] ;
	for(int nGroup=0 ; nGroup<11 ; nGroup++)
		nUnusedArray[nGroup]=-1 ;


		// for debug output.
		char chMessage[1024] ;

		// we'll only be writing to ValueA[GROUP][0], ValueA[GROUP][1], ValueA[GROUP][0], ValueA[GROUP][1]
		// and GROUP is a constant.
		const int GROUP=1 ;  

		int nFurnCount=0 ;
		SIMPLECONSTRUCT Construct ;

		// since CONSTRUCT is just POD, isn't is supposed to be ok to ZeroMemory it?
		// After this, every element in Construct should be zero
		ZeroMemory((void*)&Construct, sizeof(SIMPLECONSTRUCT)) ;
		

		// here we put values 1 and 2 into ValueA and ValueB.  
		// nFurnCount should be 0, since we zero-ed out Construct above.
		// Attempts to log nFurnCount confirm this... but also make the bug disappear.
		nFurnCount=Construct.MaxElement[GROUP] ;
		Construct.ValueA[GROUP][nFurnCount]=1 ;
01448DD8  fld1             
01448DDA  xor         eax,eax 
01448DDC  mov         dword ptr [esp+34h],eax 
01448DE0  mov         dword ptr [esp+40h],eax 
01448DE4  mov         dword ptr [esp+50h],eax 
01448DE8  mov         dword ptr [esp+30h],eax 
01448DEC  mov         dword ptr [esp+38h],eax 
01448DF0  mov         dword ptr [esp+3Ch],eax 
01448DF4  mov         dword ptr [esp+44h],eax 
01448DF8  mov         dword ptr [esp+48h],eax 
01448DFC  mov         dword ptr [esp+4Ch],eax 
01448E00  mov         dword ptr [esp+54h],eax 
01448E04  mov         eax,eax 
01448E06  add         eax,eax 
01448E08  fstp        dword ptr [esp+eax+40h] 
		Construct.ValueB[GROUP][nFurnCount]=2 ;
01448E0C  lea         ebp,[esp+eax+50h] 
01448E10  fld         dword ptr [__real@40000000 (14A809Ch)] 
		Construct.MaxElement[GROUP]++ ; // we increment the elements, so this should now be 1.

		// Log the values we just put in.  These come out correct.
		// But the bug will appear further down.
		// Note that if we remove this logging here, the bug disappears.
		sprintf(chMessage, "TEST 0: Values X %f, Y %f", Construct.ValueA[GROUP][0], Construct.ValueB[GROUP][0]) ;
01448E16  sub         esp,10h 
01448E19  fstp        dword ptr [ebp] 
01448E1C  inc         dword ptr [esp+44h] 
01448E20  fld         dword ptr [esp+60h] 
01448E24  lea         eax,[esp+84h] 
01448E2B  fstp        qword ptr [esp+8] 
01448E2F  fld         dword ptr [esp+50h] 
01448E33  fstp        qword ptr [esp] 
01448E36  push        offset string "TEST 0: Values X %f, Y %f" (14A07F8h) 
01448E3B  push        eax  
01448E3C  call        dword ptr [__imp__sprintf (1492120h)] 
01448E42  add         esp,18h 
		Ogre::LogManager::getSingleton().logMessage(chMessage) ;
01448E45  lea         ecx,[esp+74h] 
01448E49  push        ecx  
01448E4A  lea         ecx,[esp+18h] 
01448E4E  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (149206Ch)] 
01448E54  push        0    
01448E56  lea         edx,[esp+18h] 
01448E5A  push        2    
01448E5C  push        edx  
01448E5D  mov         dword ptr [esp+48Ch],3 
01448E68  call        esi  
01448E6A  mov         ecx,eax 
01448E6C  call        edi  
01448E6E  lea         ecx,[esp+14h] 
01448E72  mov         dword ptr [esp+480h],ebx 
01448E79  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (1492070h)] 

		// here we put values 3 and 4 into ValueA and ValueB.  
		// nFurnCount should be 1, from the above increment.
		// Attempts to log nFurnCount confirm this... but also make the bug disappear.
		nFurnCount=Construct.MaxElement[GROUP] ;
		Construct.ValueA[GROUP][nFurnCount]=3 ;
01448E7F  fld         dword ptr [__real@40400000 (14A8098h)] 
01448E85  mov         eax,dword ptr [esp+34h] 
01448E89  fstp        dword ptr [esp+eax*4+40h] 
		Construct.ValueB[GROUP][nFurnCount]=4 ; // <--- COMES OUT 0 INSTEAD OF 4
		Construct.MaxElement[GROUP]++ ;

		// Log the values we just put in... AND VALUEB[GROUP][1] COMES OUT WRONG!  
		// It comes out as 0 instead of 4 ;
		sprintf(chMessage, "TEST 1: Values X %f, Y %f", Construct.ValueA[GROUP][1], Construct.ValueB[GROUP][1]) ;
01448E8D  sub         esp,10h 
01448E90  fld         dword ptr [__real@40800000 (14A8090h)] 
01448E96  lea         ecx,[esp+84h] 
01448E9D  fstp        dword ptr [ebp] 
01448EA0  fld         dword ptr [esp+64h] 
01448EA4  fstp        qword ptr [esp+8] 
01448EA8  fld         dword ptr [esp+54h] 
01448EAC  fstp        qword ptr [esp] 
01448EAF  push        offset string "TEST 1: Values X %f, Y %f" (14A0814h) 
01448EB4  push        ecx  
01448EB5  call        dword ptr [__imp__sprintf (1492120h)] 
01448EBB  add         esp,18h 
		Ogre::LogManager::getSingleton().logMessage(chMessage) ;
01448EBE  lea         edx,[esp+74h] 
01448EC2  push        edx  
01448EC3  lea         ecx,[esp+18h] 
01448EC7  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (149206Ch)] 
01448ECD  push        0    
01448ECF  lea         eax,[esp+18h] 
01448ED3  push        2    
01448ED5  push        eax  
01448ED6  mov         dword ptr [esp+48Ch],4 
01448EE1  call        esi  
01448EE3  mov         ecx,eax 
01448EE5  call        edi  
01448EE7  lea         ecx,[esp+14h] 
01448EEB  mov         dword ptr [esp+480h],ebx 
01448EF2  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (1492070h)] 


	Ogre::LogManager::getSingleton().logMessage("") ;
01448EF8  push        offset string "" (14A0246h) 
01448EFD  lea         ecx,[esp+18h] 
01448F01  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (149206Ch)] 
01448F07  push        0    
01448F09  lea         ecx,[esp+18h] 
01448F0D  push        2    
01448F0F  push        ecx  
01448F10  mov         dword ptr [esp+48Ch],5 
01448F1B  call        esi  
01448F1D  mov         ecx,eax 
01448F1F  call        edi  
01448F21  lea         ecx,[esp+14h] 
01448F25  mov         dword ptr [esp+480h],ebx 
01448F2C  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (1492070h)] 
	Ogre::LogManager::getSingleton().logMessage("******* End Construct Test ********") ;
01448F32  push        offset string "******* End Construct Test *****"... (14A0830h) 
01448F37  lea         ecx,[esp+18h] 
01448F3B  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (149206Ch)] 
01448F41  push        0    
01448F43  lea         edx,[esp+18h] 
01448F47  push        2    
01448F49  push        edx  
01448F4A  mov         dword ptr [esp+48Ch],6 
01448F55  call        esi  
01448F57  mov         ecx,eax 
01448F59  call        edi  
01448F5B  lea         ecx,[esp+14h] 
01448F5F  mov         dword ptr [esp+480h],ebx 
01448F66  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (1492070h)] 
	Ogre::LogManager::getSingleton().logMessage("") ;
01448F6C  push        offset string "" (14A0246h) 
01448F71  lea         ecx,[esp+5Ch] 
01448F75  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (149206Ch)] 
01448F7B  push        0    
01448F7D  mov         dword ptr [esp+484h],7 
01448F88  push        2    
01448F8A  lea         eax,[esp+60h] 
01448F8E  push        eax  
01448F8F  call        esi  
01448F91  mov         ecx,eax 
01448F93  call        edi  
01448F95  lea         ecx,[esp+58h] 
01448F99  mov         dword ptr [esp+480h],ebx 
01448FA0  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (1492070h)] 
}
01448FA6  mov         ecx,dword ptr [esp+478h] 
01448FAD  mov         dword ptr fs:[0],ecx 
01448FB4  pop         ecx  
01448FB5  pop         edi  
01448FB6  pop         esi  
01448FB7  pop         ebp  
01448FB8  pop         ebx  
01448FB9  mov         ecx,dword ptr [esp+460h] 
01448FC0  xor         ecx,esp 
01448FC2  call        __security_check_cookie (148E739h) 
01448FC7  add         esp,470h 
01448FCD  ret              
--- No source file -------------------------------------------------------------
01448FCE  int         3    
01448FCF  int         3    
--- c:\ogre\archatron\archatron140112a\mapconstructor\ogreframework.cpp --------
Buggy Log Output:

Code: Select all

11:19:20: ******* Start Construct Test ********
11:19:20: 
11:19:20: TEST 0: Values X 1.000000, Y 2.000000
11:19:20: TEST 1: Values X 3.000000, Y 0.000000
11:19:20: 
11:19:20: ******* End Construct Test ********
And for the correctly functioning, Safe_ZeroMemory version,

Code: Select all

// Here are some simple operations on a SIMPLECONSTRUCT.  
// We get an error in ValueB[1][1] under the below circumstance, but minor and seemingly irrelevant changes to
// the code make the bug disappear.

void OgreFramework::SimpleConstructTest()
{
01068E70  push        0FFFFFFFFh 
01068E72  push        offset __ehhandler$?SimpleConstructTest@OgreFramework@@QAEXXZ (10AFA80h) 
01068E77  mov         eax,dword ptr fs:[00000000h] 
01068E7D  push        eax  
01068E7E  sub         esp,53Ch 
01068E84  mov         eax,dword ptr [___security_cookie (10D301Ch)] 
01068E89  xor         eax,esp 
01068E8B  mov         dword ptr [esp+538h],eax 
01068E92  push        ebx  
01068E93  push        ebp  
01068E94  push        esi  
01068E95  push        edi  
01068E96  mov         eax,dword ptr [___security_cookie (10D301Ch)] 
01068E9B  xor         eax,esp 
01068E9D  push        eax  
01068E9E  lea         eax,[esp+550h] 
01068EA5  mov         dword ptr fs:[00000000h],eax 

	Ogre::LogManager::getSingleton().logMessage("") ;
01068EAB  push        offset string "" (10C0246h) 
01068EB0  lea         ecx,[esp+134h] 
01068EB7  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (10B206Ch)] 
01068EBD  push        0    
01068EBF  lea         eax,[esp+134h] 
01068EC6  mov         dword ptr [esp+55Ch],0 
01068ED1  mov         esi,dword ptr [__imp_Ogre::LogManager::getSingleton (10B2640h)] 
01068ED7  push        2    
01068ED9  push        eax  
01068EDA  call        esi  
01068EDC  mov         edi,dword ptr [__imp_Ogre::LogManager::logMessage (10B2644h)] 
01068EE2  mov         ecx,eax 
01068EE4  call        edi  
01068EE6  or          ebx,0FFFFFFFFh 
01068EE9  lea         ecx,[esp+130h] 
01068EF0  mov         dword ptr [esp+558h],ebx 
01068EF7  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (10B2070h)] 
	Ogre::LogManager::getSingleton().logMessage("******* Start Construct Test ********") ;
01068EFD  push        offset string "******* Start Construct Test ***"... (10C07D0h) 
01068F02  lea         ecx,[esp+0E0h] 
01068F09  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (10B206Ch)] 
01068F0F  push        0    
01068F11  lea         ecx,[esp+0E0h] 
01068F18  push        2    
01068F1A  push        ecx  
01068F1B  mov         dword ptr [esp+564h],1 
01068F26  call        esi  
01068F28  mov         ecx,eax 
01068F2A  call        edi  
01068F2C  lea         ecx,[esp+0DCh] 
01068F33  mov         dword ptr [esp+558h],ebx 
01068F3A  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (10B2070h)] 
	Ogre::LogManager::getSingleton().logMessage("") ;
01068F40  push        offset string "" (10C0246h) 
01068F45  lea         ecx,[esp+118h] 
01068F4C  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (10B206Ch)] 
01068F52  push        0    
01068F54  lea         edx,[esp+118h] 
01068F5B  push        2    
01068F5D  push        edx  
01068F5E  mov         dword ptr [esp+564h],2 
01068F69  call        esi  
01068F6B  mov         ecx,eax 
01068F6D  call        edi  
01068F6F  lea         ecx,[esp+114h] 
01068F76  mov         dword ptr [esp+558h],ebx 
01068F7D  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (10B2070h)] 

	// This array is unused, except to be initialized with -1.
	// If it is removed, the bug disappears.  
	// If the array size is less than 11, the bug disappears.
	// If the array isn't initialized with any values, the bug disappears.

	int nUnusedArray[11] ;
	for(int nGroup=0 ; nGroup<11 ; nGroup++)
		nUnusedArray[nGroup]=-1 ;
01068F83  mov         eax,ebx 
01068F85  mov         dword ptr [esp+40h],eax 
01068F89  mov         dword ptr [esp+44h],eax 
01068F8D  mov         dword ptr [esp+48h],eax 
01068F91  mov         dword ptr [esp+4Ch],eax 
01068F95  mov         dword ptr [esp+50h],eax 
01068F99  mov         dword ptr [esp+54h],eax 
01068F9D  mov         dword ptr [esp+58h],eax 
01068FA1  mov         dword ptr [esp+5Ch],eax 
01068FA5  mov         dword ptr [esp+60h],eax 
01068FA9  mov         dword ptr [esp+64h],eax 
01068FAD  mov         dword ptr [esp+68h],eax 


		// for debug output.
		char chMessage[1024] ;

		// we'll only be writing to ValueA[GROUP][0], ValueA[GROUP][1], ValueA[GROUP][0], ValueA[GROUP][1]
		// and GROUP is a constant.
		const int GROUP=1 ;  

		int nFurnCount=0 ;
		SIMPLECONSTRUCT Construct ;

		// since CONSTRUCT is just POD, isn't is supposed to be ok to ZeroMemory it?
		// After this, every element in Construct should be zero
		Safe_ZeroMemory((void*)&Construct, sizeof(SIMPLECONSTRUCT)) ;
01068FB1  lea         eax,[esp+18h] 
01068FB5  mov         ecx,28h 
01068FBA  lea         ebx,[ebx] 
01068FC0  mov         byte ptr [eax],0 
01068FC3  inc         eax  
01068FC4  sub         ecx,1 
01068FC7  jne         OgreFramework::SimpleConstructTest+150h (1068FC0h) 
		

		// here we put values 1 and 2 into ValueA and ValueB.  
		// nFurnCount should be 0, since we zero-ed out Construct above.
		// Attempts to log nFurnCount confirm this... but also make the bug disappear.
		nFurnCount=Construct.MaxElement[GROUP] ;
		Construct.ValueA[GROUP][nFurnCount]=1 ;
01068FC9  mov         eax,dword ptr [esp+1Ch] 
01068FCD  fld1             
01068FCF  add         eax,eax 
01068FD1  add         eax,eax 
01068FD3  fstp        dword ptr [esp+eax+28h] 
		Construct.ValueB[GROUP][nFurnCount]=2 ;
		Construct.MaxElement[GROUP]++ ; // we increment the elements, so this should now be 1.

		// Log the values we just put in.  These come out correct.
		// But the bug will appear further down.
		// Note that if we remove this logging here, the bug disappears.
		sprintf(chMessage, "TEST 0: Values X %f, Y %f", Construct.ValueA[GROUP][0], Construct.ValueB[GROUP][0]) ;
01068FD7  sub         esp,10h 
01068FDA  fld         dword ptr [__real@40000000 (10C8400h)] 
01068FE0  fstp        dword ptr [esp+eax+48h] 
01068FE4  mov         ebp,dword ptr [esp+2Ch] 
01068FE8  fld         dword ptr [esp+48h] 
01068FEC  lea         eax,[esp+15Ch] 
01068FF3  fstp        qword ptr [esp+8] 
01068FF7  inc         ebp  
01068FF8  fld         dword ptr [esp+38h] 
01068FFC  fstp        qword ptr [esp] 
01068FFF  push        offset string "TEST 0: Values X %f, Y %f" (10C07F8h) 
01069004  push        eax  
01069005  call        dword ptr [__imp__sprintf (10B2120h)] 
0106900B  add         esp,18h 
		Ogre::LogManager::getSingleton().logMessage(chMessage) ;
0106900E  lea         ecx,[esp+14Ch] 
01069015  push        ecx  
01069016  lea         ecx,[esp+0FCh] 
0106901D  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (10B206Ch)] 
01069023  push        0    
01069025  lea         edx,[esp+0FCh] 
0106902C  push        2    
0106902E  push        edx  
0106902F  mov         dword ptr [esp+564h],3 
0106903A  call        esi  
0106903C  mov         ecx,eax 
0106903E  call        edi  
01069040  lea         ecx,[esp+0F8h] 
01069047  mov         dword ptr [esp+558h],ebx 
0106904E  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (10B2070h)] 

		// here we put values 3 and 4 into ValueA and ValueB.  
		// nFurnCount should be 1, from the above increment.
		// Attempts to log nFurnCount confirm this... but also make the bug disappear.
		nFurnCount=Construct.MaxElement[GROUP] ;
		Construct.ValueA[GROUP][nFurnCount]=3 ;
01069054  fld         dword ptr [__real@40400000 (10C83FCh)] 
0106905A  lea         eax,[ebp*4] 
01069061  fstp        dword ptr [esp+eax+28h] 
		Construct.ValueB[GROUP][nFurnCount]=4 ; // <--- COMES OUT 0 INSTEAD OF 4
		Construct.MaxElement[GROUP]++ ;

		// Log the values we just put in... AND VALUEB[GROUP][1] COMES OUT WRONG!  
		// It comes out as 0 instead of 4 ;
		sprintf(chMessage, "TEST 1: Values X %f, Y %f", Construct.ValueA[GROUP][1], Construct.ValueB[GROUP][1]) ;
01069065  sub         esp,10h 
01069068  fld         dword ptr [__real@40800000 (10C8090h)] 
0106906E  fstp        dword ptr [esp+eax+48h] 
01069072  lea         eax,[esp+15Ch] 
01069079  fld         dword ptr [esp+4Ch] 
0106907D  fstp        qword ptr [esp+8] 
01069081  fld         dword ptr [esp+3Ch] 
01069085  fstp        qword ptr [esp] 
01069088  push        offset string "TEST 1: Values X %f, Y %f" (10C0814h) 
0106908D  push        eax  
0106908E  call        dword ptr [__imp__sprintf (10B2120h)] 
01069094  add         esp,18h 
		Ogre::LogManager::getSingleton().logMessage(chMessage) ;
01069097  lea         ecx,[esp+14Ch] 
0106909E  push        ecx  
0106909F  lea         ecx,[esp+0C4h] 
010690A6  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (10B206Ch)] 
010690AC  push        0    
010690AE  lea         edx,[esp+0C4h] 
010690B5  push        2    
010690B7  push        edx  
010690B8  mov         dword ptr [esp+564h],4 
010690C3  call        esi  
010690C5  mov         ecx,eax 
010690C7  call        edi  
010690C9  lea         ecx,[esp+0C0h] 
010690D0  mov         dword ptr [esp+558h],ebx 
010690D7  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (10B2070h)] 


	Ogre::LogManager::getSingleton().logMessage("") ;
010690DD  push        offset string "" (10C0246h) 
010690E2  lea         ecx,[esp+70h] 
010690E6  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (10B206Ch)] 
010690EC  push        0    
010690EE  lea         eax,[esp+70h] 
010690F2  push        2    
010690F4  push        eax  
010690F5  mov         dword ptr [esp+564h],5 
01069100  call        esi  
01069102  mov         ecx,eax 
01069104  call        edi  
01069106  lea         ecx,[esp+6Ch] 
0106910A  mov         dword ptr [esp+558h],ebx 
01069111  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (10B2070h)] 
	Ogre::LogManager::getSingleton().logMessage("******* End Construct Test ********") ;
01069117  push        offset string "******* End Construct Test *****"... (10C0830h) 
0106911C  lea         ecx,[esp+8Ch] 
01069123  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (10B206Ch)] 
01069129  push        0    
0106912B  lea         ecx,[esp+8Ch] 
01069132  push        2    
01069134  push        ecx  
01069135  mov         dword ptr [esp+564h],6 
01069140  call        esi  
01069142  mov         ecx,eax 
01069144  call        edi  
01069146  lea         ecx,[esp+88h] 
0106914D  mov         dword ptr [esp+558h],ebx 
01069154  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (10B2070h)] 
	Ogre::LogManager::getSingleton().logMessage("") ;
0106915A  push        offset string "" (10C0246h) 
0106915F  lea         ecx,[esp+0A8h] 
01069166  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (10B206Ch)] 
0106916C  push        0    
0106916E  lea         edx,[esp+0A8h] 
01069175  push        2    
01069177  push        edx  
01069178  mov         dword ptr [esp+564h],7 
01069183  call        esi  
01069185  mov         ecx,eax 
01069187  call        edi  
01069189  lea         ecx,[esp+0A4h] 
01069190  mov         dword ptr [esp+558h],ebx 
01069197  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (10B2070h)] 
}
0106919D  mov         ecx,dword ptr [esp+550h] 
010691A4  mov         dword ptr fs:[0],ecx 
010691AB  pop         ecx  
010691AC  pop         edi  
010691AD  pop         esi  
010691AE  pop         ebp  
010691AF  pop         ebx  
010691B0  mov         ecx,dword ptr [esp+538h] 
010691B7  xor         ecx,esp 
010691B9  call        __security_check_cookie (10AE759h) 
010691BE  add         esp,548h 
010691C4  ret              
--- No source file -------------------------------------------------------------
010691C5  int         3    
010691C6  int         3    
010691C7  int         3    
010691C8  int         3    
010691C9  int         3    
010691CA  int         3    
010691CB  int         3    
010691CC  int         3    
010691CD  int         3    
010691CE  int         3    
010691CF  int         3    
--- c:\ogre\archatron\archatron140112a\mapconstructor\ogreframework.cpp --------
Correct Log Output:

Code: Select all

11:24:04: ******* Start Construct Test ********
11:24:04: 
11:24:04: TEST 0: Values X 1.000000, Y 2.000000
11:24:04: TEST 1: Values X 3.000000, Y 4.000000
11:24:04: 
11:24:04: ******* End Construct Test ********
Hehe, so, any assembly code gurus out there who can spot the issue? It's not important, I just curious to see if anyone understands the above and can see why the optimized version is bugged out.
"In theory there is no difference between practice and theory. In practice, there is." - Psychology Textbook.
User avatar
c6burns
Beholder
Posts: 1512
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 138

Re: Weird behaviour.... optimizer error?

Post by c6burns »

I'll give you my 2 cents, but I'm no guru. Anyone else feel free to step in with more detail or to correct me :)

In the first program, ZeroMemory appears to be optimized out. In the second, SecureZeroMemory generates the following which I commented

Code: Select all

    01068FB1  lea         eax,[esp+18h] ; load the address of &Construct into eax
    01068FB5  mov         ecx,28h ; move 28h (40) into ecx ... this is the sizeof(SIMPLECONSTRUCT) ... so it's 40 bytes long
    01068FBA  lea         ebx,[ebx] ; lol?
    01068FC0  mov         byte ptr [eax],0 ; using eax as a pointer, move a 0 there (this is the start of the loop)
    01068FC3  inc         eax ; increment eax so we point at the next byte, and are prepared for the next iteration of the loop
    01068FC4  sub         ecx,1 ; subtract 1 from ecx, bringing us 1 iteration closer to completing the loop
    01068FC7  jne         OgreFramework::SimpleConstructTest+150h (1068FC0h) ; jump to 1068FC0 if ecx is not equal to 0
Also this problem got me curious about the older solutions I had seen, so I tested and found that my solution I originally proposed (to dereference after memset) is actually no longer valid in gcc (and probably other compilers) :shock: It's too smart for this now apparently:

Code: Select all

memset(mythingy, 0, sizeof(mythingy));
*(volatile char*)mythingy = *(volatile char*)mythingy;
Post Reply