]> granicus.if.org Git - nethack/commitdiff
fix pull request #621 - potential divide by 0
authorPatR <rankin@nethack.org>
Mon, 25 Oct 2021 21:51:26 +0000 (14:51 -0700)
committerPatR <rankin@nethack.org>
Mon, 25 Oct 2021 21:51:26 +0000 (14:51 -0700)
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

doc/fixes37.0
src/hack.c
src/trap.c

index 07329f960b6b622742c33473287f528e820203b1..040a384607881a1c9d4cb0f26f8df0017a7d5b8f 100644 (file)
@@ -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
index fb04501e0445271fd29d081670edbcb768ecfa40..7c7dc0609bb123d47f7d57e3e03912cb8e1a8f1f 100644 (file)
@@ -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. */
index 05fe3c3e93a9f37dc17224c34bae3b1724ba6ea0..f61ce92e8ad477d0283d5603ea6bf73c153b485f 100644 (file)
@@ -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;