Hidden segfaults

Started by
15 comments, last by LackOfGrace 16 years, 2 months ago
Me and some friends are working on a school-project where we decided to create a RPG game, with a very similar gameplay as Zelda: A link to the past to the SNES. We're constructing our own engine, but the following code contains a segfault which I've been, for the last 3-4 hours, unable to find.
class Sector
{
          public:       int posx;
                        int posy;                        
                        char spritefile[50];
                        bool passable;
};

class Room
{
          public:       Room(const char *file);
                        void LoadRoom(const char *file);
                        void DrawRoom(SDL_Surface *surface);
                        
                        int rootx;
                        int rooty;
                        
                        Sector rmap[100][100];                                                                     
};

Room::Room(const char *file)
{           
     LoadRoom(file);
}

void Room::LoadRoom(const char *file)
{                              
     FILE *roomfile;
     int posx;
     int posy;
     int pass;
     char sprfile[50];
     roomfile = fopen(file, "r");
     char tag[20];
     char params[100];
     while(fscanf(roomfile, "%s = %s", tag, params) != EOF)
     {
              if (strcmp(tag, "WALL") == 0)
              {
                       sscanf(params, "%d - %d - %d - %s", &posx, &posy, &pass, sprfile);
                       rmap[posy][posx].posx = posx;
                       rmap[posy][posx].posy = posy;
                       if (pass == 0)
                       {
                       rmap[posy][posx].passable = true;
                       }
                       else
                       {
                       rmap[posy][posx].passable = false;                           
                       }
                       strcpy(rmap[posy][posx].spritefile, sprfile); 
              }
              else if (strcmp(tag, "COMMENT") == 0)
              {
                       
              }
     }
}


void Room::DrawRoom(SDL_Surface *surface)
{
     int i2, i;
     SDL_Surface *spr;
     SDL_Rect pos;
     for(i2=0;i2<100;i2++)
     {
            for(i=0;i<100;i++)
            {
                  pos.x = rmap[i2].posx * 50;
                  pos.y = rmap[i2].posy * 50;
                  pos.w = 50;
                  pos.h = 50;
                  spr = SDL_LoadBMP(rmap[i2].spritefile);
                  SDL_SetColorKey(spr, SDL_SRCCOLORKEY, SDL_MapRGB(spr->format, 0x00, 0x00, 0xFF));
                  SDL_BlitSurface(spr, &spr->clip_rect, surface, &pos);  
            }
     }
}
Advertisement
It's impossible to tell without seeing the data files that are being read. Even then, it may be impossible to tell without see the rest of the game's source code. How are you sure it's in this code?

There are other problems lurking in this code. You're loading the tile's every time they're drawn, for example. You should load them once somewhere besides the drawing function.
Maybe it is the consequence of the fscanf call. fscanf returns the number of arguments filled or EOF. Try this:

int scan = fscanf(roomfile, "%s = %s", tag, params);while(scan != EOF && scan != 0){    ...        // Repeat it at the end of the loop    scan = fscanf(roomfile, "%s = %s", tag, params);}




If that doesn't work, please use a just-in-time debugger to determine which line of code causes the segfault. If you don't have one installed, use Dr. MinGW (contained in mingw-utils) - put it somewhere and install it as the default debugger with "drmingw.exe -i -a". Then you need to tell the compiler to create debugging information.

GCC: Use the parameter "-g3"
MS VC++: Look at the project options, there should be a predefined "Debug" target
Quote:Original post by wendigo23
It's impossible to tell without seeing the data files that are being read. Even then, it may be impossible to tell without see the rest of the game's source code. How are you sure it's in this code?

There are other problems lurking in this code. You're loading the tile's every time they're drawn, for example. You should load them once somewhere besides the drawing function.


The data file:

WALL = 10 - 10 - 0 - resources/sprites/church_floor.bmpWALL = 10 - 10 - 0 - resources/sprites/church_floor.bmp


The BMP file is just, a BMP file, which SDL takes care of which is beyond my control and is as such irrelevant to the code.

My program only crashes when I use this code and occurs when I create an object of the Room-class. It's exactly there the crash occurs.

Yes, I know. I just felt lazy to make a completely optimized drawer for it just when testing.
I assume this is C++? If so, it looks like you're basically programming in C (or what we sometimes call 'C with classes').

C++ is a low-level language, but C is lower-level still, and C (or C-ish) code is often replete with opportunities for access violations, segfaults, and other unpleasant behavior. Every fixed-sized buffer, every call to strcpy(), every argument passed via pointer - each is an opportunity for nasty bugs to arise.

C++ is by no means an easy language to program in, but it is much easier to avoid these types of errors in C++, assuming you write idiomatic code and use the tools that the language provides. In your case, for example, replacing character buffers, C-style file access, and raw arrays with string objects, file stream objects, and range-checked containers such as vector or boost::multi_array would go a long way towards making your code safer, more robust, and less error-prone.
Quote:Original post by jyk
I assume this is C++? If so, it looks like you're basically programming in C (or what we sometimes call 'C with classes').

C++ is a low-level language, but C is lower-level still, and C (or C-ish) code is often replete with opportunities for access violations, segfaults, and other unpleasant behavior. Every fixed-sized buffer, every call to strcpy(), every argument passed via pointer - each is an opportunity for nasty bugs to arise.

C++ is by no means an easy language to program in, but it is much easier to avoid these types of errors in C++, assuming you write idiomatic code and use the tools that the language provides. In your case, for example, replacing character buffers, C-style file access, and raw arrays with string objects, file stream objects, and range-checked containers such as vector or boost::multi_array would go a long way towards making your code safer, more robust, and less error-prone.


I understand what you mean, and I am a old C-coder since when I was like 11 or 12. To my experience, the string-class generally never works and almost always makes my program crash where a char array works perfectly. Almost everything C++ and whatever it's STL brings, brings nothing more than trouble. But since C++ and C is the same thing to the compilers of today, I see no reason why I shouldn't make use of both specialities by combining structural code with classes of C++ and still using the low-level speciality of C. It's always the same code when compiled anyway ;)

Quote:Original post by archaos90
To my experience, the string-class generally never works and almost always makes my program crash where a char array works perfectly.

That's funny. In my experience the string class works fine (trust me, the millions and millions of actual C++ programmers aren't hallucinating). In contrast, I'm given to understand that one may easily write good-looking C-style C++ which nevertheless contains segfaults which take upwards of 3-4 hours to find. Does that last bit jibe with your own experience?
Quote:Almost everything C++ and whatever it's STL brings, brings nothing more than trouble.

That's because you don't understand it. It's a common programmer defense mechanism to attribute the problems one has with a language to faults of the language itself, as opposed to an unwillingness to get to know the language well enough. I'm not saying C++ is perfect--far from it, it's almost as crappy as C--but your reasons for disliking it are stupid.

Aaanyways, insults aside. If it's actually taken you 3-4 hours to find the bug so far, it's a cinch that you don't know how to use the debugger properly. The debugger will tell you exactly where the segfault is, and (with a little more effort) how the incorrect memory address got into the pointer in the first place. Trust me, you will save yourself time by learning to use the debugger now instead of doing ad-hoc troubleshooting.
Introduction to Debugging. Largely focuses on MSVC 2005, but a some the advice is applicable to other debuggers, and almost all of it can be used with other versions of MSVC.
Quote:Original post by archaos90
To my experience, the string-class generally never works and almost always makes my program crash where a char array works perfectly. Almost everything C++ and whatever it's STL brings, brings nothing more than trouble.
We're all free, of course, to develop in the language with which we're most comfortable, and it certainly makes sense that you would be more comfortable with C, given your history with it.

However, for the sake of others who might read this thread, I have to point out that your assessment of the C++ standard library is questionable at best, and completely inaccurate at worst.

Your basic implementation of the basic_string class template (such as those provided along with GCC or VC++) should be, for all practical purposes, bug-free. As such, it's safe to say that the string class works fine. If you found that it always made your program crash, it was most likely that you were using it incorrectly. (There aren't that many ways to screw up when using string objects, but it's still possible - for example, by reading or writing past the end of its allocated buffer.)

As for the rest of what you're referring to as the STL, the statement 'it brings nothing more than trouble' would be contested, I'm sure, by the countless experienced developers who use it every day. On the contrary, the STL-derived portions of the SC++L make things easier and less error-prone, not the other way around. If you've had a bad experience with these parts of the C++ standard library, it was again probably just due to unfamiliarity.

Finally, you say that a 'character array works perfectly'. And yet, here you are, posting on the forums because your program is crashing inexplicably :) As such, I'm not sure how you can say with such confidence that character arrays 'work perfectly' ;)

Anyway, I'll stop now. Language choice is certainly very personal (just peruse any of the recent 'language war' threads for evidence of this), and I don't mean to be overzealous in my advocacy of C++. However, I do feel strongly that the way forward in software development is in higher-level, more abstract languages, which C definitely is not. (Neither is C++, for that matter.)
Use a debugger to step through the code one line at a time to find exactly where it crashes.

This topic is closed to new replies.

Advertisement