From: PatR Date: Mon, 25 Oct 2021 21:51:26 +0000 (-0700) Subject: fix pull request #621 - potential divide by 0 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b4908f692801b600fc6e3d1f0fcdd119dfc28ce2;p=nethack fix pull request #621 - potential divide by 0 The pull request by argrath changes weight_cap() to never return a value less than 1 because try_lift() divides by that return value and a 0 would trigger a crash. The code involved is used when attempting to pull a monster out of a pit via #untrap. I'm fairly sure that weight_cap() can never produce a value that's less than 1 already, but have put in a variation of the PR's fix. I've also implemented a different fix that removes the division from try_lift(). The original code seems to have gone out of its way to avoid calculating inv_weight() twice, but doing the latter (for the once in a hundred games where it might happen) greatly simplifies things by removing details of carrying capacity. Fixes #621 --- diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 07329f960..040a38460 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -660,6 +660,8 @@ using 'F'orcefight against iron bars while wielding something breakable could called twice and could yield results that conflicted have applying a polearm give feedback similar to 'F' for melee weapon when attacking a wall or boulder +if weight_cap() ever returned 0 (which probably can't happen), using #untrap + to pull a monster out of a pit would trigger a divide by 0 crash Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/src/hack.c b/src/hack.c index fb04501e0..7c7dc0609 100644 --- a/src/hack.c +++ b/src/hack.c @@ -3330,8 +3330,6 @@ weight_cap(void) if (EWounded_legs & RIGHT_SIDE) carrcap -= 100; } - if (carrcap < 0) - carrcap = 0; } if (ELevitation != save_ELev || BLevitation != save_BLev) { @@ -3340,7 +3338,7 @@ weight_cap(void) float_vs_flight(); } - return (int) carrcap; + return (int) max(carrcap, 1L); /* never return 0 */ } /* returns how far beyond the normal capacity the player is currently. */ diff --git a/src/trap.c b/src/trap.c index 05fe3c3e9..f61ce92e8 100644 --- a/src/trap.c +++ b/src/trap.c @@ -4687,18 +4687,15 @@ disarm_shooting_trap(struct trap* ttmp, int otyp) return 1; } -/* Is the weight too heavy? - * Formula as in near_capacity() & check_capacity() */ +/* trying to #untrap a monster from a pit; is the weight too heavy? */ static int try_lift( - struct monst *mtmp, - struct trap *ttmp, - int wt, - boolean stuff) + struct monst *mtmp, /* trapped monster */ + struct trap *ttmp, /* pit, possibly made by hero, or spiked pit */ + int xtra_wt, /* monster (corpse weight) + (stuff ? minvent weight : 0) */ + boolean stuff) /* False: monster w/o minvent; True: w/ minvent */ { - int wc = weight_cap(); - - if (((wt * 2) / wc) >= HVY_ENCUMBER) { + if (calc_capacity(xtra_wt) >= HVY_ENCUMBER) { pline("%s is %s for you to lift.", Monnam(mtmp), stuff ? "carrying too much" : "too heavy"); if (!ttmp->madeby_u && !mtmp->mpeaceful && mtmp->mcanmove @@ -4719,7 +4716,7 @@ help_monster_out( struct monst *mtmp, struct trap *ttmp) { - int wt; + int xtra_wt; struct obj *otmp; boolean uprob; @@ -4788,15 +4785,18 @@ help_monster_out( } /* is the monster too heavy? */ - wt = inv_weight() + mtmp->data->cwt; - if (!try_lift(mtmp, ttmp, wt, FALSE)) + xtra_wt = mtmp->data->cwt; + if (!try_lift(mtmp, ttmp, xtra_wt, FALSE)) return 1; - /* is the monster with inventory too heavy? */ - for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) - wt += otmp->owt; - if (!try_lift(mtmp, ttmp, wt, TRUE)) - return 1; + /* monster without its inventory isn't too heavy; if it carries + anything, include that minvent weight and check again */ + if (mtmp->minvent) { + for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) + xtra_wt += otmp->owt; + if (!try_lift(mtmp, ttmp, xtra_wt, TRUE)) + return 1; + } You("pull %s out of the pit.", mon_nam(mtmp)); mtmp->mtrapped = 0;