about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2021-11-07 01:33:26 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2021-11-07 01:33:26 +0000
commit42efa67c47521596088768d82f5665b15d03d6bf (patch)
tree358e75c107ff9ef1a45e3f4a15085d1f3f7a7a42
parent109fb3ec30eaca9ce3427d58a2b8fb1c038a7c4f (diff)
downloadnetpbm-mirror-42efa67c47521596088768d82f5665b15d03d6bf.tar.gz
netpbm-mirror-42efa67c47521596088768d82f5665b15d03d6bf.tar.xz
netpbm-mirror-42efa67c47521596088768d82f5665b15d03d6bf.zip
fix arithmetic overflows
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@4177 9d0c8265-081b-0410-96cb-a4ca84ce46f8
-rw-r--r--converter/other/sunicontopnm.c32
-rw-r--r--converter/pbm/escp2topbm.c37
-rw-r--r--converter/pbm/mgrtopbm.c80
-rw-r--r--converter/pbm/ybmtopbm.c37
-rw-r--r--doc/HISTORY4
-rw-r--r--editor/pamcut.c4
-rw-r--r--editor/pbmpscale.c36
-rw-r--r--editor/pnmcat.c5
-rw-r--r--editor/pnmpad.c10
-rw-r--r--lib/libpbm2.c7
10 files changed, 165 insertions, 87 deletions
diff --git a/converter/other/sunicontopnm.c b/converter/other/sunicontopnm.c
index eff1be58..93ddc0ab 100644
--- a/converter/other/sunicontopnm.c
+++ b/converter/other/sunicontopnm.c
@@ -12,10 +12,12 @@
 
 /*
   Most icon images are monochrome: Depth=1
+
   Depth=8 images are extremely rare.  At least some of these are color
-  images but we can't tell the palette color order.
+  images but we haven't found information on the palette color order.
   Output will be in pgm.  Convert to ppm with pgmtoppm or pamlookup
-  if necessary.
+  if necessary.  It is up to the user to provide the color palette in
+  a form acceptable by the above conversion utilities.
 */
 
 #include <assert.h>
@@ -28,9 +30,9 @@
 
 
 static void
-ReadIconFileHeader(FILE * const file, 
-                   int *  const widthP, 
-                   int *  const heightP, 
+ReadIconFileHeader(FILE * const file,
+                   int *  const widthP,
+                   int *  const heightP,
                    int *  const depthP,
                    int *  const bitsPerItemP) {
 
@@ -49,7 +51,7 @@ ReadIconFileHeader(FILE * const file,
                 ch == ' ')
             ;
         for (i = 0;
-             ch != '=' && ch != ',' && ch != '\n' && ch != '\t' && 
+             ch != '=' && ch != ',' && ch != '\n' && ch != '\t' &&
                  ch != ' ' && (i < (sizeof(variable) - 1));
              ++i) {
             variable[i] = ch;
@@ -82,7 +84,7 @@ ReadIconFileHeader(FILE * const file,
         } else if (streq(variable, "Valid_bits_per_item")) {
             if (value != 16 && value !=32)
                 pm_error("invalid Valid_bits_per_item");
-            *bitsPerItemP = value; 
+            *bitsPerItemP = value;
             ++fieldCt;
         }
     }
@@ -93,12 +95,19 @@ ReadIconFileHeader(FILE * const file,
 
     if (*widthP <= 0)
         pm_error("invalid width (must be positive): %d", *widthP);
+    else if (*widthP % 8 > 0)
+        pm_message("warning: width not a multiple of 8: %d", *widthP);
+        /* We don't know whether widths which are not a multiple of 8
+           are allowed.   The program must gracefully handle this case
+           because sun icon files are easy to edit by hand.
+        */
     if (*heightP <= 0)
         pm_error("invalid height (must be positive): %d", *heightP);
 
 }
 
 
+
 int
 main(int argc, const char ** argv) {
 
@@ -125,7 +134,7 @@ main(int argc, const char ** argv) {
         maxval = 1;
         pbm_writepbminit(stdout, cols, rows, 0);
         bitrow = pbm_allocrow_packed(cols);
-        colChars = cols / 8;
+        colChars = pbm_packed_bytes(cols);
     } else {
         assert(depth == 8);
         format = PGM_TYPE;
@@ -156,7 +165,7 @@ main(int argc, const char ** argv) {
                 else
                     grayrow[colChar] = data;
             } else
-                pm_error("error scanning bits item %u" , colChar);
+                pm_error("error scanning bits item %u", colChar);
         }
 
         /* output row */
@@ -166,6 +175,11 @@ main(int argc, const char ** argv) {
             pgm_writepgmrow(stdout, grayrow, cols, maxval, 0);
     }
 
+    if (format == PBM_TYPE)
+        pbm_freerow_packed(bitrow);
+    else
+        pgm_freerow(grayrow);
+
     pm_close(ifP);
     pm_close(stdout);
     return 0;
diff --git a/converter/pbm/escp2topbm.c b/converter/pbm/escp2topbm.c
index 632e6345..de3ea931 100644
--- a/converter/pbm/escp2topbm.c
+++ b/converter/pbm/escp2topbm.c
@@ -47,10 +47,17 @@
 
 
 #include <stdbool.h>
+#include <assert.h>
 
 #include "mallocvar.h"
 #include "pbm.h"
 
+static unsigned int widthMax = 127 * 256 + 255;
+    /* Limit in official Epson manual */
+
+static unsigned int const heightMax = 5120 * 200;
+    /* 5120 rows is sufficient for US legal at 360 DPI */
+
 #define ESC 033
 
 
@@ -97,7 +104,7 @@ readChar(FILE * const ifP) {
 
 
 
-static void       
+static void
 readStripeHeader(unsigned int * const widthThisStripeP,
                  unsigned int * const rowsThisStripeP,
                  unsigned int * const compressionP,
@@ -113,13 +120,17 @@ readStripeHeader(unsigned int * const widthThisStripeP,
     compression     = stripeHeader[0];
     /* verticalResolution   = stripeHeader[1]; */
     /* horizontalResolution = stripeHeader[2]; */
-    rowsThisStripe  = stripeHeader[3];  
+    rowsThisStripe  = stripeHeader[3];
     widthThisStripe = stripeHeader[5] * 256 + stripeHeader[4];
 
     if (widthThisStripe == 0 || rowsThisStripe == 0)
         pm_error("Error: Abnormal value in data block header:  "
                  "Says stripe has zero width or height");
 
+    if (widthThisStripe > widthMax)
+        pm_error("Error: Abnormal width value in data block header:  %u",
+                 widthThisStripe);
+
     if (compression != 0 && compression != 1)
         pm_error("Error: Unknown compression mode %u", compression);
 
@@ -132,7 +143,7 @@ readStripeHeader(unsigned int * const widthThisStripeP,
 
 /* RLE decoder */
 static void
-decEpsonRLE(unsigned int    const blockSize, 
+decEpsonRLE(unsigned int    const blockSize,
             unsigned char * const outBuffer,
             FILE *          const ifP) {
 
@@ -163,7 +174,7 @@ decEpsonRLE(unsigned int    const blockSize,
             unsigned int i;
 
             for (i = 0; i < runLength; ++i)
-                outBuffer[dpos + i] = repeatChar;  
+                outBuffer[dpos + i] = repeatChar;
             dpos += runLength;
         }
     }
@@ -180,7 +191,7 @@ processStripeRaster(unsigned char ** const bitarray,
                     unsigned int     const compression,
                     FILE *           const ifP,
                     unsigned int *   const rowIdxP) {
-         
+
     unsigned int const initialRowIdx = *rowIdxP;
     unsigned int const widthInBytes = pbm_packed_bytes(width);
     unsigned int const blockSize = rowsThisStripe * widthInBytes;
@@ -221,14 +232,12 @@ expandBitarray(unsigned char *** const bitarrayP,
                unsigned int   *  const bitarraySizeP) {
 
     unsigned int const heightIncrement = 5120;
-    unsigned int const heightMax = 5120 * 200;
-        /* 5120 rows is sufficient for US legal at 360 DPI */
 
     *bitarraySizeP += heightIncrement;
     if (*bitarraySizeP > heightMax)
-        pm_error("Image too tall");
+        pm_error("Error: Image too tall");
     else
-        REALLOCARRAY_NOFAIL(*bitarrayP, *bitarraySizeP); 
+        REALLOCARRAY_NOFAIL(*bitarrayP, *bitarraySizeP);
 }
 
 
@@ -244,7 +253,7 @@ writePbmImage(unsigned char ** const bitarray,
         pm_error("No image");
 
     pbm_writepbminit(stdout, width, height, 0);
- 
+
     for (row = 0; row < height; ++row) {
         pbm_cleanrowend_packed(bitarray[row], width);
         pbm_writepbmrow_packed(stdout, bitarray[row], width, 0);
@@ -300,7 +309,7 @@ main(int          argc,
                 unsigned int compression;
                 unsigned int rowsThisStripe;
                 unsigned int widthThisStripe;
-            
+
                 readStripeHeader(&widthThisStripe, &rowsThisStripe,
                                  &compression, ifP);
 
@@ -311,7 +320,7 @@ main(int          argc,
                     /* The official Epson manual says valid values are 1, 8,
                        24 but we just print a warning message and continue if
                        other values are detected.
-                    */ 
+                    */
                     pm_message("Abnormal data block height value: %u "
                                "(ignoring)",
                                rowsThisStripe);
@@ -326,6 +335,10 @@ main(int          argc,
                              width, widthThisStripe);
                 }
                 height += rowsThisStripe;
+                assert(height <= INT_MAX - 10);
+                    /* Becuse image height is tested in expandBitarray()
+                       with a more stringent condition.
+                    */
                 if (height > bitarraySize)
                     expandBitarray(&bitarray, &bitarraySize);
 
diff --git a/converter/pbm/mgrtopbm.c b/converter/pbm/mgrtopbm.c
index 9f7004a1..e0a88883 100644
--- a/converter/pbm/mgrtopbm.c
+++ b/converter/pbm/mgrtopbm.c
@@ -16,12 +16,54 @@
 
 
 static void
-readMgrHeader(FILE *          const ifP, 
-              unsigned int *  const colsP, 
-              unsigned int *  const rowsP, 
-              unsigned int *  const depthP, 
+interpHdrWidth(struct b_header const head,
+               unsigned int *  const colsP) {
+
+    if (head.h_wide < ' ' || head.l_wide < ' ')
+        pm_error("Invalid width field in MGR header");
+    else {
+        unsigned int const maxDimension = 4095;
+
+        unsigned int const cols =
+            (((int)head.h_wide - ' ') << 6) + ((int)head.l_wide - ' ');
+
+        if (cols == 0 || cols > maxDimension)
+            pm_error("Invalid width value (%u) in MGR header", cols);
+        else
+            *colsP = cols;
+    }
+}
+
+
+
+static void
+interpHdrHeight(struct b_header const head,
+                unsigned int *  const rowsP) {
+
+    if (head.h_high < ' ' || head.l_high < ' ')
+        pm_error("Invalid height field in MGR header");
+    else {
+        unsigned int const maxDimension = 4095;
+
+        unsigned int const rows =
+            (((int)head.h_high - ' ') << 6) + ((int)head.l_high - ' ');
+
+        if (rows == 0 || rows > maxDimension)
+            pm_error("Invalid height value (%u) in MGR header", rows);
+        else
+            *rowsP = rows;
+    }
+}
+
+
+
+static void
+readMgrHeader(FILE *          const ifP,
+              unsigned int *  const colsP,
+              unsigned int *  const rowsP,
+              unsigned int *  const depthP,
               unsigned int *  const padrightP ) {
-    
+
     struct b_header head;
     unsigned int pad;
     size_t bytesRead;
@@ -31,10 +73,10 @@ readMgrHeader(FILE *          const ifP,
         pm_error("Unable to read 1st byte of file.  "
                  "fread() returns errno %d (%s)",
                  errno, strerror(errno));
-    if (head.magic[0] == 'y' && head.magic[1] == 'z') { 
+    if (head.magic[0] == 'y' && head.magic[1] == 'z') {
         /* new style bitmap */
         size_t bytesRead;
-        bytesRead = fread(&head.depth, 
+        bytesRead = fread(&head.depth,
                           sizeof(head) - sizeof(struct old_b_header), 1, ifP);
         if (bytesRead != 1 )
             pm_error("Unable to read header after 1st byte.  "
@@ -42,11 +84,11 @@ readMgrHeader(FILE *          const ifP,
                      errno, strerror(errno));
         *depthP = (int) head.depth - ' ';
         pad = 8;
-    } else if (head.magic[0] == 'x' && head.magic[1] == 'z') { 
+    } else if (head.magic[0] == 'x' && head.magic[1] == 'z') {
         /* old style bitmap with 32-bit padding */
         *depthP = 1;
         pad = 32;
-    } else if (head.magic[0] == 'z' && head.magic[1] == 'z') { 
+    } else if (head.magic[0] == 'z' && head.magic[1] == 'z') {
         /* old style bitmap with 16-bit padding */
         *depthP = 1;
         pad = 16;
@@ -60,14 +102,10 @@ readMgrHeader(FILE *          const ifP,
         pad = 0;  /* should never reach here */
     }
 
-    if (head.h_wide < ' ' || head.l_wide < ' ')
-        pm_error("Invalid width field in MGR header");
-    if (head.h_high < ' ' || head.l_high < ' ')
-        pm_error("Invalid width field in MGR header");
-    
-    *colsP = (((int)head.h_wide - ' ') << 6) + ((int)head.l_wide - ' ');
-    *rowsP = (((int)head.h_high - ' ') << 6) + ((int) head.l_high - ' ');
-    *padrightP = ( ( *colsP + pad - 1 ) / pad ) * pad - *colsP;
+    interpHdrWidth (head, colsP);
+    interpHdrHeight(head, rowsP);
+
+    *padrightP = ((*colsP + pad - 1) / pad) * pad - *colsP;
 }
 
 
@@ -93,7 +131,7 @@ main(int    argc,
         inputFileName = argv[1];
     else
         inputFileName = "-";
-    
+
     ifP = pm_openr(inputFileName);
 
     readMgrHeader(ifP, &cols, &rows, &depth, &padright);
@@ -103,7 +141,7 @@ main(int    argc,
     pbm_writepbminit(stdout, cols, rows, 0);
 
     bitrow = pbm_allocrow_packed(cols + padright);
-    
+
     itemCount = (cols + padright ) / 8;
 
     for (row = 0; row < rows; ++row) {
@@ -128,9 +166,9 @@ main(int    argc,
    Changed bitrow from plain to raw, read function from getc() to fread(),
    write function from pbm_writepbmrow() to pbm_writepbmrow_packed().
    Retired bitwise transformation functions.
-   
+
    NOT tested for old-style format files.  Only one zz file in mgrsrc-0.69 .
-  
+
 */
 
 
diff --git a/converter/pbm/ybmtopbm.c b/converter/pbm/ybmtopbm.c
index 2a429086..36f2dee7 100644
--- a/converter/pbm/ybmtopbm.c
+++ b/converter/pbm/ybmtopbm.c
@@ -19,45 +19,48 @@ static short const ybmMagic = ( ( '!' << 8 ) | '!' );
 
 
 static void
-getinit(FILE *  const ifP,
-        short * const colsP,
-        short * const rowsP,
-        short * const depthP) {
+getinit(FILE *         const ifP,
+        unsigned int * const colsP,
+        unsigned int * const rowsP,
+        int *          const depthP) {
 
-    short magic;
+    short int magic;
+    short int cols, rows;
     int rc;
 
     rc = pm_readbigshort(ifP, &magic);
     if (rc == -1)
         pm_error("EOF / read error");
-
-    if (magic != ybmMagic)
+    else if (magic != ybmMagic)
         pm_error("bad magic number in YBM file");
 
-    rc = pm_readbigshort(ifP, colsP);
+    rc = pm_readbigshort(ifP, &cols);
     if (rc == -1 )
         pm_error("EOF / read error");
+    else if (cols <= 0)
+        pm_error("invalid width value in YBM file");
 
-    rc = pm_readbigshort(ifP, rowsP);
+    rc = pm_readbigshort(ifP, &rows);
     if (rc == -1)
         pm_error("EOF / read error");
+    else if (rows <= 0)
+        pm_error("invalid height value in YBM file");
 
+    *colsP = (unsigned int) cols;
+    *rowsP = (unsigned int) rows;
     *depthP = 1;
 }
 
 
 
-
-
-
 int
 main(int argc, const char * argv[]) {
 
     FILE * ifP;
     bit * bitrow;
-    short rows, cols;
+    unsigned int rows, cols;
     unsigned int row;
-    short depth;
+    int depth;
     const char * inputFile;
 
     pm_proginit(&argc, argv);
@@ -76,8 +79,8 @@ main(int argc, const char * argv[]) {
 
     getinit(ifP, &cols, &rows, &depth);
     if (depth != 1)
-        pm_error("YBM file has depth of %u, must be 1", (unsigned)depth);
-    
+        pm_error("YBM file has depth of %u, must be 1", (unsigned int) depth);
+
     pbm_writepbminit(stdout, cols, rows, 0);
 
     bitrow = pbm_allocrow_packed(cols + 8);
@@ -92,7 +95,7 @@ main(int argc, const char * argv[]) {
         for (i = 0; i < itemCt; ++i) {
             short int item;
             pm_readbigshort(ifP, &item);
-            itemrow[i] = (uint16_t) item; 
+            itemrow[i] = (uint16_t) item;
         }
 
         for (i = 0; i < pbm_packed_bytes(cols); ++i)
diff --git a/doc/HISTORY b/doc/HISTORY
index bbd399b7..d9462f87 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -18,6 +18,10 @@ not yet  BJH  Release 10.97.00
               the image than the first.  Always broken (Pamrubber was new in
               Netpbm 10.54 (March 2011)).
 
+              sunicontopnm, escp2topbm, mgrtopbm, ybmtopbm, pamcut, pbmpscale,
+              pnmcat, pnmpad: Fix arithmetic overrun with ridiculously large
+              image.
+
               pbmclean: Fix overallocation of memory (waste).
 
               libnetpbm: When validating computable size of width and height,
diff --git a/editor/pamcut.c b/editor/pamcut.c
index 1fc9d9b2..7870fd70 100644
--- a/editor/pamcut.c
+++ b/editor/pamcut.c
@@ -712,7 +712,7 @@ extractRowsPBM(const struct pam * const inpamP,
 
     if (leftcol > 0) {
         totalWidth = MAX(rightcol+1, inpamP->width) + 7;
-        if (totalWidth > INT_MAX)
+        if (totalWidth > INT_MAX - 10)
             /* Prevent overflows in pbm_allocrow_packed() */
             pm_error("Specified right edge is too far "
                      "from the right end of input image");
@@ -721,7 +721,7 @@ extractRowsPBM(const struct pam * const inpamP,
         writeOffset = leftcol;
     } else {
         totalWidth = -leftcol + MAX(rightcol+1, inpamP->width);
-        if (totalWidth > INT_MAX)
+        if (totalWidth > INT_MAX - 10)
             pm_error("Specified left/right edge is too far "
                      "from the left/right end of input image");
 
diff --git a/editor/pbmpscale.c b/editor/pbmpscale.c
index 9ab89350..434c7965 100644
--- a/editor/pbmpscale.c
+++ b/editor/pbmpscale.c
@@ -12,7 +12,7 @@
 #define LEFTBITS pm_byteLeftBits
 #define RIGHTBITS pm_byteRightBits
 
-/* Table for translating bit pattern into "corners" flag element */ 
+/* Table for translating bit pattern into "corners" flag element */
 
 unsigned char const
 transTable[512] = {
@@ -141,7 +141,7 @@ validateComputableDimensions(unsigned int const width,
    See validateComputetableSize() in libpam.c
    and pbm_readpbminitrest() in libpbm2.c
 -----------------------------------------------------------------------------*/
-    unsigned int const maxWidthHeight = INT_MAX - 2;
+    unsigned int const maxWidthHeight = INT_MAX - 10;
     unsigned int const maxScaleFactor = maxWidthHeight / MAX(height, width);
 
     if (scaleFactor > maxScaleFactor)
@@ -154,8 +154,8 @@ validateComputableDimensions(unsigned int const width,
 
 static void
 writeBitSpan(unsigned char * const packedBitrow,
-             int             const cols,
-             int             const offset,
+             unsigned int    const cols,
+             unsigned int    const offset,
              int             const color) {
 /*----------------------------------------------------------------------------
    Write white (color="0") or black (="1") bits into packedBitrow[],
@@ -191,8 +191,8 @@ setFlags(const bit *     const prevrow,
          unsigned char * const flags,
          unsigned int    const cols ) {
 /*----------------------------------------------------------------------------
-   Scan one row, examining the row above and row below, and determine 
-   whether there are "corners" for each pixel.  Feed a 9 bit sample into 
+   Scan one row, examining the row above and row below, and determine
+   whether there are "corners" for each pixel.  Feed a 9 bit sample into
    pre-calculated array transTable[512] to calculate all four corner statuses
    at once.
 
@@ -220,7 +220,7 @@ setFlags(const bit *     const prevrow,
        The high byte of the patterns is a mask, which determines which bits are
        not ignored.
     */
-    uint16_t const patterns[] 
+    uint16_t const patterns[]
         = { 0x0000,   0xd555,            /* no corner */
             0x0001,   0xffc1, 0xd514,    /* normal corner */
             0x0002,   0xd554, 0xd515, 0xbea2, 0xdfc0, 0xfd81, 0xfd80, 0xdf80,
@@ -230,7 +230,7 @@ setFlags(const bit *     const prevrow,
     /*
       For example, the NE corner is examined with the following 8 bit sample:
       Current : W : NW : N : NE : E : SE : S
-      (SW is the "square behind") 
+      (SW is the "square behind")
       */
 #endif
 
@@ -257,7 +257,7 @@ setFlags(const bit *     const prevrow,
         sample = ( ( prevrow24 >> ( 8 -offset) ) & 0x01c0 )
             | ( ( thisrow24 >> (11 -offset) ) & 0x0038 )
             | ( ( nextrow24 >> (14 -offset) ) & 0x0007 );
-        
+
         flags[col] =  transTable[sample];
     }
 }
@@ -275,14 +275,14 @@ expandRow(const bit *     const thisrow,
           int             const ucutoff) {
 /*----------------------------------------------------------------------------
   Process one row, using flags array as reference.  If pixel has no corners
-  output a NxN square of the given color, otherwise output with the 
+  output a NxN square of the given color, otherwise output with the
   specified corner area(s) clipped off.
 -----------------------------------------------------------------------------*/
     unsigned int const outcols = cols * scale;
 
     unsigned int i;
     unsigned int col;
-    
+
     for (i = 0; i < scale; ++i) {
         int const zone = (i > ucutoff) - (i < cutoff);
         int const cut1 =
@@ -297,7 +297,7 @@ expandRow(const bit *     const thisrow,
         cut[1] = cut1;
         cut[2] = cut1 ? cut1 - 1 : 0;
         cut[3] = (cut1 && cutoff > 1) ? cut1 - 1 : cut1;
-      
+
         for (col = 0; col < cols; ++col) {
             unsigned int const col8 = col / 8;
             unsigned int const offset = col % 8;
@@ -309,11 +309,11 @@ expandRow(const bit *     const thisrow,
             if (flag == 0x00) {
                 /* There are no corners, no color change */
                 outcol += scale;
-            } else { 
+            } else {
                 switch (zone) {
                 case -1:
                     if (i==0 && flag == 0xff) {
-                        /* No corners, color changed */ 
+                        /* No corners, color changed */
                         cutl = cutr = 0;
                         flags[col] = 0x00;
                             /* Use above skip procedure next cycle */
@@ -330,7 +330,7 @@ expandRow(const bit *     const thisrow,
                     cutr = cut[SE(flag)];
                     break;
                 }
-                
+
                 if (cutl > 0) {
                     writeBitSpan(outrow, cutl, outcol, !pix);
                     outcol += cutl;
@@ -384,10 +384,10 @@ main(int argc, const char ** argv) {
 
     pbm_readpbminit(ifP, &cols, &rows, &format) ;
 
-    validateComputableDimensions(cols, rows, cmdline.scale); 
+    validateComputableDimensions(cols, rows, cmdline.scale);
 
     outcols = cols * cmdline.scale;
-    outrows = rows * cmdline.scale; 
+    outrows = rows * cmdline.scale;
 
     /* Initialize input buffers.
        We add a margin of 8 bits on the right of the three rows.
@@ -402,7 +402,7 @@ main(int argc, const char ** argv) {
     for (i = 0; i < pbm_packed_bytes(cols + 8); ++i)
         edgerow[i] = 0x00;
 
-    /* Add blank bytes at right edges */ 
+    /* Add blank bytes at right edges */
     for (i = 0; i < 3; ++i)
         buffer[i][pbm_packed_bytes(cols + 8) - 1] = 0x00;
 
diff --git a/editor/pnmcat.c b/editor/pnmcat.c
index c660698c..01811cb4 100644
--- a/editor/pnmcat.c
+++ b/editor/pnmcat.c
@@ -115,7 +115,7 @@ parseCommandLine(int argc, const char ** const argv,
         cmdlineP->backcolor = BACK_AUTO;
 
     if (jtop + jbottom + jleft + jright + jcenter > 1)
-        pm_error("You may specify onlyone of -jtop, -jbottom, "
+        pm_error("You may specify only one of -jtop, -jbottom, "
                  "-jleft, and -jright");
     else {
         switch (cmdlineP->orientation) {
@@ -367,7 +367,8 @@ getPbmImageInfo(ImgInfo               const img[],
             switch (backcolor) {
             case BACK_AUTO: {
                 bit bgBit;
-                img2[i].proberow = pbm_allocrow_packed(img[i].cols+7);
+                img2[i].proberow =
+                    pbm_allocrow_packed((unsigned int)img[i].cols + 7);
                 pbm_readpbmrow_bitoffset(
                     img[i].ifP, img2[i].proberow,
                     img[i].cols, img[i].format, img2[i].offset % 8);
diff --git a/editor/pnmpad.c b/editor/pnmpad.c
index 55cdcd6c..1e704724 100644
--- a/editor/pnmpad.c
+++ b/editor/pnmpad.c
@@ -11,7 +11,7 @@
 #include "shhopt.h"
 #include "pnm.h"
 
-#define MAX_WIDTHHEIGHT INT_MAX-10
+#define MAX_WIDTHHEIGHT ((INT_MAX)-10)
     /* The maximum width or height value we can handle without risking
        arithmetic overflow
     */
@@ -268,7 +268,7 @@ validateHorizontalSize(struct cmdlineInfo const cmdline,
         pm_error("The right padding value you specified is too large.");
 
     if ((double) cols +
-        (double) lpad + 
+        (double) lpad +
         (double) rpad +
         (double) mwidthMaxPad > MAX_WIDTHHEIGHT)
         pm_error("Given padding parameters make output width too large "
@@ -378,7 +378,7 @@ computePadSizesOneDim(unsigned int   const unpaddedSize,
         unsigned int const totalPadBeforeMult =
             begPadBeforeMult + endPadBeforeMult;
         double const begFrac =
-            totalPadBeforeMult > 0 ? 
+            totalPadBeforeMult > 0 ?
             (double)begPadBeforeMult / totalPadBeforeMult :
             0.0;
         unsigned int const addlMsizeBegPad = ROUNDU(morePadNeeded * begFrac);
@@ -501,7 +501,7 @@ reportPadSizes(int          const inCols,
 
     unsigned int const outCols = inCols + lpad + rpad;
     unsigned int const outRows = inRows + tpad + bpad;
- 
+
     printf("%u %u %u %u %u %u\n", lpad, rpad, tpad, bpad, outCols, outRows);
 
 }
@@ -547,7 +547,7 @@ padPbm(FILE *       const ifP,
     /* Write top margin */
     for (row = 0; row < tpad; ++row)
         pbm_writepbmrow_packed(stdout, bgrow, newcols, 0);
-    
+
     /* Read rows, shift and write with left and right margins added */
     for (row = 0; row < rows; ++row) {
         pbm_readpbmrow_bitoffset(ifP, newrow, cols, format, lpad);
diff --git a/lib/libpbm2.c b/lib/libpbm2.c
index 1ad93534..2a2e2aac 100644
--- a/lib/libpbm2.c
+++ b/lib/libpbm2.c
@@ -216,6 +216,9 @@ pbm_readpbmrow_bitoffset(FILE *          const ifP,
    Read it into packedBits[], preserving surrounding image data.
 
    Logic not tested for negative offsets.
+
+   Because we are reading in packed mode large cols and offset values are
+   acceptable; dividing by 8 prevents overflows.
 -----------------------------------------------------------------------------*/
     unsigned int const rsh = offset % 8;
     unsigned int const lsh = (8 - rsh) % 8;
@@ -224,13 +227,15 @@ pbm_readpbmrow_bitoffset(FILE *          const ifP,
            Aligned to nearest byte boundary to the left, so the first
            few bits might contain original data, not output.
         */
-    unsigned int const last = pbm_packed_bytes(cols+rsh) - 1;
+    unsigned int const last = pbm_packed_bytes((unsigned int)cols + rsh) - 1;
         /* Position within window of rightmost byte after shift */
 
     /* The original leftmost and rightmost chars. */
     unsigned char const origHead = window[0];
     unsigned char const origEnd  = window[last];
 
+    assert(cols > 0 && pbm_packed_bytes(cols) > 0);
+
     pbm_readpbmrow_packed(ifP, window, cols, format);
 
     if (rsh > 0) {