Skip to main content
GameDev.net gamedev.net
🔒 Locked

Weird Segmentation Error(s)

Started by Neutrinohunter Jan 26, 2008 at 7:50 PM 24 replies 4.4k views
Original Post
Neutrinohunter
Neutrinohunter
I am getting a lot of segmentation errors in the gdb debugger after I have made some changes and recompiled my project. If I call a function through a pointer: boundingBox->recalculate() And boundingBox isn't NULL and recalculate() doesn't access any heap memory nor call another function, how can there be a seg fault? I'm trying to find these across my project, it seems the debugger doesn't like VFT and indirect recursion for a start off. Could it be a broken pointer? Neutrinohunter
KodeNerd
KodeNerd
If recalculate() is private or protected that may be a problem (only if in C++), that is all I can think of right now.
------------George Gough
Neutrinohunter
Neutrinohunter
Nah its public. Yeah its C++.

I narrowed the code down to this: (from std::cout, so the error debugging is as accurate as the gdb debugger.)

void JBoundingBox::testVertex(float x, float y, float z) {
/*if (x < minX) minX = x;
if (x > maxX) maxX = x;
if (y < minY) minY = y;
if (y > maxY) maxY = y;
if (z < minZ) minZ = z;
if (z > maxZ) maxZ = z;*/
}

It seems to crash on any call to boundingBox->someFunction(), yet boundingBox isn't NULL. I can comment this stuff out (its secondary stuff) but I have a few similar errors like this which are frankly above the word annoying :P

Is there anyway to check for broken pointers or other possible problems? It should be mentioned that the getBoundingBox() function is inherited and its protected so could that be a problem?

Neutrinohunter
KodeNerd
KodeNerd
I know it breaks OO rules but try making boundingBox public. If that does not work try:

if(boundingBox)    boundingBox->recalculate();



Make sure to return boundingBox to protected if it does not work.
------------George Gough
SiCrane
SiCrane
Public, protected and other access specifiers exist only at compile time; they have no effect at runtime. The most likely cause is that you're calling the function on a bad pointer. You could have a buffer overrun, be referencing deleted memory or have similar problem in your application.
Neutrinohunter
Neutrinohunter
I thought of that and that didn't work. The thing this seems to be happening with all my pointers. If I comment all the bounding box code out and try again, I get errors with other pointers in the base class. Again the pointers are not NULL. I'm going to try recompiling and see its g++/gcc causing the problem. Because ive not changed much since it was working perfectly two weeks ago.
Neutrinohunter
Neutrinohunter
SiCrane: You mean I could be right and its a broken pointer? Or am I not understanding you correctly. If so how would one attempt to fix such a problem?

neutrinohunter
SiCrane
SiCrane
Welcome to one of the suckiest parts of programming C++ (or any other non-managed programming language). I'm not familiar with gdb's memory debugging facilities, so I can't recommend anything that way. At a basic level try using something like valgrind to check your memory management.
Neutrinohunter
Neutrinohunter
Hehe, good to know.

As soon as I get a Linux build I'll try running Valgrind. I managed to find bugs in Valgrind last year so I'm not too hopeful :( I've managed to work around some code so far so hopefully I might try to rewrite some of it to get around the problem.

It looks like two subsystems which are affected (in a 20,000 Uni project) which are the animation system and the bounding box system, so I suppose I could just staticly allocate them and that would remove the problem? I mean I guess it would be a huge performance loss, but I will most likely need both systems eventually.

Thanks for your help so far
neutrinohunter
KodeNerd
KodeNerd
Quote:
Original post by SiCrane
Public, protected and other access specifiers exist only at compile time; they have no effect at runtime. The most likely cause is that you're calling the function on a bad pointer. You could have a buffer overrun, be referencing deleted memory or have similar problem in your application.


Ah, I am not super proficient with function pointers as I have never needed them. Thanks for clearing that up.
------------George Gough
Ademan555
Ademan555
The error you're describing suggests that boundingBox points to something that doesn't exist, unallocated memory. Maybe it points to memory that WAS allocated, but it's been deleted now. boundingBox has to point to memory allocated with "new" or "malloc()" (i'm sure you already knew that but I'm making sure i've covered all of the bases, sometimes the super obvious errors are overlooked)

I think most likely though, is that in some piece of code somewhere you are delete-ing boundingBox or free()-ing it. remember it doesn't necessarily have to be "delete boundingBox;"

BB * foo;BB * bar;foo = new BB();bar = foo;delete bar;foo->recalculate();

would still break since you freed the memory that both foo and bar point to

One final possibility is that it sounds like you're on windows right? gcc/g++ are great compilers, but mingw really isn't too good, this could actually be a compiler bug... *maybe*.
When General Patton died after World War 2 he went to the gates of Heaven to talk to St. Peter. The first thing he asked is if there were any Marines in heaven. St. Peter told him no, Marines are too rowdy for heaven. He then asked why Patton wanted to know. Patton told him he was sick of the Marines overshadowing the Army because they did more with less and were all hard-core sons of bitches. St. Peter reassured him there were no Marines so Patton went into Heaven. As he was checking out hi
miminawewe
miminawewe
It would be better if you can show us all the code, or at least give a very clear description of the code. C/C++ is tricky. E.g. if you are using vectors (from the STL) and you had a pointer to one of the elements in the vector then you push_back() another element the vector can re-allocate memory to store the element you just pushed in case there is not enough to store it in the currently allocated memory of storing the elements thus the pointer above references an element that has been removed (and re-allocated to another place in memory). This is just an example of how interesting things can be in C++.
Neutrinohunter
Neutrinohunter
I've had a sleep and come back to it and commented out the two systems for the moment.

Description: I have a abstract base class called JPolygon() which handles all the similar features of a shape or model. This includes the bounding box and animation systems. There is 1 AnimationManager and 1 BoundingBox per JPolygon().

From the subclass, I call getAnimationManager() and getBoundingBox() which are inherited function calls (protected) from JPolygon() like so:

JBoundingBox * JPolygon::getBoundingBox() {   if (boundingBox == NULL) boundingBox = new JBoundingBox();   return boundingBox;}JAnimationManager * JPolygon::getAnimationManager() {   if (animationManager == NULL)      animationManager = new JAnimationManager();   return animationManager;}


I call my base class like so:

JBox::JBox(JStatsManager * stats) : JPolygon() {   setPosition(JVector3D(0,5, 0));   setScale(3);    setColour(1.0,0.0,0.0);   setOutwardNormals();   setVisible(true);   setName("JBox");   getAnimationManager();   setAnimated(true);   setStatsCollector(stats);   getBoundingBox();   //This gets boundingBox   createBoundingBox(); //This calls boundingBox->recalculate and resizes box}void JBox::createBoundingBox() {   boundingBox->recalculate();  for(int i = 0; i < 24; i++) {      float x = points[0];// * scale + position.x;      float y = points[1];// * scale + position.y;      float z = points[2];// * scale + position.z;      boundingBox->testVertex(x, y, z);   }}


I am using STL Vectors but they are in other areas of the code (different subsystems) I don't think I am deallocating memory (the gdb stack doesn't seem to indicate this, then again it sometimes says I have an error when it works fine in Linux and Windows :P)

Yes, I am working on Windows. That would be typical, I'm using QT too and I've found a problem with a few of their classes :(

Errmmm...I wondering whether its the static initializer thats the problem, all of sudden. It could be because my destructor for the abstract base class is virtual and I've added extra code in there. I'll remove and compile and see if that helps.

Thanks guys

neutrinohunter




Structural
Structural
Just a random thought, try a rebuild-all.
If you added/removed members to your JPolygon class and not all intermediate files have been rebuilt the different intermediate binary files may be using JPolygon objects with slightly different sizes.
I once ran into this when I set my system clock forward to test something, so the intermediate files were always newer than the source files and were thus not rebuilt.

Other than that, check if you set your boundingbox member to NULL at object creation.
STOP THE PLANET!! I WANT TO GET OFF!!
Neutrinohunter
Neutrinohunter
I've tried that, unfortunately it didn't see it work.

Weirdly though, something on the computer set my clock 20 mins fast the other day, which as you said could cause intermediate files not be compiled.

I think its the base class which is causing the problems, might be just a bad compile on that.

neutrinohunter
Zahlman
Zahlman
Quote:
Original post by KodeNerd
If recalculate() is private or protected that may be a problem (only if in C++), that is all I can think of right now.


If you can't think of something that is reasonably likely to actually be relevant, don't feel compelled to post.

The 'private' and 'protected' concepts are in the compile-time domain. There is no code generated to respect those keywords explicitly; they only allow the compiler to complain if you write code that modifies data in a way you said you didn't want to. If 'recalculate()' were private or protected and this were actually not kosher, the compiler would have refused to create the program.

A segmentation fault occurs at runtime. It won't be influenced by that stuff, and the fact of it happening is evidence that the compiler didn't emit any errors.

Not to mention, he then said it was public, and you responded by suggesting to make 'boundingBox' public as well. Which doesn't even make sense: it isn't necessarily a member of another object here.

Quote:
Original post by KodeNerd
Quote:
Original post by SiCrane
Public, protected and other access specifiers exist only at compile time; they have no effect at runtime. The most likely cause is that you're calling the function on a bad pointer. You could have a buffer overrun, be referencing deleted memory or have similar problem in your application.


Ah, I am not super proficient with function pointers as I have never needed them. Thanks for clearing that up.


OK, there is something seriously wrong with your reading comprehension, understanding of the language or both. Function pointers are pointers *to* functions. That has nothing to do with calling a function *on a* pointer (i.e. calling a member function of a pointed-to object, via the -> operator).

To the OP: Just because 'boundingBox' isn't NULL doesn't mean it's valid. Without context, it could still point to anywhere in memory, including memory that does not belong to your program, or to data that does not logically actually represent a BoundingBox (or whatever) object. So yes, a broken pointer. Commonly, an uninitialized one, or one that "points" past the end of an array.
Zahlman
Zahlman
Quote:
Original post by Neutrinohunter
I've had a sleep and come back to it and commented out the two systems for the moment.

Description: I have a abstract base class called JPolygon() which handles all the similar features of a shape or model. This includes the bounding box and animation systems. There is 1 AnimationManager and 1 BoundingBox per JPolygon().

From the subclass, I call getAnimationManager() and getBoundingBox() which are inherited function calls (protected) from JPolygon() like so:

*** Source Snippet Removed ***

I call my base class like so:

*** Source Snippet Removed ***


OK, there are a few strange things here.

1) What's with all the 'J' prefixes? Use a namespace.

2) You store the bounding box (and animation manager) by pointer, creating one dynamically when it is "asked for". Presumably this is intended as some kind of "create on first use" optimization.

Don't do that. Yes, I see this kind of thing all the time in samples of "professional" real world code, and it is almost universally a bad idea. It only really saves you anything if you never end up using the bounding box of a Polygon. But you do already in the derived constructor. Which makes sense: there's no reason for a Polygon not to have a bounding box. Even if you do save something, it's just a small chunk of memory (sizeof(BoundingBox) - sizeof(BoundingBox*)).

In every other case, you pay the memory cost of the pointer, the speed cost of indirection, the speed cost of lost cache coherency and the complexity cost of maintaining a dynamic allocation, while not actually making use of any of the resulting flexibility.

3) You create a separate animation manager for every polygon. This seems very strange, considering what "manager"s usually are.

4) You set a zillion things up through getters and setters. This is a disease. Use constructor parameters (and forward them to the base constructor via the initialization list) for initializing things. Seriously rethink your design if you think you want to set data members of the class directly, post-initialization. 9 times out of 10, you are in effect lying to yourself to maintain the delusion that you're doing things the "proper, OO way" while still allowing yourself to scribble all over "private" data members.




These kinds of problems tend to indicate things that are systematically wrong with how you are writing code. Unfortunately, they are very prevalent out there. Anyway, it's quite possible that this sort of thing is helping to hide a problem in code somewhere else which corrupts your memory, causing undefined behaviour (one possible consequence of which is the later failure of a perfectly innocent and totally unrelated pointer).
Bregma
Bregma
Here are the common causes of the symptoms you're experiencing.

(1) Your class contains pointers but you don't properly follow the rule of three: provide an appropriate destructor, copy constructor, and assignment operator. This bites you particularly hard using Qt with its byzantine and myriad ownership semantics. If you copy objects with pointers and one of those objects gets deleted (by setAutoDelete(true) or via a QObject destructor, say) the pointer might be freed even though the same pointer is still in play in other objects. Valgrind will help you with this. It is the most frequent and likely cause.

(2) You have changed the ABI of some object but not done a full clean-and-rebuild. This can be more subtle. If the problem goes away after a full force-build, that was your problem.

(3) Global variable can cause this problem if you instantiate them in more than one object module. This would show up only if you dynamically load modules (LoadLibrary() or dlopen()).

--smw
Stephen M. Webb
Professional Free Software Developer
Neutrinohunter
Neutrinohunter
1) The JPrefixes? - Preference.

2) Yes, it is. It also provides an abstraction so only one can be created. The idea of a Factory and Singleton design patterns are being employed here.

3) Indirection is a GoF Design Pattern and it promotes reusability and user-friendliness as there is only one object to deal with. I'm not concerned on the neglible overhead of the indirection.

4) One JAnimationManager manages 0:n JAnimationPaths which are transformations for one polygon. Manager is possibly misworded here.

5) Rightly, so I suppose I should use better base initialisers in JPolygon. Though I wanted default set values in its subclasses.

6) Could possibly be with something I wrote since I changed it, yet it *was* working a few days ago with no errors such as these.


Bregma: Its probably the first. Though I only use QT for Widgets and nothing more.

Neutrinohunter
Driv3MeFar
Driv3MeFar
Quote:
Original post by Neutrinohunter
2) Yes, it is. It also provides an abstraction so only one can be created. The idea of a Factory and Singleton design patterns are being employed here.


So, you can only create one bounding box per polygon (unless boundingBox is static, but why would you want that). That's kind of the whole point of a member variable; each instance of the class gets its own single instance of that variable. I don't really see how what you're doing is any different than having boundingBox be created when the polygon itself is, other than the fact that now you have the overhead of an allocation the first time you try to get a poly's boundingBox instead of when you create the poly.

Why you would want something that behaves as a singleton here is beyond me, anyway.

Quote:

3) Indirection is a GoF Design Pattern


No it isn't. Not in my copy of Design Patterns, at least.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.