From b9f38fdd14bc0b49904a6e85869633ba8656ca22 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 16 Jan 2019 15:08:11 -0800 Subject: [PATCH] fix #H6285 - flooreffects and deltrap panic Reported 14 months ago, a monster reading a scroll of earth which dropped a boulder that killed another monster in an adjacent pit was giving credit/blame to the hero and could also trigger a panic. If the monster was killed, the pit would be filled and deleted via m_detach and then when flooreffects tried to delete the same trap, it accessed freed memory and deltrap could panic. --- doc/fixes36.2 | 4 +++- src/do.c | 60 +++++++++++++++++++++++++++++++++++++++------------ src/uhitm.c | 21 ++++++++++-------- 3 files changed, 61 insertions(+), 24 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index b63630534..d796f3260 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.229 $ $NHDT-Date: 1547421445 2019/01/13 23:17:25 $ +$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.230 $ $NHDT-Date: 1547680081 2019/01/16 23:08:01 $ This fixes36.2 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.1 in April 2018. Please note, however, @@ -335,6 +335,8 @@ entering Ft.Ludios with a lit candle lit up the entire entry room except for one corner spot; that corner is beyond candle radius but other spots even further away were being shown; force the walls to unlit in order to prevent those wall spots from showing so soon +boulder dropped or launched by a monster onto a monster trapped in a pit and + killing it credited/blamed the hero and might trigger a deltrap panic Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/do.c b/src/do.c index 3afac4ee6..e069c3ac6 100644 --- a/src/do.c +++ b/src/do.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do.c $NHDT-Date: 1547512513 2019/01/15 00:35:13 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.185 $ */ +/* NetHack 3.6 do.c $NHDT-Date: 1547680082 2019/01/16 23:08:02 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.186 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -139,6 +139,8 @@ const char *verb; struct trap *t; struct monst *mtmp; struct obj *otmp; + boolean tseen; + int ttyp = NO_TRAP; if (obj->where != OBJ_FREE) panic("flooreffects: obj not free"); @@ -150,18 +152,43 @@ const char *verb; return TRUE; } else if (obj->otyp == BOULDER && (t = t_at(x, y)) != 0 && (is_pit(t->ttyp) || is_hole(t->ttyp))) { + ttyp = t->ttyp; + tseen = t->tseen ? TRUE : FALSE; if (((mtmp = m_at(x, y)) && mtmp->mtrapped) || (u.utrap && u.ux == x && u.uy == y)) { - if (*verb) - pline_The("boulder %s into the pit%s.", - vtense((const char *) 0, verb), - (mtmp) ? "" : " with you"); + if (*verb && (cansee(x, y) || distu(x, y) == 0)) + pline("%s boulder %s into the pit%s.", + Blind ? "A" : "The", + vtense((const char *) 0, verb), + mtmp ? "" : " with you"); if (mtmp) { if (!passes_walls(mtmp->data) && !throws_rocks(mtmp->data)) { - int dieroll = rnd(20); + /* dieroll was rnd(20); 1: maximum chance to hit + since trapped target is a sitting duck */ + int damage, dieroll = 1; - if (hmon(mtmp, obj, HMON_THROWN, dieroll) - && !is_whirly(mtmp->data)) + /* 3.6.2: this was calling hmon() unconditionally + so always credited/blamed the hero but the boulder + might have been thrown by a giant or launched by + a rolling boulder trap triggered by a monster or + dropped by a scroll of earth read by a monster */ + if (context.mon_moving) { + /* normally we'd use ohitmon() but it can call + drop_throw() which calls flooreffects() */ + damage = dmgval(obj, mtmp); + mtmp->mhp -= damage; + if (DEADMONSTER(mtmp)) { + if (canspotmon(mtmp)) + pline("%s is %s!", Monnam(mtmp), + (nonliving(mtmp->data) + || is_vampshifter(mtmp)) + ? "destroyed" : "killed"); + mondied(mtmp); + } + } else { + (void) hmon(mtmp, obj, HMON_THROWN, dieroll); + } + if (!DEADMONSTER(mtmp) && !is_whirly(mtmp->data)) return FALSE; /* still alive */ } mtmp->mtrapped = 0; @@ -179,17 +206,22 @@ const char *verb; You_hear("a CRASH! beneath you."); } else if (!Blind && cansee(x, y)) { pline_The("boulder %s%s.", - (t->ttyp == TRAPDOOR && !t->tseen) - ? "triggers and " : "", - t->ttyp == TRAPDOOR + (ttyp == TRAPDOOR && !tseen) + ? "triggers and " : "", + (ttyp == TRAPDOOR) ? "plugs a trap door" - : t->ttyp == HOLE ? "plugs a hole" - : "fills a pit"); + : (ttyp == HOLE) ? "plugs a hole" + : "fills a pit"); } else { You_hear("a boulder %s.", verb); } } - deltrap(t); + /* + * Note: trap might have gone away via ((hmon -> killed -> xkilled) + * || mondied) -> mondead -> m_detach -> fill_pit. + */ + if ((t = t_at(x, y)) != 0) + deltrap(t); useupf(obj, 1L); bury_objs(x, y); newsym(x, y); diff --git a/src/uhitm.c b/src/uhitm.c index e0b8b5e99..986f9c3bd 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 uhitm.c $NHDT-Date: 1547118630 2019/01/10 11:10:30 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.198 $ */ +/* NetHack 3.6 uhitm.c $NHDT-Date: 1547680084 2019/01/16 23:08:04 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.199 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -923,13 +923,13 @@ int dieroll; break; #define useup_eggs(o) \ - { \ + do { \ if (thrown) \ obfree(o, (struct obj *) 0); \ else \ useupall(o); \ o = (struct obj *) 0; \ - } /* now gone */ + } while (0) /* now gone */ case EGG: { long cnt = obj->quan; @@ -963,10 +963,11 @@ int dieroll; break; return (boolean) (!DEADMONSTER(mon)); } else { /* ordinary egg(s) */ - const char *eggp = - (obj->corpsenm != NON_PM && obj->known) - ? the(mons[obj->corpsenm].mname) - : (cnt > 1L) ? "some" : "an"; + const char *eggp = (obj->corpsenm != NON_PM + && obj->known) + ? the(mons[obj->corpsenm].mname) + : (cnt > 1L) ? "some" : "an"; + You("hit %s with %s egg%s.", mon_nam(mon), eggp, plur(cnt)); if (touch_petrifies(mdat) && !stale_egg(obj)) { @@ -1001,7 +1002,7 @@ int dieroll; case BLINDING_VENOM: mon->msleeping = 0; if (can_blnd(&youmonst, mon, - (uchar) (obj->otyp == BLINDING_VENOM + (uchar) ((obj->otyp == BLINDING_VENOM) ? AT_SPIT : AT_WEAP), obj)) { @@ -1309,7 +1310,9 @@ int dieroll; if (unpoisonmsg) Strcpy(saved_oname, cxname(obj)); - /* [note: thrown obj might go away during killed/xkilled call] */ + /* [note: thrown obj might go away during killed()/xkilled() call + (via 'thrownobj'; if swallowed, it gets added to engulfer's + minvent and might merge with a stack that's already there)] */ if (needpoismsg) pline_The("poison doesn't seem to affect %s.", mon_nam(mon));