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:
23
src/trap.c
23
src/trap.c
@@ -4095,17 +4095,23 @@ boolean
|
||||
lava_effects()
|
||||
{
|
||||
register struct obj *obj, *obj2;
|
||||
int dmg;
|
||||
int dmg = d(6, 6); /* only applicable for water walking */
|
||||
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();
|
||||
if (likes_lava(youmonst.data)) return FALSE;
|
||||
|
||||
if (!Fire_resistance) {
|
||||
if(Wwalking) {
|
||||
dmg = d(6,6);
|
||||
pline_The("lava here burns you!");
|
||||
if(dmg < u.uhp) {
|
||||
if (usurvive) {
|
||||
losehp(dmg, lava_killer, KILLED_BY); /* lava damage */
|
||||
goto burn_stuff;
|
||||
}
|
||||
@@ -4116,6 +4122,13 @@ lava_effects()
|
||||
#ifdef WIZARD
|
||||
if (wizard) usurvive = TRUE;
|
||||
#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) {
|
||||
obj2 = obj->nobj;
|
||||
if(is_organic(obj) && !obj->oerodeproof) {
|
||||
@@ -4130,7 +4143,7 @@ lava_effects()
|
||||
else if(obj == uarmg) (void) Gloves_off();
|
||||
else if(obj == uarmf) (void) Boots_off();
|
||||
#ifdef TOURIST
|
||||
else if(obj == uarmu) setnotworn(obj);
|
||||
else if(obj == uarmu) (void) Shirt_off();
|
||||
#endif
|
||||
else if(obj == uleft) Ring_gone(obj);
|
||||
else if(obj == uright) Ring_gone(obj);
|
||||
@@ -4144,6 +4157,8 @@ lava_effects()
|
||||
}
|
||||
}
|
||||
|
||||
context.in_lava_effects--;
|
||||
|
||||
/* s/he died... */
|
||||
u.uhp = -1;
|
||||
killer.format = KILLED_BY;
|
||||
|
||||
Reference in New Issue
Block a user