From: PatR Date: Tue, 21 Jun 2022 19:52:29 +0000 (-0700) Subject: tentative fix for #K3626 - segfault when swallowed X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=27c287997b34f1ab8121cab6e9f099036e7db048;p=nethack tentative fix for #K3626 - segfault when swallowed release_hold() checked for (Upolyd && sticks(g.youmonst.data)) before checking for (u.uswallow) and it could set u.ustuck to Null while u.uswallow remained set to 1. dmove_core() was accessing u.ustuck->mx and u.ustuck->my after that, resulting in a crash. This fixes that particular case but there might be others that also assume sticky poly'd hero should be handled before swallowed hero. Being swallowed/engulfed needs to be handled first. --- diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 81f06cce1..c0240e8ce 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -928,6 +928,12 @@ ball and chain could be accessed after having been freed if bones were saved early post-3.4.3 tried to fix the "naming artifacts trick" which could be used to distinguish the type of some undiscovered items, but using a name that only matched an artifact after capitalization was exploitable +the u.ustuck hierarchy is: swallowed by ustuck, hero poly'd into sticky form + is holding ustuck even if ustuck is sticky, ustuck is holding hero; + but some code assumed that the first two cases were reversed and + could make formerly sticky pold'd hero clear ustuck, leaving hero + swallowed by nothing (u.uswallow==1 with u.ustuck==NULL); that could + cause a crash if u.ustuck got dereferenced Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/src/botl.c b/src/botl.c index 5a79f6e3f..5d97eff97 100644 --- a/src/botl.c +++ b/src/botl.c @@ -887,23 +887,30 @@ bot_via_windowport(void) && !condtests[bl_tethered].test); } condtests[bl_grab].test = condtests[bl_held].test +#if 0 + = condtests[bl_engulfed].test +#endif = condtests[bl_holding].test = FALSE; if (u.ustuck) { - if (Upolyd && sticks(g.youmonst.data)) { - test_if_enabled(bl_holding) = TRUE; - } else { - test_if_enabled(bl_grab) = (u.ustuck->data->mlet == S_EEL); + /* it is possible for a hero in sticks() form to be swallowed, + so swallowed needs to be checked first; it is not possible for + a hero in sticks() form to be held--sticky hero does the holding + even if u.ustuck is also a holder */ + if (u.uswallow) { + /* engulfed/swallowed isn't currently a tracked status condition; + "held" might look odd for it but seems better than blank */ #if 0 - test_if_enabled(bl_engulfed) = u.uswallow ? TRUE : FALSE; - test_if_enabled(bl_held) = (!condtests[bl_grab].test - && !condtests[bl_engulfed].test); + test_if_enabled(bl_engulfed) = TRUE; #else - test_if_enabled(bl_held) = (!condtests[bl_grab].test - /* engulfed/swallowed isn't currently a tracked condition - and showing "held" when in that state looks a bit odd, - so suppress "held" if swallowed */ - && !u.uswallow); + test_if_enabled(bl_held) = TRUE; #endif + } else if (Upolyd && sticks(g.youmonst.data)) { + test_if_enabled(bl_holding) = TRUE; + } else { + /* grab == hero is held by sea monster and about to be drowned; + held == hero is held by something else and can't move away */ + test_if_enabled(bl_grab) = (u.ustuck->data->mlet == S_EEL); + test_if_enabled(bl_held) = !condtests[bl_grab].test; } } condtests[bl_blind].test = (Blind) ? TRUE : FALSE; diff --git a/src/cmd.c b/src/cmd.c index 293c611e2..73d175105 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -146,6 +146,7 @@ static void mon_chain(winid, const char *, struct monst *, boolean, long *, long *); static void contained_stats(winid, const char *, long *, long *); static void misc_stats(winid, long *, long *); +static void you_sanity_check(void); static boolean accept_menu_prefix(const struct ext_func_tab *); static void reset_cmd_vars(boolean); static void mcmd_addmenu(winid, int, const char *); @@ -3630,10 +3631,25 @@ wiz_show_stats(void) RESTORE_WARNING_FORMAT_NONLITERAL +static void +you_sanity_check(void) +{ + if (u.uswallow && !u.ustuck) { + /* this probably ought to be panic() */ + impossible("sanity_check: swallowed by nothing?"); + display_nhwindow(WIN_MESSAGE, TRUE); + /* try to recover from whatever the problem is */ + u.uswallow = 0; + u.uswldtim = 0; + docrt(); + } + (void) check_invent_gold("invent"); +} + void sanity_check(void) { - (void) check_invent_gold("invent"); + you_sanity_check(); obj_sanity_check(); timer_sanity_check(); mon_sanity_check(); diff --git a/src/zap.c b/src/zap.c index 52a0558e2..095e852dc 100644 --- a/src/zap.c +++ b/src/zap.c @@ -489,13 +489,7 @@ release_hold(void) if (!mtmp) { impossible("release_hold when not held?"); - } else if (sticks(g.youmonst.data)) { - /* order matters if 'holding' status condition is enabled; - set_ustuck() will set flag for botl update, You() pline will - trigger a status update with "UHold" removed */ - set_ustuck((struct monst *) 0); - You("release %s.", mon_nam(mtmp)); - } else if (u.uswallow) { + } else if (u.uswallow) { /* possible for sticky hero to be swallowed */ if (is_animal(mtmp->data)) { if (!Blind) pline("%s opens its mouth!", Monnam(mtmp)); @@ -504,6 +498,12 @@ release_hold(void) } /* gives "you get regurgitated" or "you get expelled from " */ expels(mtmp, mtmp->data, TRUE); + } else if (sticks(g.youmonst.data)) { + /* order matters if 'holding' status condition is enabled; + set_ustuck() will set flag for botl update, You() pline will + trigger a status update with "UHold" removed */ + set_ustuck((struct monst *) 0); + You("release %s.", mon_nam(mtmp)); } else { /* held but not swallowed */ char relbuf[BUFSZ];