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.
This commit is contained in:
PatR
2022-06-21 12:52:29 -07:00
parent 3a0c1541dd
commit 27c287997b
4 changed files with 49 additions and 20 deletions

View File

@@ -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

View File

@@ -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)) {
/* 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) = TRUE;
#else
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);
#if 0
test_if_enabled(bl_engulfed) = u.uswallow ? TRUE : FALSE;
test_if_enabled(bl_held) = (!condtests[bl_grab].test
&& !condtests[bl_engulfed].test);
#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);
#endif
test_if_enabled(bl_held) = !condtests[bl_grab].test;
}
}
condtests[bl_blind].test = (Blind) ? TRUE : FALSE;

View File

@@ -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();

View File

@@ -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 <mon>" */
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];