Now that I have your attention
I am a first year uni student and had to make a c program for an assignment. Have run into problems though with pointers changing (mebe just breaking?) at a strange point where I should (read _should_ lol) have locked down all the random memory writes. I would normally just trawl forums / google looking for answer to something like this but feel here it is too ambiguous and strange to get something out of it. So here goes.
A bit of background: The program is a small 2d RPG that has a 40x40 map array and a 40x40 monsters / items array. It has a function GenerateMap that poplulates both these arrays at the start of the game. I then has the ability to go up and down levels via a trigger
that recalls GenerateMap with a different seed index.
It did originally work, but I changed the map access with the original being (simplified e.g.)
if (map[x][y] == 'g') //read
map[x][y] = 'x' //write
Like I said this worked fine but some parts of the map were obviously reading / writing outside the map. It worked, but badly. I changed it so that this became part of wrapper modules ReadMap() and WriteMap() that preformed error checking in the basic form
char ReadMap(map, x, y)
if (within bounds)
return map[x][y]
and the same for writing to the map. Now I don't have any problems with writing to strange areas of RAM and know that the rest of the program isn't going to be modified when writing to the map.
The problem is this:
void RunTests() is used to check among other things whether a map change is required. If it is it increases the map seed number and reruns GenerateMap(). This works out fine, and returns back to RunTests without error. Exiting out of RunTests however the pointer to monstersItems() is destroyed. Instead of eg 0x7fffa0df6520 it is changes to 0x7fffffffffff. Somehow the program stack is being destroyed from outside what is writeable. Now when ReadMap() or WriteMap() are run the XY values are ok but the pointer is outside of what the program can read and it segfaults. I have run kdbg all over
this program but have no idea what the problem is here.
So to recap
GameState()
//pointer to monstersitems is fine here
<do stuff>
RunTests()
//pointer points to wrong address
//next ReadMap() or WriteMap() segfaults as we are reading outside of program block.
RunTests()
if (need level change)
//pointer to monsters is fine here
GenerateMap(mapSeed + 1)
//pointer is still fine
I've included my full source for you to look at but appreciate the time it takes to identify with the code and find errors. Like I said I normally don't just go on forums and say "this is broke, how to fix lol" but in these extenuating circumstances I can't see my normal forum trawl helping much. If anyone could give some description of the problem itself so that I could research it would be greatly appreciated.
[edit] Also again some things may be done a bit strangely / badly. This is my first major c project, I'm still learning. feel free to tell me what is wrong and if you can be bother how / why it can be made better.
[edit] Gah sent production version with my full name / student number int it. Any way to delete? Ok got it.
[another edit] One dodgy way I though around this would be in GameState() to back up the pointer, run it, and copy back.
tmpPoint = &monstersItems;
RunTests;
&monstersItems = tmpPoint;
Is this possible? Would this work? I have no idea how I would code-wise go about this, but that's nothing half an hour on google wouldn't fix
Last edited by kimbecause; 10-12-2009 at 11:38 AM.
The real question is: WHERE does monsterItems get changed? Have you been able to use debugging statements to localize it more precisely? Have you run your code in a debugger?
Thanks for the response. monstersItems[][] is moved around and changed a fair bit, but it's pointer is never modified. All reads and writes to these decayed arrays are bounds checked, so they are not writing over local stack data (as I said, I'm not sure how stack data is stored in RAM so i'm not sure if this is possible). To clarify,
//monstersItems[][] is passed into GameState as an array decayed to a pointer to it's first element.
GameState()
//pointer to monstersitems is fine here
<do stuff>
RunTests()
//pointer points to wrong address
//next ReadMap() or WriteMap() segfaults as we are reading outside of program memory block.
RunTests()
if (need level change)
//pointer to monsters is fine here
GenerateMap(mapSeed + 1)
//pointer is still fine
So the stack is definitely getting corrupted through the process of GenerateMap() before returning to GameState. I've confirmed this using kdbg (the kde linux debugger), but only know how to view the local stack data, not the total memory area, so don't know where / why data is being written.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah. So many hours.
I found a way in kdbg to watch stack information in real time. I looped through one line at a time watching the information for EnterGameState. Finally in a completely unrelated function (probably written at 2am. Its 2:30 am now btw) I found this:
Of course after the final test to see if the room has been done before it changes the index in use, and then modifies it exactly 44 bytes after the end of the array. In m**********ing stack data.Code:short GetNextRoom(int *roomX, int *roomY, int roomBuffer[][2], int completedRooms[][2]) { /* Function: GetNextRoom() Written: 01/09/09 By: <me> Takes: roombuffer returns: x and y of next required room Requires: Does: returns the x/y of the next viable room in the frameBuffer. Returns 1 if this is found. */ short tmpI; short output = 0; for (tmpI = 0; tmpI < 256; tmpI++) { if (roomBuffer[tmpI][0] != -1) { *roomX = roomBuffer[tmpI][0]; //update vars *roomY = roomBuffer[tmpI][1]; if (TestCompleted(roomBuffer[tmpI][0], roomBuffer[tmpI][1], completedRooms) == 0) //final test to see if room has been done before { tmpI = 300; } //break loop roomBuffer[tmpI][0] = -1; //tag this index for reuse output = 1; //generate return } } return output; }
Obviously when this module is run earlier in the stack it was editing goodness knows what in a way that wasn't crashing the program; moving it further into used memory messed it up.
It's always a seemingly unrelated problem. Welcome to serious programming.
Oh, also, I'd suggest you divide your program up into multiple files. Your file is already coming up on 2400 lines, and that should really be divided into multiple files. You'll have a much easier time managing each piece and seeing what's going on if you took some time out to refactor your code that way, placing relevant functions next to each other in different files. You've got more than big enough of a program to do that with!
Wow I changed my sig!
Thanks, I will definitely look into this. There are some certain places where the code could be split. Quick! To the GoogleMobile (plays batman music).
'Tis the best place to find information, Google!
But here's a quick and easy convenience reference:
In order to write a program using multiple files, you'll need to employ source files and header files, and the distinction is that header files will be directly #included into your source files as necessary, whereas your source files will maintain the executable code and will be the partitions of your generated .o files. The name's of the .c source files aren't important, nor are the names of the header files, however convention states that .h header files should be named the same name as their according .c source files that contain the functions described in the header. A header will look like this:
The according source file to the above header would look like so:Code:#if !defined(MYHEADERNAME_H_INCLUDED) #define MYHEADERNAME_H_INCLUDED int myFunction(int, char**); /* Function prototype. */ /* Other function prototypes would also go in header files according to the .c source file's functions. You should also include struct's, typedefs, and necessary #define calls and macros in header files. */ #endif
In this manner you can attach the .c source files you've written by #including their according .h header files into other source files. Like so in main.c:Code:#include "myheadername.h" int myFunction(int aNum, char** args) { /* This is the actual function body that does the work. */ return aNum; }
And that's a quick and dirty tut on including other files!Code:#include <stdio.h> #include "myheadername.h" int main(int argc, char* argv[]) { int retnum; retnum = myFunction(argc, argv); printf("%d", retnum); return 0; }
Last edited by ZekeDragon; 10-12-2009 at 09:01 PM. Reason: Whoop, not done!
Wow I changed my sig!
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks