stale lock picking context

Lock context wasn't being cleared if it was for a container and that
container got destroyed.  Case discovered was forcelock() ->
breakchestlock() -> delobj() (sometimes the container is destroyed
rather than just breaking its lock) followed by #wizmakemap (replace
current level) and maybe_reset_pick() trying to check whether
xlock.box was being carried.  But being interrupted, destroying the
container or dropping it down a hole to ship it to another level, then
attempting to resume picking the lock would also find a stale pointer.
This commit is contained in:
PatR
2019-01-31 15:50:12 -08:00
parent ed79141463
commit 8bf16b940e
6 changed files with 40 additions and 15 deletions

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 lock.c $NHDT-Date: 1547086531 2019/01/10 02:15:31 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.83 $ */
/* NetHack 3.6 lock.c $NHDT-Date: 1548978605 2019/01/31 23:50:05 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.84 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2011. */
/* NetHack may be freely redistributed. See license for details. */
@@ -253,10 +253,14 @@ forcelock(VOID_ARGS)
return 1; /* still busy */
You("succeed in forcing the lock.");
exercise(xlock.picktyp ? A_DEX : A_STR, TRUE);
/* breakchestlock() might destroy xlock.box; if so, xlock context will
be cleared (delobj -> obfree -> maybe_reset_pick); but it might not,
so explicitly clear that manually */
breakchestlock(xlock.box, (boolean) (!xlock.picktyp && !rn2(3)));
reset_pick(); /* lock-picking context is no longer valid */
exercise((xlock.picktyp) ? A_DEX : A_STR, TRUE);
return ((xlock.usedtime = 0));
return 0;
}
void
@@ -264,15 +268,28 @@ reset_pick()
{
xlock.usedtime = xlock.chance = xlock.picktyp = 0;
xlock.magic_key = FALSE;
xlock.door = 0;
xlock.box = 0;
xlock.door = (struct rm *) 0;
xlock.box = (struct obj *) 0;
}
/* level change; don't reset if hero is carrying xlock.box with him/her */
/* level change or object deletion; context may no longer be valid */
void
maybe_reset_pick()
maybe_reset_pick(container)
struct obj *container; /* passed from obfree() */
{
if (!xlock.box || !carried(xlock.box))
/*
* If a specific container, only clear context if it is for that
* particular container (which is being deleted). Other stuff on
* the current dungeon level remains valid.
* However if 'container' is Null, clear context if not carrying
* xlock.box (which might be Null if context is for a door).
* Used for changing levels, where a floor container or a door is
* being left behind and won't be valid on the new level but a
* carried container will still be. There might not be any context,
* in which case redundantly clearing it is harmless.
*/
if (container ? (container == xlock.box)
: (!xlock.box || !carried(xlock.box)))
reset_pick();
}