fprintf causes segmentation fault due to sudden address change
I'm writing a small console game with ncurses (as a learning task) and I've already had some minor problems (it has been the first time I've been using lists in C), yet there never was a real showstopper. However, as a "provision for the future", I wanted to implement a rudimentary debug log file. And this is where things started to behave strange.
The log file is declared globally, fopen() (using w+ mode) and ferror() don't show any evidence for an error. Instead everything seems to work flawlessly, the log file is created, information is written to it. However, after I've added some debug output to various functions, the game just segfaults. As a consquence, I've commented out nearly every debug output to the file, and now this simple line of code crashes the whole game:
fprintf(debuglog, "loop_game()\n\tTime's over! Returning 0\n");
I've run the program using gdb, and开发者_StackOverflow社区 bt full outputted the following:
#0 0x00007ffff7886f24 in fwrite () from /lib/libc.so.6
No symbol table info available.
#1 0x000000000040224f in loop_game (pl=0x62d800, list_win=0x62f930,
timer=0x632620, list_ob=0x632640) at game.c:207
elapsed = 60
#2 0x0000000000402d53 in main () at main.c:62
pl = 0x62d800
list_win = 0x62f930
timer = 0x632620
list_ob = 0x632640
(game.c:207 is the line I've mentioned earlier) Additionally, someone told me I should use watch debuglog, and its output was the following:
Old value = (FILE *) 0x0
New value = (FILE *) 0x62f6f0
init () at console.c:128
128 fprintf(debuglog, "init()\n\tInitialised ncurses\n");
Then I've used continue, and roughly 10 seconds later, it printed out these lines:
Old value = (FILE *) 0x62f6f0
New value = (FILE *) 0x20062f6f0
move_obstacle (win_game=0x62f970, target_ob=0x63ce00) at game.c:370
370 wrefresh(win_game);
And then, after 60 seconds (this is the time after the game should end normally), the game segfaults. Sometimes when using gdb with debuglog as a watchpoint it also outputs
Old value = (FILE *) 0x22f6f0
New value = (FILE *) 0x0
or 0x2 instead of 0x0. I've even already had a SIGABRT.
Since I'm a beginner I have no idea what to do next. I've already asked some guys who definitely have a broad knowledge, yet they were unable to find the "root of all evil". If you need the code you can find it here. I hope it's just a stupid mistake I've made ...
It's likely you are writing over it. Here's what I mean.
In console.c
, you have
int field[FIELDMAXX][FIELDMAXY];
FILE * debuglog;
At the line that changes debuglog
you have:
field[target_ob->x_pos][target_ob->y_pos] = OBSTACLE; /* Changes debuglog. */
So it's pretty likely the values target_ob->x_pos
and target_ob->y_pos
are something you're not expecting.
Now, the first thing you have to do is fix that (find out what happens with those coordinates). The second thing you could do would be to define some other way of logging. Personally I think I would use a separate logging functions (which would call vfprintf
) and I would make debugfile
static to some file.
So, I've found a solution. And it was a stupid mistake I've made ... really stupid :D
The playing field is declared by int field[FIELDMAXX][FIELDMAXY];
, where FIELDMAXX
is 78 and FIELDMAXY
is 21. Now have a look at create_obstacle()
: The coordinates for newly created obstacles are FIELDMAXX + 1
and get_randypos()
(which returns an integer from 1 to 21). And here it comes, the typical beginner's mistake: In move_obstacle()
, there's a line which says field[target_ob->x_pos][target_ob->y_pos] = OBSTACLE;
(OBSTACLE is defined as 2).
Every obstacle moves every second one "unit of length" to the left (target_ob->x_pos--;
). So, if a newly created obstacle with x_pos = 79
(which is FIELDMAXX + 1
) and y_pos = 21
is moved by move_obstacle()
, its new x_pos
is 78 (while its y_pos
is 21). And as a consequence, the line I've mentioned above tries to set field[78][21]
to OBSTACLE
- and this is impossible (out of bounds). I feel a bit ashamed of myself now :)
精彩评论