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:
@@ -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
|
||||
|
||||
31
src/botl.c
31
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)) {
|
||||
/* 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;
|
||||
|
||||
18
src/cmd.c
18
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();
|
||||
|
||||
14
src/zap.c
14
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 <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];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user