shapechanger dropping boulders

Something I noticed while looking over the recent report about hug
attacks.  If a monster carrying one or more boulders (picked up while
in giant form) polymorphs into a non-giant, it will drop them.  If
that happens while it's trapped, it could be killed.  newcham() would
use a stale pointer to continue traversing its inventory after it was
dead and its possessions had been dropped.

I managed to get a chameleon-as-giant carrying boulders and some other
stuff trapped in a bear trap and then transform, but the few attempts
I made never killed off its next form so I wasn't able to induce a
crash to verify that a problem would actually occur.
This commit is contained in:
PatR
2023-04-12 03:03:17 -07:00
parent 8b32ae98e9
commit 9718181322
2 changed files with 18 additions and 5 deletions
+13 -4
View File
@@ -1,4 +1,4 @@
/* NetHack 3.7 mon.c $NHDT-Date: 1679896593 2023/03/27 05:56:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.491 $ */
/* NetHack 3.7 mon.c $NHDT-Date: 1681293789 2023/04/12 10:03:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.494 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Derek S. Ray, 2015. */
/* NetHack may be freely redistributed. See license for details. */
@@ -4735,7 +4735,7 @@ newcham(
/* (this code used to try to adjust the monster's health based on
a normal one of its type but there are too many special cases
which need to handled in order to do that correctly, so just
which need to be handled in order to do that correctly, so just
give the new form the same proportion of HP as its old one had) */
hpn = mtmp->mhp;
hpd = mtmp->mhpmax;
@@ -4808,8 +4808,15 @@ newcham(
/* update swallow glyphs for new monster */
swallowed(0);
}
} else if (!sticks(mdat) && !sticks(gy.youmonst.data))
} else if ((!sticks(mdat) && !sticks(gy.youmonst.data))
/* sticky hero can't continue to hold mtmp if it has
turned into a non-solid creature; we don't use
uunstick() for that because its message would be
shown out of sequence [before 'if (msg)' below];
unstuck() doesn't issue any messages */
|| unsolid(mdat)) {
unstuck(mtmp);
}
}
if (mdat == &mons[PM_LONG_WORM] && (mtmp->wormno = get_wormno()) != 0) {
@@ -4856,7 +4863,9 @@ newcham(
if (mtmp->minvent && !throws_rocks(mdat)) {
register struct obj *otmp, *otmp2;
for (otmp = mtmp->minvent; otmp; otmp = otmp2) {
/* DEADMONSTER(): it is possible for flooreffects() to kill mtmp;
the rest of its inventory would be dropped making otmp2 stale */
for (otmp = mtmp->minvent; otmp && !DEADMONSTER(mtmp); otmp = otmp2) {
otmp2 = otmp->nobj;
if (otmp->otyp == BOULDER) {
/* this keeps otmp from being polymorphed in the