Synopsis: Recovering from pfile loading failures via longjmp. April 98 From erwin@pip.dknet.dk Sat Apr 18 10:58:47 1998 Date: Sat, 18 Apr 1998 10:58:43 +0200 (MET DST) From: "Erwin S. Andreasen" X-Sender: erwin@shire.shire.dk Reply-To: erwin@pip.dknet.dk To: Nebseni cc: rom@rom.org Subject: Making pfile loading a bit more robust; WAS: Re: passwords? On Fri, 17 Apr 1998, Nebseni wrote: > I frequently add totally new code to my mud. Of course such code is rarely > 100% correct the first time, and on some occasions the error is nothing I > see in my testing but something that a unique player has that my code didn't > account for. If the mud crashes when that player logs on and I can't see > anything obvious, I do the debug thing with the test mud, and load the > player file to replicate the crash (while observing the debug) to rapidly > localize (and squash) the bug. 99% of the time, a bad pfile has a missing number or a string without a ~ or such, so fread_number/fread_string just go down - and don't tell you where the heck the error really is. To avoid passing a flag to fread_XXX functions, which would complicate things immensely, I use setjmp/longjmp to provide error handling. Basically, in load_char_obj I use setjmp. that stores the current stack frame in a variable. I also set a flag. In fread_number/string, if some fatal error occurrs which usually exits the MUD, I check for that flag, and if it is set... I longjmp back. The code looks roughly like this: // Format error while reading pfile! jump_on_error = 1; if (setjmp(error_hook) == 1) { fp.close(); addBadPfile(); return LOAD_FATAL_ERROR; } When setjmp is FIRST called, it returns 0. When you longjmp back, it is like if setjmp was just called, but it returns 0 instead. And in MappedFile::readNumber() (I use mmaped files, but the principle is really the same) int MappedFile::readNumber() { [...] if (pos == end) { bugf("mread_number:EOF"); if (jump_on_error) longjmp(error_hook, 1); else do_abort(); } ANOTHER thing that is very important: in case of a fread_number coming upon a number , write the current line in the file! This is quite a lot easier with mmapped file, but still can be done with FILE* - check thet code for bug(), which does ftell, goes back to beginning of the file then reads everything in again and counts the lines. So, when I do something like: >> pload BadPfile I get: WIZNET: BUG: Bad number: got a 'q', expected a digit in ../player/b/Badpfile:1234 and I start up vi, go to that file's line 1234 and find out what the problem is :) Oh yeah, another thing is that load_char_obj returns several different values, not just false for new player, and true for old player, but another value for "bad pfile" And a third thing: I currently don't free anything of the player's inventory or anything, I suppose I should; but I'd rather have a minor memory loss whenever someone with a bad pfile tries to login (they only get to do this once, then their pfile is added to a list of bad pfiles which do not load) than the MUD crashing. PS: I found it very amusing to see that the person who whined over CC'ing the rom mailing list, posted in HTML.. :) ============================================================================== Erwin Andreasen Herlev, Denmark UNIX System Programmer <*> (not speaking for) DDE ==============================================================================