From 378648bd9c1e851477d05471f2194d55ee40096c Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 31 Jan 2024 12:51:33 -0500 Subject: [PATCH] fix crash on NULL gi.invent --- include/extern.h | 2 +- src/files.c | 2 +- src/invent.c | 44 +++++++++++++++++++++++--------------------- src/pickup.c | 4 ++-- src/shk.c | 2 +- src/uhitm.c | 2 +- 6 files changed, 29 insertions(+), 27 deletions(-) diff --git a/include/extern.h b/include/extern.h index 8a8bfce3f..34e9fe65c 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1239,7 +1239,7 @@ extern Loot *sortloot(struct obj **, unsigned, boolean, boolean(*)(struct obj *)) NONNULLARG1; extern void unsortloot(Loot **) NONNULLARG1; extern void assigninvlet(struct obj *) NONNULLARG1; -extern struct obj *merge_choice(struct obj *, struct obj *) NONNULLPTRS; +extern struct obj *merge_choice(struct obj **, struct obj *) NONNULLPTRS; extern int merged(struct obj **, struct obj **) NONNULLPTRS; extern void addinv_core1(struct obj *) NONNULLARG1; extern void addinv_core2(struct obj *) NONNULLARG1; diff --git a/src/files.c b/src/files.c index c3956deaa..09e1a1039 100644 --- a/src/files.c +++ b/src/files.c @@ -3885,7 +3885,7 @@ wizkit_addinv(struct obj *obj) obj->bknown = 1; /* ok to bypass set_bknown() */ /* same criteria as lift_object()'s check for available inventory slot */ if (obj->oclass != COIN_CLASS && inv_cnt(FALSE) >= invlet_basic - && !merge_choice(gi.invent, obj)) { + && !merge_choice(&gi.invent, obj)) { /* inventory overflow; can't just place & stack object since hero isn't in position yet, so schedule for arrival later */ add_to_migration(obj); diff --git a/src/invent.c b/src/invent.c index 20a7cf645..454573410 100644 --- a/src/invent.c +++ b/src/invent.c @@ -781,10 +781,11 @@ reorder_invent(void) one of them; used in pickup.c when all 52 inventory slots are in use, to figure out whether another object could still be picked up */ struct obj * -merge_choice(struct obj *objlist, struct obj *obj) +merge_choice(struct obj **objlist, struct obj *obj) { struct monst *shkp; unsigned save_nocharge; + struct obj *olist = *objlist; if (obj->otyp == SCR_SCARE_MONSTER) /* punt on these */ return (struct obj *) 0; @@ -792,28 +793,29 @@ merge_choice(struct obj *objlist, struct obj *obj) have when carried are different from what they are now; prevent that from eliciting an incorrect result from mergable() */ save_nocharge = obj->no_charge; - if (objlist == gi.invent && obj->where == OBJ_FLOOR - && (shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) { - if (obj->no_charge) - obj->no_charge = 0; - /* A billable object won't have its `unpaid' bit set, so would - erroneously seem to be a candidate to merge with a similar - ordinary object. That's no good, because once it's really - picked up, it won't merge after all. It might merge with - another unpaid object, but we can't check that here (depends - too much upon shk's bill) and if it doesn't merge it would - end up in the '#' overflow inventory slot, so reject it now. */ - else if (inhishop(shkp)) - return (struct obj *) 0; + if (olist) { + if (olist == gi.invent && obj->where == OBJ_FLOOR + && (shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) { + if (obj->no_charge) + obj->no_charge = 0; + /* A billable object won't have its `unpaid' bit set, so would + erroneously seem to be a candidate to merge with a similar + ordinary object. That's no good, because once it's really + picked up, it won't merge after all. It might merge with + another unpaid object, but we can't check that here (depends + too much upon shk's bill) and if it doesn't merge it would + end up in the '#' overflow inventory slot, so reject it now. */ + else if (inhishop(shkp)) + return (struct obj *) 0; + } + do { + if (mergable(olist, obj)) + break; + olist = olist->nobj; + } while (olist); } - do { - /*assert(objlist != NULL);*/ - if (mergable(objlist, obj)) - break; - objlist = objlist->nobj; - } while (objlist); obj->no_charge = save_nocharge; - return objlist; + return olist; } /* merge obj with otmp and delete obj if types agree */ diff --git a/src/pickup.c b/src/pickup.c index 33af16001..bd155f4fb 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1699,7 +1699,7 @@ lift_object( if (obj->otyp == LOADSTONE || (obj->otyp == BOULDER && throws_rocks(gy.youmonst.data))) { if (inv_cnt(FALSE) < invlet_basic || !carrying(obj->otyp) - || merge_choice(gi.invent, obj)) + || merge_choice(&gi.invent, obj)) return 1; /* lift regardless of current situation */ /* if we reach here, we're out of slots and already have at least one of these, so treat this one more like a normal item @@ -1719,7 +1719,7 @@ lift_object( /* [exception for gold coins will have to change if silver/copper ones ever get implemented] */ && inv_cnt(FALSE) >= invlet_basic - && !merge_choice(gi.invent, obj)) { + && !merge_choice(&gi.invent, obj)) { /* if there is some gold here (and we haven't already skipped it), we aren't limited by the 52 item limit for it, but caller and "grandcaller" aren't prepared to skip stuff and then pickup diff --git a/src/shk.c b/src/shk.c index a2dc796aa..c227a6dc2 100644 --- a/src/shk.c +++ b/src/shk.c @@ -152,7 +152,7 @@ money2u(struct monst* mon, long amount) mongold = splitobj(mongold, amount); obj_extract_self(mongold); - if (!merge_choice(gi.invent, mongold) + if (!merge_choice(&gi.invent, mongold) && inv_cnt(FALSE) >= invlet_basic) { You("have no room for the gold!"); dropy(mongold); diff --git a/src/uhitm.c b/src/uhitm.c index c233e088b..fb03df597 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -2717,7 +2717,7 @@ mhitm_ad_sgld( if (mongold) { obj_extract_self(mongold); - if (merge_choice(gi.invent, mongold) + if (merge_choice(&gi.invent, mongold) || inv_cnt(FALSE) < invlet_basic) { addinv(mongold); Your("purse feels heavier.");