From 6a953231a3a4662f36449e28f10d3d6f7cd3bb55 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 31 Jan 2019 09:42:03 +0200 Subject: [PATCH 1/6] Silence sprintf format warnings and dehardcode buffer sizes --- util/makedefs.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/util/makedefs.c b/util/makedefs.c index daaecd61d..f83974d85 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -145,7 +145,9 @@ static char xclear[MAX_ROW][MAX_COL]; #endif /*-end of vision defs-*/ -static char filename[600]; +#define MAXFNAMELEN 600 + +static char filename[MAXFNAMELEN]; #ifdef FILE_PREFIX /* if defined, a first argument not starting with - is @@ -904,7 +906,7 @@ int *rumor_count; long *rumor_size; unsigned long old_rumor_offset; { - char infile[600]; + char infile[MAXFNAMELEN]; char *line; unsigned long rumor_offset; @@ -1003,7 +1005,7 @@ do_rumors() char *line; static const char rumors_header[] = "%s%04d,%06ld,%06lx;%04d,%06ld,%06lx;0,0,%06lx\n"; - char tempfile[600]; + char tempfile[MAXFNAMELEN]; int true_rumor_count, false_rumor_count; long true_rumor_size, false_rumor_size; unsigned long true_rumor_offset, false_rumor_offset, eof_offset; @@ -1046,7 +1048,7 @@ do_rumors() goto rumors_failure; /* get ready to transfer the contents of temp file to output file */ - line = malloc(256); + line = malloc(BUFSZ + MAXFNAMELEN); Sprintf(line, "rewind of \"%s\"", tempfile); if (rewind(tfp) != 0) { perror(line); @@ -1421,7 +1423,7 @@ char *githash, *gitbranch; { FILE *gifp; size_t len; - char infile[600]; + char infile[MAXFNAMELEN]; char *line, *strval, *opt, *c, *end; boolean havebranch = FALSE, havehash = FALSE; @@ -1479,7 +1481,7 @@ void do_fix_sampleconfig() { FILE *scfp, *ofcfp; - char fixedline[600]; + char fixedline[BUFSZ]; char *line; if (!(scfp = fopen(SAMPLE_CONFIGFILE, RDTMODE))) { @@ -1492,7 +1494,7 @@ do_fix_sampleconfig() /* read the sample config file */ while ((line = fgetline(scfp)) != 0) { /* comment out the STATUS_HILITES related lines */ - if (strlen(line) < (600 - 1)) { + if (strlen(line) < (BUFSZ - 1)) { if (strstr(line, "statushilites") || strstr(line, "hilite_status:")) { #ifdef FIX_SAMPLECONFIG fixedline[0] = '#'; @@ -1502,7 +1504,7 @@ do_fix_sampleconfig() #endif fputs(fixedline, ofcfp); } else { - fputs(line, ofcfp); + fputs(line, ofcfp); } } free(line); @@ -1983,7 +1985,7 @@ do_data() Fclose(ifp); /* all done with original input file */ /* reprocess the scratch file; 1st format an error msg, just in case */ - line = malloc(256); + line = malloc(BUFSZ + MAXFNAMELEN); Sprintf(line, "rewind of \"%s\"", tempfile); if (rewind(tfp) != 0) goto dead_data; @@ -1999,7 +2001,7 @@ do_data() Unlink(tempfile); /* remove it */ /* update the first record of the output file; prepare error msg 1st */ - line = malloc(256); + line = malloc(BUFSZ + MAXFNAMELEN); Sprintf(line, "rewind of \"%s\"", filename); ok = (rewind(ofp) == 0); if (ok) { @@ -2156,7 +2158,7 @@ do_oracles() Fclose(ifp); /* all done with original input file */ /* reprocess the scratch file; 1st format an error msg, just in case */ - line = malloc(256); + line = malloc(BUFSZ + MAXFNAMELEN); Sprintf(line, "rewind of \"%s\"", tempfile); if (rewind(tfp) != 0) goto dead_data; @@ -2172,7 +2174,7 @@ do_oracles() Unlink(tempfile); /* remove it */ /* update the first record of the output file; prepare error msg 1st */ - line = malloc(256); + line = malloc(BUFSZ + MAXFNAMELEN); Sprintf(line, "rewind of \"%s\"", filename); ok = (rewind(ofp) == 0); if (ok) { From 8736141f680ecb6f2acfa79377b7fef2351061a0 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 31 Jan 2019 10:46:41 +0200 Subject: [PATCH 2/6] Option handling return values and errors Fix some options not stopping when encountering an error, some didn't show up any errors, and other minor fixes. --- src/options.c | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/src/options.c b/src/options.c index 77d6d6338..b7ec363a2 100644 --- a/src/options.c +++ b/src/options.c @@ -3301,8 +3301,10 @@ boolean tinitial, tfrom_file; } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return FALSE; } - if (!assign_videocolors(opts)) /* TODO: error msg */ + if (!assign_videocolors(opts)) { + config_error_add("Unknown error handling '%s'", fullname); return FALSE; + } return retval; } /* videoshades:string */ @@ -3316,8 +3318,10 @@ boolean tinitial, tfrom_file; } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return FALSE; } - if (!assign_videoshades(opts)) /* TODO: error msg */ + if (!assign_videoshades(opts)) { + config_error_add("Unknown error handling '%s'", fullname); return FALSE; + } return retval; } #endif /* VIDEOSHADES */ @@ -3334,8 +3338,10 @@ boolean tinitial, tfrom_file; } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return FALSE; } - if (!assign_video(opts)) /* TODO: error msg */ + if (!assign_video(opts)) { + config_error_add("Unknown error handling '%s'", fullname); return FALSE; + } return retval; } #endif /* NO_TERMS */ @@ -3350,8 +3356,10 @@ boolean tinitial, tfrom_file; } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return FALSE; } - if (!assign_soundcard(opts)) /* TODO: error msg */ + if (!assign_soundcard(opts)) { + config_error_add("Unknown error handling '%s'", fullname); return FALSE; + } return retval; } #endif /* MSDOS */ @@ -3575,10 +3583,14 @@ boolean tinitial, tfrom_file; if (duplicate) complain_about_duplicate(opts, 1); if ((op = string_for_opt(opts, FALSE)) != 0) { - if (!wc_set_window_colors(op)) /* TODO: error msg*/ + if (!wc_set_window_colors(op)) { + config_error_add("Could not set %s '%s'", fullname, op); return FALSE; - } else if (negated) + } + } else if (negated) { bad_negation(fullname, TRUE); + return FALSE; + } return retval; } #ifdef CURSES_GRAPHICS @@ -3588,8 +3600,10 @@ boolean tinitial, tfrom_file; if (match_optname(opts, fullname, sizeof "term_cols" - 1, TRUE)) { op = string_for_opt(opts, negated); iflags.wc2_term_cols = atoi(op); - if (negated) - bad_negation(fullname, FALSE); + if (negated) { + bad_negation(fullname, FALSE); + return FALSE; + } return retval; } @@ -3599,8 +3613,10 @@ boolean tinitial, tfrom_file; if (match_optname(opts, fullname, sizeof "term_rows" - 1, TRUE)) { op = string_for_opt(opts, negated); iflags.wc2_term_rows = atoi(op); - if (negated) + if (negated) { bad_negation(fullname, FALSE); + return FALSE; + } return retval; } @@ -3612,16 +3628,20 @@ boolean tinitial, tfrom_file; if (op && !negated) { #ifdef CURSES_GRAPHICS iflags.wc2_petattr = curses_read_attrs(op); - if (!curses_read_attrs(op)) + if (!curses_read_attrs(op)) { config_error_add("Unknown %s parameter '%s'", fullname, opts); return FALSE; + } #else /* non-curses windowports will not use this flag anyway * but the above will not compile if we don't have curses. * Just set it to a sensible default: */ iflags.wc2_petattr = ATR_INVERSE #endif - } else if (negated) bad_negation(fullname, TRUE); + } else if (negated) { + bad_negation(fullname, TRUE); + return FALSE; + } return retval; } @@ -3630,9 +3650,10 @@ boolean tinitial, tfrom_file; fullname = "windowborders"; if (match_optname(opts, fullname, sizeof "windowborders" - 1, TRUE)) { op = string_for_opt(opts, negated); - if (negated && op) + if (negated && op) { bad_negation(fullname, TRUE); - else { + return FALSE; + } else { if (negated) iflags.wc2_windowborders = 2; /* Off */ else if (!op) @@ -3643,6 +3664,7 @@ boolean tinitial, tfrom_file; || (iflags.wc2_windowborders < 1)) { iflags.wc2_windowborders = 0; config_error_add("Badoption - windowborders %s.", opts); + return FALSE; } } return retval; From 48e76437391b202145b24e2d07dbd6cb3cdadccb Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 31 Jan 2019 04:22:04 -0800 Subject: [PATCH 3/6] fix monstone() ... dealloc_obj() panic Fuzzer feebdack. When turning a monster into a statue, monstone() builds a linked list of mon->minvent items to put into that statue. It doesn't use obj_extract_self() to take them off again, leaving obj->nobj non-Null. Not noticed for the normal case where each item gets linked into the container's contents, but triggers panic if an item merges with something already put inside so gets removed. Suddenly, the dungeon collapses. dealloc_obj with nobj [2] 0x01000c4193 panic + 995 [3] 0x0100155427 dealloc_obj + 71 [4] 0x010021d4de obfree + 686 [5] 0x01000f2f92 merged + 834 [6] 0x010015356e add_to_container + 126 [7] 0x01001628ac monstone + 636 I don't know why the petrified monster's mergeable inventory wasn't already merged while in inventory. --- doc/fixes36.2 | 4 +++- src/mon.c | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 945ac8f57..c5c37abea 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.239 $ $NHDT-Date: 1548695445 2019/01/28 17:10:45 $ +$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.241 $ $NHDT-Date: 1548937318 2019/01/31 12:21:58 $ 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, @@ -355,6 +355,8 @@ hero poly'd into creature with hug attack could hug a long worm's tail which smudging of an engraving has been relocated to after a succesful move and both your former location and your resulting location are subject to the smudging +monster with multiple items in inventory could trigger 'dealloc_obj with nobj' + panic when turned into a statue if separate mon->minvent items merged Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/mon.c b/src/mon.c index 570b95244..7ea70a576 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mon.c $NHDT-Date: 1548208236 2019/01/23 01:50:36 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.277 $ */ +/* NetHack 3.6 mon.c $NHDT-Date: 1548937318 2019/01/31 12:21:58 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.278 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2213,6 +2213,7 @@ struct monst *mdef; otmp = oname(otmp, MNAME(mdef)); while ((obj = oldminvent) != 0) { oldminvent = obj->nobj; + obj->nobj = 0; /* avoid merged-> obfree-> dealloc_obj-> panic */ (void) add_to_container(otmp, obj); } /* Archeologists should not break unique statues */ From c456b313a706363879a77fb3cda5f602e05ff69d Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 31 Jan 2019 13:03:00 -0500 Subject: [PATCH 4/6] Revert "adjust sample config file when STATUS_HILITES isn't defined" This reverts commit 03e6c26af6de62f6a970d5b0c9845f924bfc93f4. --- util/makedefs.c | 58 +------------------------------------------------ 1 file changed, 1 insertion(+), 57 deletions(-) diff --git a/util/makedefs.c b/util/makedefs.c index f83974d85..33cf3b2a5 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -111,15 +111,6 @@ static const char SCCS_Id[] UNUSED = "@(#)makedefs.c\t3.6\t2018/03/02"; #endif /* else !MAC */ #endif /* else !AMIGA */ -#if !defined(STATUS_HILITES) && defined(WIN32) -#define FIX_SAMPLECONFIG -#endif - -#ifdef WIN32 -#define SAMPLE_CONFIGFILE "../sys/winnt/defaults.nh" -#define FIXED_CONFIGFILE "./fixed_defaults.nh" -#endif - static const char *Dont_Edit_Code = "/* This source file is generated by 'makedefs'. Do not edit. */\n", @@ -173,9 +164,6 @@ void NDECL(do_questtxt); void NDECL(do_rumors); void NDECL(do_oracles); void NDECL(do_vision); -#ifdef WIN32 -void NDECL(do_fix_sampleconfig); -#endif extern void NDECL(monst_init); /* monst.c */ extern void NDECL(objects_init); /* objects.c */ @@ -378,12 +366,7 @@ char *options; case 'Z': do_vision(); break; -#ifdef WIN32 - case 'c': - case 'C': - do_fix_sampleconfig(); - break; -#endif + default: Fprintf(stderr, "Unknown option '%c'.\n", *options); (void) fflush(stderr); @@ -1476,45 +1459,6 @@ char *githash, *gitbranch; return FALSE; } -#ifdef WIN32 -void -do_fix_sampleconfig() -{ - FILE *scfp, *ofcfp; - char fixedline[BUFSZ]; - char *line; - - if (!(scfp = fopen(SAMPLE_CONFIGFILE, RDTMODE))) { - return; - } - if (!(ofcfp = fopen(FIXED_CONFIGFILE, WRTMODE))) { - return; - } - - /* read the sample config file */ - while ((line = fgetline(scfp)) != 0) { - /* comment out the STATUS_HILITES related lines */ - if (strlen(line) < (BUFSZ - 1)) { - if (strstr(line, "statushilites") || strstr(line, "hilite_status:")) { -#ifdef FIX_SAMPLECONFIG - fixedline[0] = '#'; - Strcpy(&fixedline[1], line); -#else - Strcpy(fixedline, line); -#endif - fputs(fixedline, ofcfp); - } else { - fputs(line, ofcfp); - } - } - free(line); - } - Fclose(scfp); - Fclose(ofcfp); - return; -} -#endif /* WIN32 */ - static int case_insensitive_comp(s1, s2) const char *s1; From 7bbc1f0130ce88456d611f84041a55b53f433310 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 31 Jan 2019 21:31:26 +0200 Subject: [PATCH 5/6] Fix warning Fix "using integer constants in boolean context" --- src/botl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/botl.c b/src/botl.c index d8244734d..a527f6406 100644 --- a/src/botl.c +++ b/src/botl.c @@ -3069,8 +3069,8 @@ choose_value: op, aval.a_int, is_out_of_range); goto choose_value; } else if (dt == ANY_LONG - && (aval.a_long < (lt_gt_eq == GT_VALUE) ? -1L - : (lt_gt_eq == LT_VALUE) ? 1L : 0L)) { + && (aval.a_long < ((lt_gt_eq == GT_VALUE) ? -1L + : (lt_gt_eq == LT_VALUE) ? 1L : 0L))) { pline("%s'%s%ld'%s", threshold_value, op, aval.a_long, is_out_of_range); goto choose_value; From 8bf16b940e15cac75cea2a4de92738c90fa71688 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 31 Jan 2019 15:50:12 -0800 Subject: [PATCH 6/6] 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. --- doc/fixes36.2 | 4 +++- src/cmd.c | 4 ++-- src/do.c | 4 ++-- src/lock.c | 33 +++++++++++++++++++++++++-------- src/mkobj.c | 6 +++++- src/shk.c | 4 +++- 6 files changed, 40 insertions(+), 15 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index c5c37abea..1c5b9edfa 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.241 $ $NHDT-Date: 1548937318 2019/01/31 12:21:58 $ +$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.242 $ $NHDT-Date: 1548978603 2019/01/31 23:50:03 $ 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, @@ -357,6 +357,8 @@ smudging of an engraving has been relocated to after a succesful move subject to the smudging monster with multiple items in inventory could trigger 'dealloc_obj with nobj' panic when turned into a statue if separate mon->minvent items merged +lock picking context could end up with stale container pointer if container + being forced/unlocked/locked got destroyed or sent to another level Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/cmd.c b/src/cmd.c index 75319f5e5..5b77eb1a4 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 cmd.c $NHDT-Date: 1547512504 2019/01/15 00:35:04 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.328 $ */ +/* NetHack 3.6 cmd.c $NHDT-Date: 1548978603 2019/01/31 23:50:03 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.330 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -823,7 +823,7 @@ wiz_makemap(VOID_ARGS) unplacebc(); } /* reset lock picking unless it's for a carried container */ - maybe_reset_pick(); + maybe_reset_pick((struct obj *) 0); /* reset interrupted digging if it was taking place on this level */ if (on_level(&context.digging.level, &u.uz)) (void) memset((genericptr_t) &context.digging, 0, diff --git a/src/do.c b/src/do.c index 7467356c7..20aadf751 100644 --- a/src/do.c +++ b/src/do.c @@ -1,4 +1,4 @@ -/* 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 $ */ +/* NetHack 3.6 do.c $NHDT-Date: 1548978604 2019/01/31 23:50:04 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.189 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1322,7 +1322,7 @@ boolean at_stairs, falling, portal; for lock-picking, container may be carried, in which case we keep context; if on the floor, it's about to be saved+freed and maybe_reset_pick() needs to do its carried() check before that */ - maybe_reset_pick(); + maybe_reset_pick((struct obj *) 0); reset_trapset(); /* even if to-be-armed trap obj is accompanying hero */ iflags.travelcc.x = iflags.travelcc.y = 0; /* travel destination cache */ context.polearm.hitmon = (struct monst *) 0; /* polearm target */ diff --git a/src/lock.c b/src/lock.c index 0f4c4dbff..3e2337351 100644 --- a/src/lock.c +++ b/src/lock.c @@ -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(); } diff --git a/src/mkobj.c b/src/mkobj.c index 0c6b960ca..195de0b4a 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mkobj.c $NHDT-Date: 1547086532 2019/01/10 02:15:32 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.141 $ */ +/* NetHack 3.6 mkobj.c $NHDT-Date: 1548978605 2019/01/31 23:50:05 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.142 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2076,6 +2076,10 @@ struct obj *obj; if (obj->where != OBJ_FREE) panic("add_to_migration: obj not free"); + /* lock picking context becomes stale if it's for this object */ + if (Is_container(obj)) + maybe_reset_pick(obj); + obj->where = OBJ_MIGRATING; obj->nobj = migrating_objs; migrating_objs = obj; diff --git a/src/shk.c b/src/shk.c index 154924550..09892e709 100644 --- a/src/shk.c +++ b/src/shk.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 shk.c $NHDT-Date: 1547849604 2019/01/18 22:13:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.153 $ */ +/* NetHack 3.6 shk.c $NHDT-Date: 1548978606 2019/01/31 23:50:06 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.154 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -912,6 +912,8 @@ register struct obj *obj, *merge; book_disappears(obj); if (Has_contents(obj)) delete_contents(obj); + if (Is_container(obj)) + maybe_reset_pick(obj); shkp = 0; if (obj->unpaid) {