fix object lost panic (trunc only)

While testing some killer_xname() changes, I noticed that it was
feasible to avoid having some gear destroyed by causing a hangup after
getting the destruction message.  And while testing the fix for that, I
stumbled across a panic situation (not caused by my changes).  If you
survive entering lava while wearing water walking boots (and aren't fire
resistant yourself, and don't have enough hit points to survive 6d6
damage, and your boots aren't fireproofed...), having those boots be
destroyed will dump you back into the same lava recursively (lava_effects
-> Boots_off -> spoteffects -> lava_effects).  And if you survive that
(wizard/explore mode or life-saving), there will be a panic when finishing
deletion of the boots (useupall) because the recursive call will have
already done it (since they aren't worn anymore when inner call handles
them, no additional recursion gets triggered and object deletion happens).

     Some of the other stuff I was working on is mixed in here because
this is the configuration I ended up using to test the panic fix.

     Several Makefiles are missing the dependency for context.h (post-3.4.3
revision).  If yours is, then you'll need to force a full rebuild after
applying this or you'll end up with havoc.  (Mine was, but I noticed that
the expected full build wasn't happening and interrupted it to fix that.)
This commit is contained in:
nethack.rankin
2005-12-08 05:45:43 +00:00
parent 6a40b203ed
commit baff3bc88b
5 changed files with 72 additions and 37 deletions

View File

@@ -167,6 +167,8 @@ a samurai quest guardian message used "ninja" where "ronin" was intended
revive from fainting if vault guard or bribe-demanding demon approaches revive from fainting if vault guard or bribe-demanding demon approaches
tame flaming spheres and shocking spheres shouldn't pick up items tame flaming spheres and shocking spheres shouldn't pick up items
can hear the opening or closing of an unseen drawbridge can hear the opening or closing of an unseen drawbridge
prevent "object lost" panic caused by accessing freed memory after worn
non-fireproof water walking boots are destroyed by lava
Platform- and/or Interface-Specific Fixes Platform- and/or Interface-Specific Fixes

View File

@@ -80,6 +80,7 @@ struct context_info {
/* 8: travel */ /* 8: travel */
unsigned startingpet_mid; unsigned startingpet_mid;
int warnlevel; int warnlevel;
int in_lava_effects; /* hack for Boots_off() */
long next_attrib_check; /* next attribute check */ long next_attrib_check; /* next attribute check */
long stethoscope_move; long stethoscope_move;
short stethoscope_movement; short stethoscope_movement;

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)do_wear.c 3.5 2004/11/11 */ /* SCCS Id: @(#)do_wear.c 3.5 2005/12/07 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -35,6 +35,7 @@ STATIC_PTR int NDECL(Boots_on);
STATIC_DCL int NDECL(Cloak_on); STATIC_DCL int NDECL(Cloak_on);
STATIC_PTR int NDECL(Helmet_on); STATIC_PTR int NDECL(Helmet_on);
STATIC_PTR int NDECL(Gloves_on); STATIC_PTR int NDECL(Gloves_on);
STATIC_DCL void FDECL(wielding_corpse, (struct obj *,BOOLEAN_P));
STATIC_PTR int NDECL(Shield_on); STATIC_PTR int NDECL(Shield_on);
#ifdef TOURIST #ifdef TOURIST
STATIC_PTR int NDECL(Shirt_on); STATIC_PTR int NDECL(Shirt_on);
@@ -151,7 +152,9 @@ Boots_off()
/* check for lava since fireproofed boots make it viable */ /* check for lava since fireproofed boots make it viable */
if ((is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) && if ((is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) &&
!Levitation && !Flying && !is_clinger(youmonst.data) && !Levitation && !Flying && !is_clinger(youmonst.data) &&
!context.takeoff.cancelled_don) { !context.takeoff.cancelled_don &&
/* avoid recursive call to lava_effects() */
!context.in_lava_effects) {
/* make boots known in case you survive the drowning */ /* make boots known in case you survive the drowning */
makeknown(otyp); makeknown(otyp);
spoteffects(TRUE); spoteffects(TRUE);
@@ -407,6 +410,29 @@ Gloves_on()
return 0; return 0;
} }
STATIC_OVL void
wielding_corpse(obj, voluntary)
struct obj *obj;
boolean voluntary; /* taking gloves off on purpose? */
{
char kbuf[BUFSZ];
if (!obj || obj->otyp != CORPSE) return;
if (obj != uwep && (obj != uswapwep || !u.twoweap)) return;
if (touch_petrifies(&mons[obj->corpsenm]) && !Stone_resistance) {
You("now wield %s in your bare %s.",
the(corpse_xname(obj, TRUE)),
makeplural(body_part(HAND)));
Sprintf(kbuf, "%s gloves while wielding %s",
voluntary ? "removing" : "losing",
killer_xname(obj));
instapetrify(kbuf);
/* life-saved; can't continue wielding cockatrice corpse though */
remove_worn_item(obj, FALSE);
}
}
int int
Gloves_off() Gloves_off()
{ {
@@ -414,6 +440,7 @@ Gloves_off()
u.uprops[objects[uarmg->otyp].oc_oprop].extrinsic & ~WORN_GLOVES; u.uprops[objects[uarmg->otyp].oc_oprop].extrinsic & ~WORN_GLOVES;
context.takeoff.mask &= ~W_ARMG; context.takeoff.mask &= ~W_ARMG;
boolean on_purpose = !context.mon_moving && !uarmg->in_use;
switch(uarmg->otyp) { switch(uarmg->otyp) {
case LEATHER_GLOVES: case LEATHER_GLOVES:
@@ -435,30 +462,15 @@ Gloves_off()
context.takeoff.cancelled_don = FALSE; context.takeoff.cancelled_don = FALSE;
(void) encumber_msg(); /* immediate feedback for GoP */ (void) encumber_msg(); /* immediate feedback for GoP */
/* Prevent wielding cockatrice when not wearing gloves */ /* prevent wielding cockatrice when not wearing gloves */
if (uwep && uwep->otyp == CORPSE && if (uwep && uwep->otyp == CORPSE)
touch_petrifies(&mons[uwep->corpsenm])) { wielding_corpse(uwep, on_purpose);
char kbuf[BUFSZ];
You("wield the %s in your bare %s.", /* KMH -- ...or your secondary weapon when you're wielding it
corpse_xname(uwep, TRUE), makeplural(body_part(HAND))); [This case can't actually happen; twoweapon mode won't
Strcpy(kbuf, an(corpse_xname(uwep, TRUE))); engage if a corpse has been set up as the alternate weapon.] */
instapetrify(kbuf); if (u.twoweap && uswapwep && uswapwep->otyp == CORPSE)
uwepgone(); /* life-saved still doesn't allow touching cockatrice */ wielding_corpse(uswapwep, on_purpose);
}
/* KMH -- ...or your secondary weapon when you're wielding it */
if (u.twoweap && uswapwep && uswapwep->otyp == CORPSE &&
touch_petrifies(&mons[uswapwep->corpsenm])) {
char kbuf[BUFSZ];
You("wield the %s in your bare %s.",
corpse_xname(uswapwep, TRUE), body_part(HAND));
Strcpy(kbuf, an(corpse_xname(uswapwep, TRUE)));
instapetrify(kbuf);
uswapwepgone(); /* lifesaved still doesn't allow touching cockatrice */
}
return 0; return 0;
} }
@@ -2127,7 +2139,8 @@ register struct obj *atmp;
register struct obj *otmp; register struct obj *otmp;
#define DESTROY_ARM(o) ((otmp = (o)) != 0 && \ #define DESTROY_ARM(o) ((otmp = (o)) != 0 && \
(!atmp || atmp == otmp) && \ (!atmp || atmp == otmp) && \
(!obj_resists(otmp, 0, 90))) (!obj_resists(otmp, 0, 90)) ? \
(otmp->in_use = TRUE) : FALSE)
if (DESTROY_ARM(uarmc)) { if (DESTROY_ARM(uarmc)) {
if (donning(otmp)) cancel_don(); if (donning(otmp)) cancel_don();

View File

@@ -729,19 +729,23 @@ struct obj *sobj;
/* KMH -- catch underflow */ /* KMH -- catch underflow */
s = sobj->cursed ? -otmp->spe : otmp->spe; s = sobj->cursed ? -otmp->spe : otmp->spe;
if (s > (special_armor ? 5 : 3) && rn2(s)) { if (s > (special_armor ? 5 : 3) && rn2(s)) {
pline("%s violently %s%s%s for a while, then %s.", otmp->in_use = TRUE;
Yname2(otmp), pline("%s violently %s%s%s for a while, then %s.",
otense(otmp, Blind ? "vibrate" : "glow"), Yname2(otmp),
(!Blind && !same_color) ? " " : nul, otense(otmp, Blind ? "vibrate" : "glow"),
(Blind || same_color) ? nul : (!Blind && !same_color) ? " " : nul,
hcolor(sobj->cursed ? NH_BLACK : NH_SILVER), (Blind || same_color) ? nul :
otense(otmp, "evaporate")); hcolor(sobj->cursed ? NH_BLACK : NH_SILVER),
otense(otmp, "evaporate"));
if(is_cloak(otmp)) (void) Cloak_off(); if(is_cloak(otmp)) (void) Cloak_off();
if(is_boots(otmp)) (void) Boots_off(); if(is_boots(otmp)) (void) Boots_off();
if(is_helmet(otmp)) (void) Helmet_off(); if(is_helmet(otmp)) (void) Helmet_off();
if(is_gloves(otmp)) (void) Gloves_off(); if(is_gloves(otmp)) (void) Gloves_off();
if(is_shield(otmp)) (void) Shield_off(); if(is_shield(otmp)) (void) Shield_off();
if(otmp == uarm) (void) Armor_gone(); if(otmp == uarm) (void) Armor_gone();
#ifdef TOURIST
if (is_shirt(otmp)) (void) Shirt_off();
#endif
useup(otmp); useup(otmp);
break; break;
} }

View File

@@ -4095,17 +4095,23 @@ boolean
lava_effects() lava_effects()
{ {
register struct obj *obj, *obj2; register struct obj *obj, *obj2;
int dmg; int dmg = d(6, 6); /* only applicable for water walking */
boolean usurvive; boolean usurvive;
usurvive = Fire_resistance || (Wwalking && dmg < u.uhp);
/* a timely interrupt might manage to salvage your life
but not your gear; do this before messages */
if (!usurvive)
for (obj = invent; obj; obj = obj->nobj)
if (is_organic(obj) && !obj->oerodeproof) obj->in_use = TRUE;
burn_away_slime(); burn_away_slime();
if (likes_lava(youmonst.data)) return FALSE; if (likes_lava(youmonst.data)) return FALSE;
if (!Fire_resistance) { if (!Fire_resistance) {
if(Wwalking) { if(Wwalking) {
dmg = d(6,6);
pline_The("lava here burns you!"); pline_The("lava here burns you!");
if(dmg < u.uhp) { if (usurvive) {
losehp(dmg, lava_killer, KILLED_BY); /* lava damage */ losehp(dmg, lava_killer, KILLED_BY); /* lava damage */
goto burn_stuff; goto burn_stuff;
} }
@@ -4116,6 +4122,13 @@ lava_effects()
#ifdef WIZARD #ifdef WIZARD
if (wizard) usurvive = TRUE; if (wizard) usurvive = TRUE;
#endif #endif
/* prevent Boots_off() -> spoteffects() -> lava_effects() recursion
which would successfully delete (via useupall) the no-longer-worn
boots; once recursive call returned, we would try to delete them
again here in the outer call (access stale memory, probably panic) */
context.in_lava_effects++;
for(obj = invent; obj; obj = obj2) { for(obj = invent; obj; obj = obj2) {
obj2 = obj->nobj; obj2 = obj->nobj;
if(is_organic(obj) && !obj->oerodeproof) { if(is_organic(obj) && !obj->oerodeproof) {
@@ -4130,7 +4143,7 @@ lava_effects()
else if(obj == uarmg) (void) Gloves_off(); else if(obj == uarmg) (void) Gloves_off();
else if(obj == uarmf) (void) Boots_off(); else if(obj == uarmf) (void) Boots_off();
#ifdef TOURIST #ifdef TOURIST
else if(obj == uarmu) setnotworn(obj); else if(obj == uarmu) (void) Shirt_off();
#endif #endif
else if(obj == uleft) Ring_gone(obj); else if(obj == uleft) Ring_gone(obj);
else if(obj == uright) Ring_gone(obj); else if(obj == uright) Ring_gone(obj);
@@ -4144,6 +4157,8 @@ lava_effects()
} }
} }
context.in_lava_effects--;
/* s/he died... */ /* s/he died... */
u.uhp = -1; u.uhp = -1;
killer.format = KILLED_BY; killer.format = KILLED_BY;