Weird memory errors with boost::shared_ptr

Started by
5 comments, last by Katie 13 years, 9 months ago
I'm writing a single-threaded, single-player game with Visual C++, Allegro and Boost. Some time ago I started to get some really weird access violations. I've tried to track back the changes I have made but I have found nothing which could cause them. For example, although I have not changed executable lines 1 to n-1 at all, I now get an error on line n (I did, however, change some of the #includes and the other files).

I always encapsulate memory allocations inside shared_ptr's, like this:
boost::shared_ptr<Sprite> sprite = boost::shared_ptr<Sprite>( new Sprite(32, 32) );


This is where one of the errors occurs. The Sprite constructor finishes, but the shared_ptr constructor gives an error: "0xC0000005: Access violation writing location 0xcdcdcdd1." Before now, everything worked perfectly, and I did not change any line which is executed before this one.

The other errors I'm getting are weirder. For example (the following code also worked perfectly before I started getting the memory errors):
bool Spell::isOnTarget(){  // targetCharacter is of type boost::shared_ptr<Character>  // x, y and targetCharacter are member variables of Spell  if(( x == targetCharacter->x ) && (y == targetCharacter->y ))    return true;  else    return false;}


This never returns true, even when the coordinates are equal; I've tested situations when the spell should definitely be on target. When debugging with VC++, I can even check from the local variables window that x and targetCharacter->x, etc. are equal, yet, the condition still evaluates to true. If I change the code to this:

bool Spell::isOnTarget(){  int tempX = targetCharacter->x;  int tempY = targetCharacter->y;  if(( x == tempX ) && (y == tempY ))    return true;  else    return false;}


then it works.

All this doesn't seem to make any sense. Probably the heap gets corrupted somehow, but I don't have any experience debugging memory corruptions, so I don't know what to do. All calls to the new operator are encapsulated in boost::shared_ptr constructors, so they shouldn't be any memory leaks. I've tried rebooting Windows XP, but it didn't help either.

My game runs in a single thread, although I think some Allegro timer routines run in a separate thread.

Which steps should I take to debug this?

[Edited by - formalproof on July 7, 2010 4:17:46 PM]
Advertisement
First of all do a clean rebuild of the project and make sure that you don't just have some corrupted files floating around in the build cache. This is generally the first port of call when dealing with mystery bugs, because you want to rule out the possibility that it isn't in fact your fault [wink]


Strip out as much code as you can until the problem goes away. Then slowly start reintroducing things until the problem comes back. That should narrow down the exact cause a bit.

If you get stuck there (or would just like a hand getting to that point) feel free to post your actual code, and we can take a look [smile]

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

The pointers odd value is a hint. 0xcdcdcdd1 is very close to 0xcdcdcdcd, the former probably being a member offset into the latter.
Quote:Original post by formalproof
I always encapsulate memory allocations inside shared_ptr's, like this:
boost::shared_ptr<Sprite> = boost::shared_ptr<Sprite>( new Sprite(32, 32) );

That should be a compiler error.

Sounds like you've got an uninitialized pointer in the works screwing stuff up somewhere. If the shared_ptr in question is a member of a class, chances are your 'this' pointer is actually invalid/uninitialized (you can use a debugger to check if it's near 0xCDCDCDCD). This would be the fault of whatever is calling the function you're currently in, doing something like:

SpriteManager* sm; // never initialized
sm->MakeSomeSpritesAndStuff(); // crashes when trying to assign to sm->some_shared_ptr, quite possibly 'within' shared_ptr's constructor or assignment operator.
Quote:Original post by ApochPiQ
First of all do a clean rebuild of the project and make sure that you don't just have some corrupted files floating around in the build cache. This is generally the first port of call when dealing with mystery bugs, because you want to rule out the possibility that it isn't in fact your fault [wink]


Thanks a lot -- doing a clean rebuild solved the first kind of problem. I'm now trying to see if there is a regular bug (not memory corruption) causing the other errors; I'll come back to you later when I know more. Just one question at this point: since Visual C++ obviously made a mistake and had a corrupted file in cache, does this mean it is likely to do it again, and could there be a specific reason for it, or does the corruption just happen at random?

It more or less just happens, at least from what I can tell. Using incremental rebuilds can make it more frequent, as can doing a lot of start/stop action during builds; accelerators like Incredibuild are known to cause some issues with some Visual C++ versions as well. In general though it'll probably just sneak up on you now and again. One of the downsides of working with a language like C++.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

It's not "at random", it's failing to detect something that needs rebuilding.

Since, after compilation, classes are basically just vectors of function pointers and people just call slots in the vector, there's no way to tell at link time that what one unit thinks is Foo::X() is now Foo::Y() {amongst other errors}. The compiler is dependent on the build tool to make sure that changes are correctly implemented in all the compilation units.

Is it likely to happen again? Sadly yes. VS, like most of these tools, for some reason finds it incredibly hard to correctly build the dependency graph {95% of makefiles and the Qt makefile builder also fail to do it properly}. I really don't understand why, it's not rocket science.

Generally I think the problem is caused because people try and compile as few files as possible by being as clever as possible and fail by being not quite as clever as they thought they were and hence undercompile. Which leads to these sorts of errors.

If one accepts that errors may result, but aim to have the result be overcompilation instead, the worst that happens is just that your compilation takes slightly longer...

If you move to a makefile derived environment, you can at least write your own solver (or go get one which works). But with VS, you're stuck with what Microsoft implemented. Which tries to be perfect and fails the wrong way.

This topic is closed to new replies.

Advertisement