water vs acid

Fix the bug From a bug report.alt.org server, where killing a monster by closing the
castle drawbridge resulted in a panic after the dead monster's possessions
were dropped into the moat and a potion of acid exploded in the process.
water_damage() deleted the object but had no way to tell flooreffects()
that it was gone, so flooreffects() couldn't tell its own caller not to
place and stack the object.  After that, a chunk of freed memory became
part of the floor objects chain and eventually triggered a panic which
tried to make a save file but whose reason didn't get logged properly.
This commit is contained in:
nethack.rankin
2006-05-11 03:26:55 +00:00
parent 45b59990cd
commit a73d997034
7 changed files with 43 additions and 24 deletions

View File

@@ -217,6 +217,8 @@ properly handle destruction of equipment carried by monsters hit by
don't exercize or abuse wisdom when rumors get used for random graffiti don't exercize or abuse wisdom when rumors get used for random graffiti
create_object() created lizard corpses without timers and troll corpses with create_object() created lizard corpses without timers and troll corpses with
their revive timers, then changed the corpsenm field their revive timers, then changed the corpsenm field
when a potion of acid was dropped into water and exploded, nethack would
continue to use already freed memory and later might panic or crash
Platform- and/or Interface-Specific Fixes Platform- and/or Interface-Specific Fixes

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)extern.h 3.5 2004/06/12 */ /* SCCS Id: @(#)extern.h 3.5 2006/05/08 */
/* Copyright (c) Steve Creps, 1988. */ /* Copyright (c) Steve Creps, 1988. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -2173,7 +2173,7 @@ E void FDECL(fill_pit, (int,int));
E int FDECL(float_down, (long, long)); E int FDECL(float_down, (long, long));
E void NDECL(climb_pit); E void NDECL(climb_pit);
E int FDECL(fire_damage, (struct obj *,BOOLEAN_P,BOOLEAN_P,XCHAR_P,XCHAR_P)); E int FDECL(fire_damage, (struct obj *,BOOLEAN_P,BOOLEAN_P,XCHAR_P,XCHAR_P));
E void FDECL(water_damage, (struct obj *,BOOLEAN_P,BOOLEAN_P)); E void FDECL(water_damage, (struct obj **,BOOLEAN_P,BOOLEAN_P));
E boolean NDECL(drown); E boolean NDECL(drown);
E void FDECL(drain_en, (int)); E void FDECL(drain_en, (int));
E int NDECL(dountrap); E int NDECL(dountrap);

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)do.c 3.5 2006/03/20 */ /* SCCS Id: @(#)do.c 3.5 2006/05/08 */
/* 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. */
@@ -129,9 +129,9 @@ boolean pushing;
* away. * away.
*/ */
boolean boolean
flooreffects(obj,x,y,verb) flooreffects(obj, x, y, verb)
struct obj *obj; struct obj *obj;
int x,y; int x, y;
const char *verb; const char *verb;
{ {
struct trap *t; struct trap *t;
@@ -192,8 +192,8 @@ const char *verb;
return fire_damage(obj, FALSE, FALSE, x, y); return fire_damage(obj, FALSE, FALSE, x, y);
} else if (is_pool(x, y)) { } else if (is_pool(x, y)) {
/* Reasonably bulky objects (arbitrary) splash when dropped. /* Reasonably bulky objects (arbitrary) splash when dropped.
* If you're floating above the water even small things make noise. * If you're floating above the water even small things make
* Stuff dropped near fountains always misses */ * noise. Stuff dropped near fountains always misses */
if ((Blind || (Levitation || Flying)) && !Deaf && if ((Blind || (Levitation || Flying)) && !Deaf &&
((x == u.ux) && (y == u.uy))) { ((x == u.ux) && (y == u.uy))) {
if (!Underwater) { if (!Underwater) {
@@ -206,7 +206,8 @@ const char *verb;
map_background(x, y, 0); map_background(x, y, 0);
newsym(x, y); newsym(x, y);
} }
water_damage(obj, FALSE, FALSE); water_damage(&obj, FALSE, FALSE);
if (!obj) return TRUE;
} else if (u.ux == x && u.uy == y && } else if (u.ux == x && u.uy == y &&
(t = t_at(x,y)) != 0 && uteetering_at_seen_pit(t)) { (t = t_at(x,y)) != 0 && uteetering_at_seen_pit(t)) {
if (Blind && !Deaf) if (Blind && !Deaf)

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)fountain.c 3.5 2005/06/22 */ /* SCCS Id: @(#)fountain.c 3.5 2006/05/08 */
/* Copyright Scott R. Turner, srt@ucla, 10/27/86 */ /* Copyright Scott R. Turner, srt@ucla, 10/27/86 */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -125,7 +125,7 @@ genericptr_t poolcnt;
levl[x][y].typ = POOL; levl[x][y].typ = POOL;
/* No kelp! */ /* No kelp! */
del_engr_at(x, y); del_engr_at(x, y);
water_damage(level.objects[x][y], FALSE, TRUE); water_damage(&level.objects[x][y], FALSE, TRUE);
if ((mtmp = m_at(x, y)) != 0) if ((mtmp = m_at(x, y)) != 0)
(void) minliquid(mtmp); (void) minliquid(mtmp);

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)mon.c 3.5 2006/04/14 */ /* SCCS Id: @(#)mon.c 3.5 2006/05/08 */
/* 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. */
@@ -398,7 +398,7 @@ register struct monst *mtmp;
if (mtmp->data == &mons[PM_GREMLIN] && (inpool || infountain) && rn2(3)) { if (mtmp->data == &mons[PM_GREMLIN] && (inpool || infountain) && rn2(3)) {
if (split_mon(mtmp, (struct monst *)0)) if (split_mon(mtmp, (struct monst *)0))
dryup(mtmp->mx, mtmp->my, FALSE); dryup(mtmp->mx, mtmp->my, FALSE);
if (inpool) water_damage(mtmp->minvent, FALSE, FALSE); if (inpool) water_damage(&mtmp->minvent, FALSE, FALSE);
return (0); return (0);
} else if (mtmp->data == &mons[PM_IRON_GOLEM] && inpool && !rn2(5)) { } else if (mtmp->data == &mons[PM_IRON_GOLEM] && inpool && !rn2(5)) {
int dam = d(2,6); int dam = d(2,6);
@@ -410,7 +410,7 @@ register struct monst *mtmp;
mondead(mtmp); mondead(mtmp);
if (mtmp->mhp < 1) return (1); if (mtmp->mhp < 1) return (1);
} }
water_damage(mtmp->minvent, FALSE, FALSE); water_damage(&mtmp->minvent, FALSE, FALSE);
return (0); return (0);
} }
@@ -463,8 +463,8 @@ register struct monst *mtmp;
} }
mondead(mtmp); mondead(mtmp);
if (mtmp->mhp > 0) { if (mtmp->mhp > 0) {
water_damage(&mtmp->minvent, FALSE, FALSE);
(void) rloc(mtmp, FALSE); (void) rloc(mtmp, FALSE);
water_damage(mtmp->minvent, FALSE, FALSE);
return 0; return 0;
} }
return (1); return (1);

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)objnam.c 3.5 2006/04/14 */ /* SCCS Id: @(#)objnam.c 3.5 2006/05/08 */
/* 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. */
@@ -2583,7 +2583,7 @@ srch:
del_engr_at(u.ux, u.uy); del_engr_at(u.ux, u.uy);
pline("A pool."); pline("A pool.");
/* Must manually make kelp! */ /* Must manually make kelp! */
water_damage(level.objects[u.ux][u.uy], FALSE, TRUE); water_damage(&level.objects[u.ux][u.uy], FALSE, TRUE);
newsym(u.ux, u.uy); newsym(u.ux, u.uy);
return &zeroobj; return &zeroobj;
} }

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)trap.c 3.5 2006/04/14 */ /* SCCS Id: @(#)trap.c 3.5 2006/05/08 */
/* 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. */
@@ -2860,11 +2860,21 @@ xchar x, y;
} }
void void
water_damage(obj, force, here) water_damage(objp, force, here)
register struct obj *obj; struct obj **objp;
register boolean force, here; boolean force, here;
{ {
struct obj *otmp; register struct obj *obj = *objp, *otmp;
boolean loose_obj = (obj && obj->where == OBJ_FREE);
if (loose_obj && (obj->nobj || obj->nexthere)) {
/* [this should actually be a panic()] */
impossible("water_damage: loose object has%s%s%s list%s?",
obj->nobj ? " nobj" : "",
(obj->nobj && obj->nexthere) ? " and" : "",
obj->nexthere ? " nexthere" : "",
(obj->nobj && obj->nexthere) ? "s" : "");
}
/* Scrolls, spellbooks, potions, weapons and /* Scrolls, spellbooks, potions, weapons and
pieces of armor may get affected by the water */ pieces of armor may get affected by the water */
@@ -2879,7 +2889,7 @@ register boolean force, here;
if (force || !rn2(2)) obj->greased = 0; if (force || !rn2(2)) obj->greased = 0;
} else if(Is_container(obj) && !Is_box(obj) && } else if(Is_container(obj) && !Is_box(obj) &&
(obj->otyp != OILSKIN_SACK || (obj->cursed && !rn2(3)))) { (obj->otyp != OILSKIN_SACK || (obj->cursed && !rn2(3)))) {
water_damage(obj->cobj, force, FALSE); water_damage(&obj->cobj, force, FALSE);
} else if (!force && (Luck + 5) > rn2(20)) { } else if (!force && (Luck + 5) > rn2(20)) {
/* chance per item of sustaining damage: /* chance per item of sustaining damage:
* max luck (full moon): 5% * max luck (full moon): 5%
@@ -2902,8 +2912,14 @@ register boolean force, here;
else obj->otyp = SPE_BLANK_PAPER; else obj->otyp = SPE_BLANK_PAPER;
} else if (obj->oclass == POTION_CLASS) { } else if (obj->oclass == POTION_CLASS) {
if (obj->otyp == POT_ACID) { if (obj->otyp == POT_ACID) {
/* damage player/monster? */ /* [should we damage player/monster?] */
pline("A potion explodes!"); pline("A potion explodes!");
/* let caller know that obj has gone away
[when obj is part of a list, delobj()'s
obj_extract_self() takes care of this;
for loose_obj, obj should always equal
*objp and otmp should always be null] */
if (loose_obj && obj == *objp) *objp = otmp;
delobj(obj); delobj(obj);
continue; continue;
} else if (obj->odiluted) { } else if (obj->odiluted) {
@@ -3024,7 +3040,7 @@ drown()
Hallucination ? "the Titanic" : "a rock"); Hallucination ? "the Titanic" : "a rock");
} }
water_damage(invent, FALSE, FALSE); water_damage(&invent, FALSE, FALSE);
if (u.umonnum == PM_GREMLIN && rn2(3)) if (u.umonnum == PM_GREMLIN && rn2(3))
(void)split_mon(&youmonst, (struct monst *)0); (void)split_mon(&youmonst, (struct monst *)0);