From: PatR Date: Sun, 22 Nov 2015 16:33:42 +0000 (-0800) Subject: flag panic() and terminate() as "no return" X-Git-Tag: NetHack-3.6.0_RC01~28 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b30fce4f8800026fcdaace835c2ae828602b65ec;p=nethack flag panic() and terminate() as "no return" Mark panic() as never returning so that code analysis might be able to do a smarter job. It required splitting done() into two routines since the first part really can return (but not if PANICKED was the reason it got called). done() is now much shorter and ends with a call to new really_done(), and panic() skips done()'s might-return part by calling really_done() directly. Noticed in passing: the "report error to " code calls a routine which uses alloc(), which won't work very well if the reason for panic was because malloc() ran out of memory. --- diff --git a/include/extern.h b/include/extern.h index 660fa4163..2d081587b 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1447653422 2015/11/16 05:57:02 $ $NHDT-Branch: master $:$NHDT-Revision: 1.517 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1448210010 2015/11/22 16:33:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.519 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -636,12 +636,12 @@ E void FDECL(done_intr, (int)); #endif E void FDECL(done_in_by, (struct monst *, int)); #endif /* !MAKEDEFS_C && !LEV_LEX_C */ -E void VDECL(panic, (const char *, ...)) PRINTF_F(1, 2); +E void VDECL(panic, (const char *, ...)) PRINTF_F(1, 2) NORETURN; #if !defined(MAKEDEFS_C) && !defined(LEV_LEX_C) E void FDECL(done, (int)); -E void FDECL(container_contents, - (struct obj *, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); -E void FDECL(terminate, (int)); +E void FDECL(container_contents, (struct obj *, BOOLEAN_P, + BOOLEAN_P, BOOLEAN_P)); +E void FDECL(terminate, (int)) NORETURN; E int NDECL(dovanquished); E int NDECL(num_genocides); E void FDECL(delayed_killer, (int, int, const char *)); @@ -2526,8 +2526,8 @@ E boolean NDECL(authorize_wizard_mode); /* ### vmsmisc.c ### */ -E void NDECL(vms_abort); -E void FDECL(vms_exit, (int)); +E void NDECL(vms_abort) NORETURN; +E void FDECL(vms_exit, (int)) NORETURN; #ifdef PANICTRACE E void FDECL(vms_traceback, (int)); #endif diff --git a/include/tradstdc.h b/include/tradstdc.h index 697982411..26ce81ad5 100644 --- a/include/tradstdc.h +++ b/include/tradstdc.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 tradstdc.h $NHDT-Date: 1447755973 2015/11/17 10:26:13 $ $NHDT-Branch: master $:$NHDT-Revision: 1.26 $ */ +/* NetHack 3.6 tradstdc.h $NHDT-Date: 1448210011 2015/11/22 16:33:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.27 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -385,6 +385,7 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #endif #if __GNUC__ >= 3 #define UNUSED __attribute__((unused)) +#define NORETURN __attribute__((noreturn)) #endif #endif @@ -394,5 +395,8 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #ifndef UNUSED #define UNUSED #endif +#ifndef NORETURN +#define NORETURN +#endif #endif /* TRADSTDC_H */ diff --git a/src/end.c b/src/end.c index 324e0a440..191e78308 100644 --- a/src/end.c +++ b/src/end.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 end.c $NHDT-Date: 1448094339 2015/11/21 08:25:39 $ $NHDT-Branch: master $:$NHDT-Revision: 1.105 $ */ +/* NetHack 3.6 end.c $NHDT-Date: 1448210011 2015/11/22 16:33:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.107 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -47,6 +47,7 @@ STATIC_DCL void FDECL(disclose, (int, BOOLEAN_P)); STATIC_DCL void FDECL(get_valuables, (struct obj *)); STATIC_DCL void FDECL(sort_valuables, (struct valuable_data *, int)); STATIC_DCL void FDECL(artifact_score, (struct obj *, BOOLEAN_P, winid)); +STATIC_DCL void FDECL(really_done, (int)) NORETURN; STATIC_DCL boolean FDECL(odds_and_ends, (struct obj *, int)); STATIC_DCL void FDECL(savelife, (int)); STATIC_DCL void FDECL(list_vanquished, (CHAR_P, BOOLEAN_P)); @@ -535,23 +536,25 @@ VA_DECL(const char *, str) raw_print("\nError save file being written.\n"); #else if (!wizard) { + const char *maybe_rebuild = !program_state.something_worth_saving + ? "." + : " and it may be possible to rebuild."; + char *tmp = 0; + if (sysopt.support) raw_printf("To report this error, %s%s", sysopt.support, - !program_state.something_worth_saving - ? "." - : " and it may be possible to rebuild."); - else if (sysopt.wizards) { - char *tmp = build_english_list(sysopt.wizards); + maybe_rebuild); + else if (sysopt.wizards && strcmp(sysopt.wizards, "*") != 0 + /* this is risky; panic might be due to malloc failure */ + && (tmp = build_english_list(sysopt.wizards)) != 0) raw_printf("To report this error, contact %s%s", tmp, - !program_state.something_worth_saving - ? "." - : " and it may be possible to rebuild."); - free(tmp); - } else + maybe_rebuild); + else raw_printf("Report error to \"%s\"%s", WIZARD_NAME, - !program_state.something_worth_saving - ? "." - : " and it may be possible to rebuild."); + maybe_rebuild); + + if (tmp) + free((genericptr_t) tmp); } #endif /* XXX can we move this above the prints? Then we'd be able to @@ -568,6 +571,7 @@ VA_DECL(const char *, str) #endif { char buf[BUFSZ]; + Vsprintf(buf, str, VA_ARGS); raw_print(buf); paniclog("panic", buf); @@ -580,7 +584,7 @@ VA_DECL(const char *, str) NH_abort(); /* generate core dump */ #endif VA_END(); - done(PANICKED); + really_done(PANICKED); } STATIC_OVL boolean @@ -862,15 +866,6 @@ void done(how) int how; { - boolean taken; - char pbuf[BUFSZ]; - winid endwin = WIN_ERR; - boolean bones_ok, have_windows = iflags.window_inited; - struct obj *corpse = (struct obj *) 0; - time_t endtime; - long umoney; - long tmp; - if (how == TRICKED) { if (killer.name[0]) { paniclog("trickery", killer.name); @@ -882,8 +877,6 @@ int how; } } - /* pbuf: holds Sprintf'd output for raw_print and putstr - */ if (how == ASCENDED || (!killer.name[0] && how == GENOCIDED)) killer.format = NO_KILLER_PREFIX; /* Avoid killed by "a" burning or "a" starvation */ @@ -907,34 +900,48 @@ int how; (void) adjattrib(A_CON, -1, TRUE); savelife(how); - if (how == GENOCIDED) + if (how == GENOCIDED) { pline("Unfortunately you are still genocided..."); - else { + } else { killer.name[0] = 0; killer.format = 0; return; } } - if ((wizard || discover) && (how <= GENOCIDED)) { - if (paranoid_query(ParanoidDie, "Die?")) - goto die; + if ((wizard || discover) && (how <= GENOCIDED) && + !paranoid_query(ParanoidDie, "Die?")) { pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die"); savelife(how); killer.name[0] = 0; killer.format = 0; return; } + really_done(how); +} -/* - * The game is now over... - */ +/* separated from done() in order to specify the __noreturn__ attribute */ +STATIC_OVL void +really_done(how) +int how; +{ + boolean taken; + char pbuf[BUFSZ]; + winid endwin = WIN_ERR; + boolean bones_ok, have_windows = iflags.window_inited; + struct obj *corpse = (struct obj *) 0; + time_t endtime; + long umoney; + long tmp; -die: + /* + * The game is now over... + */ program_state.gameover = 1; /* in case of a subsequent panic(), there's no point trying to save */ program_state.something_worth_saving = 0; /* render vision subsystem inoperative */ iflags.vision_inited = 0; + /* might have been killed while using a disposable item, so make sure it's gone prior to inventory disclosure and creation of bones data */ inven_inuse(TRUE); @@ -1039,6 +1046,7 @@ die: formatkiller(eos(pbuf), sizeof pbuf - strlen(pbuf), how); make_grave(u.ux, u.uy, pbuf); } + pbuf[0] = '\0'; /* clear grave text; also lint suppression */ /* calculate score, before creating bones [container gold] */ { @@ -1388,6 +1396,11 @@ int status; } #ifdef VMS + /* + * This is liable to draw a warning if compiled with gcc, but it's + * more important to flag panic() -> really_done() -> terminate() + * as __noreturn__ then to avoid the warning. + */ /* don't call exit() if already executing within an exit handler; that would cancel any other pending user-mode handlers */ if (program_state.exiting) diff --git a/util/panic.c b/util/panic.c index 852a3e24f..f5a0837d0 100644 --- a/util/panic.c +++ b/util/panic.c @@ -1,10 +1,10 @@ -/* NetHack 3.6 panic.c $NHDT-Date: 1432512785 2015/05/25 00:13:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.6 panic.c $NHDT-Date: 1448210012 2015/11/22 16:33:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* - * This code was adapted from the code in end.c to run in a standalone - * mode for the makedefs / drg code. + * This code was adapted from the code in end.c to run in a standalone + * mode for the makedefs / drg code. */ #define NEED_VARARGS @@ -43,7 +43,6 @@ VA_DECL(char *, str) #endif VA_END(); exit(EXIT_FAILURE); /* redundant */ - return; } #ifdef ALLOCA_HACK