Here's the patch that I am planning to apply upstream. Please comment
if you see anything wrong with it. 

While the general idea is similar to Tomasz's patch, I've solved the
details a bit differently.

* I prefer to use ssize_t instead of unsigned long long int for memory
  manipulations. Since size_t is the type used by malloc, memcpy, etc,
  it is big enough to hold the relevant values. The reason I use a
  signed rather than unsigned type is that the "dy" field in the
  potrace_bitmap_s structure may be positive or negative, depending on
  whether the bitmap is stored top-to-bottom or bottom-to-top. Potrace
  itself always uses a positive dy, but other applications that link
  against the Potrace library may use their own convention. Tomasz's
  patch used an unsigned type which would break applications that use
  a negative dy.

  The code now checks that the bitmap dimensions are indeed such that
  all relevant values fit within ssize_t. A remaining assumption is
  that ssize_t is at least as big as int, which I think is guaranteed.

* I prefer to use calloc instead of safe_malloc. Calloc is appropriate
  whenever the memory to be allocated is a number of copies of items
  of a given size. Unlike malloc(x*y), calloc(x, y) actually checks
  that x*y does not overflow. (I checked the glibc source code for
  calloc to be sure that such a check is actually performed). In the
  few cases where the argument of malloc is calculated differently
  (say as a product of three numbers), I have added an explicit
  overflow check. This is safer, in my opinion, than safe_malloc(x*y);
  in particular, there is no difference bewteen safe_malloc and
  ordinary malloc when size_t = unsigned long long int.

* I also fixed analogous issues in Mkbitmap and throughout the rest of
  the code.

I'll post an updated upstream package in a day or two unless there's
feedback requiring additional changes.

Thanks, -- Peter

diff -u -r potrace-1.11/src/backend_eps.c potrace-1.11-patched/src/backend_eps.c
--- potrace-1.11/src/backend_eps.c      2013-02-20 00:51:44.000000000 +0100
+++ potrace-1.11-patched/src/backend_eps.c      2015-03-20 23:57:39.703432480 
+0100
@@ -26,8 +26,8 @@
 #include "config.h"
 #endif
 
-#define SAFE_MALLOC(var, n, typ) \
-  if ((var = (typ *)malloc((n)*sizeof(typ))) == NULL) goto malloc_error 
+#define SAFE_CALLOC(var, n, typ) \
+  if ((var = (typ *)calloc(n, sizeof(typ))) == NULL) goto calloc_error 
 
 typedef int color_t;
 
@@ -232,10 +232,10 @@
   double M;
   int m = curve->n;
 
-  SAFE_MALLOC(bq, m, long int);
-  SAFE_MALLOC(aq, m, long int);
-  SAFE_MALLOC(v, m, point_t);
-  SAFE_MALLOC(q, m, dpoint_t);
+  SAFE_CALLOC(bq, m, long int);
+  SAFE_CALLOC(aq, m, long int);
+  SAFE_CALLOC(v, m, point_t);
+  SAFE_CALLOC(q, m, dpoint_t);
 
   /* quantize vertices */
   for (i=0; i<m; i++) {
@@ -295,7 +295,7 @@
   free(q);
   return 0;
 
- malloc_error:
+ calloc_error:
   free(bq);
   free(aq);
   free(v);
diff -u -r potrace-1.11/src/bitmap.h potrace-1.11-patched/src/bitmap.h
--- potrace-1.11/src/bitmap.h   2013-02-20 00:51:44.000000000 +0100
+++ potrace-1.11-patched/src/bitmap.h   2015-03-20 23:57:39.704432477 +0100
@@ -7,6 +7,7 @@
 
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>
 
 /* The bitmap type is defined in potracelib.h */
 #include "potracelib.h"
@@ -27,7 +28,7 @@
 /* macros for accessing pixel at index (x,y). U* macros omit the
    bounds check. */
 
-#define bm_scanline(bm, y) ((bm)->map + (y)*(bm)->dy)
+#define bm_scanline(bm, y) ((bm)->map + (y)*(ssize_t)(bm)->dy)
 #define bm_index(bm, x, y) (&bm_scanline(bm, y)[(x)/BM_WORDBITS])
 #define bm_mask(x) (BM_HIBIT >> ((x) & (BM_WORDBITS-1)))
 #define bm_range(x, a) ((int)(x) >= 0 && (int)(x) < (a))
@@ -51,10 +52,18 @@
   free(bm);
 }
 
-/* return new un-initialized bitmap. NULL with errno on error */
+/* return new un-initialized bitmap. NULL with errno on error.
+   Assumes w, h >= 0. */
 static inline potrace_bitmap_t *bm_new(int w, int h) {
   potrace_bitmap_t *bm;
-  int dy = (w + BM_WORDBITS - 1) / BM_WORDBITS;
+  int dy = w == 0 ? 0 : (w - 1) / BM_WORDBITS + 1;
+  ssize_t size = (ssize_t)dy * (ssize_t)h * (ssize_t)BM_WORDSIZE;
+
+  /* check for overflow error */
+  if (size < 0 || size / h / dy != BM_WORDSIZE) {
+    errno = ENOMEM;
+    return NULL;
+  }
 
   bm = (potrace_bitmap_t *) malloc(sizeof(potrace_bitmap_t));
   if (!bm) {
@@ -63,7 +72,7 @@
   bm->w = w;
   bm->h = h;
   bm->dy = dy;
-  bm->map = (potrace_word *) malloc(dy * h * BM_WORDSIZE);
+  bm->map = (potrace_word *) malloc(size);
   if (!bm->map) {
     free(bm);
     return NULL;
@@ -73,23 +82,29 @@
 
 /* clear the given bitmap. Set all bits to c. */
 static inline void bm_clear(potrace_bitmap_t *bm, int c) {
-  memset(bm->map, c ? -1 : 0, bm->dy * bm->h * BM_WORDSIZE);
+  /* Note: if the bitmap was created with bm_new, then it is
+     guaranteed that size will fit into the ssize_t type. */
+  ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h * (ssize_t)BM_WORDSIZE;
+  memset(bm->map, c ? -1 : 0, size);
 }
 
 /* duplicate the given bitmap. Return NULL on error with errno set. */
 static inline potrace_bitmap_t *bm_dup(const potrace_bitmap_t *bm) {
   potrace_bitmap_t *bm1 = bm_new(bm->w, bm->h);
+  ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h * (ssize_t)BM_WORDSIZE;
   if (!bm1) {
     return NULL;
   }
-  memcpy(bm1->map, bm->map, bm->dy * bm->h * BM_WORDSIZE);
+  memcpy(bm1->map, bm->map, size);
   return bm1;
 }
 
 /* invert the given bitmap. */
 static inline void bm_invert(potrace_bitmap_t *bm) {
-  int i;
-  for (i = 0; i < bm->dy * bm->h; i++) {
+  ssize_t i;
+  ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h;
+
+  for (i = 0; i < size; i++) {
     bm->map[i] ^= BM_ALLBITS;
   }
 }
diff -u -r potrace-1.11/src/bitmap_io.c potrace-1.11-patched/src/bitmap_io.c
--- potrace-1.11/src/bitmap_io.c        2013-02-20 00:51:44.000000000 +0100
+++ potrace-1.11-patched/src/bitmap_io.c        2015-03-20 23:57:39.706432473 
+0100
@@ -478,12 +478,18 @@
       TRY(bmp_readint(f, 4, &bmpinfo.BlueMask));
       TRY(bmp_readint(f, 4, &bmpinfo.AlphaMask));
     }
-    if ((signed int)bmpinfo.h < 0) {
-      bmpinfo.h = -bmpinfo.h;
+    if (bmpinfo.w > 0x7fffffff) {
+      goto format_error;
+    }
+    if (bmpinfo.h > 0x7fffffff) {
+      bmpinfo.h = (-bmpinfo.h) & 0xffffffff;
       bmpinfo.topdown = 1;
     } else {
       bmpinfo.topdown = 0;
     }
+    if (bmpinfo.h > 0x7fffffff) {
+      goto format_error;
+    }
   } else if (bmpinfo.InfoSize == 12) {
     /* old OS/2 format */
     bmpinfo.ctbits = 24; /* sample size in color table */
@@ -517,7 +523,7 @@
 
   /* color table, present only if bmpinfo.bits <= 8. */
   if (bmpinfo.bits <= 8) {
-    coltable = (int *) malloc(bmpinfo.ncolors * sizeof(int));
+    coltable = (int *) calloc(bmpinfo.ncolors, sizeof(int));
     if (!coltable) {
       goto std_error;
     }
diff -u -r potrace-1.11/src/curve.c potrace-1.11-patched/src/curve.c
--- potrace-1.11/src/curve.c    2013-02-20 00:51:44.000000000 +0100
+++ potrace-1.11-patched/src/curve.c    2015-03-20 23:57:39.707432471 +0100
@@ -12,8 +12,8 @@
 #include "lists.h"
 #include "curve.h"
 
-#define SAFE_MALLOC(var, n, typ) \
-  if ((var = (typ *)malloc((n)*sizeof(typ))) == NULL) goto malloc_error 
+#define SAFE_CALLOC(var, n, typ) \
+  if ((var = (typ *)calloc(n, sizeof(typ))) == NULL) goto calloc_error 
 
 /* ---------------------------------------------------------------------- */
 /* allocate and free path objects */
@@ -22,14 +22,14 @@
   path_t *p = NULL;
   privpath_t *priv = NULL;
 
-  SAFE_MALLOC(p, 1, path_t);
+  SAFE_CALLOC(p, 1, path_t);
   memset(p, 0, sizeof(path_t));
-  SAFE_MALLOC(priv, 1, privpath_t);
+  SAFE_CALLOC(priv, 1, privpath_t);
   memset(priv, 0, sizeof(privpath_t));
   p->priv = priv;
   return p;
 
- malloc_error:
+ calloc_error:
   free(p);
   free(priv);
   return NULL;
@@ -81,15 +81,15 @@
 int privcurve_init(privcurve_t *curve, int n) {
   memset(curve, 0, sizeof(privcurve_t));
   curve->n = n;
-  SAFE_MALLOC(curve->tag, n, int);
-  SAFE_MALLOC(curve->c, n, dpoint3_t);
-  SAFE_MALLOC(curve->vertex, n, dpoint_t);
-  SAFE_MALLOC(curve->alpha, n, double);
-  SAFE_MALLOC(curve->alpha0, n, double);
-  SAFE_MALLOC(curve->beta, n, double);
+  SAFE_CALLOC(curve->tag, n, int);
+  SAFE_CALLOC(curve->c, n, dpoint3_t);
+  SAFE_CALLOC(curve->vertex, n, dpoint_t);
+  SAFE_CALLOC(curve->alpha, n, double);
+  SAFE_CALLOC(curve->alpha0, n, double);
+  SAFE_CALLOC(curve->beta, n, double);
   return 0;
 
- malloc_error:
+ calloc_error:
   free(curve->tag);
   free(curve->c);
   free(curve->vertex);
diff -u -r potrace-1.11/src/greymap.c potrace-1.11-patched/src/greymap.c
--- potrace-1.11/src/greymap.c  2013-02-20 00:51:44.000000000 +0100
+++ potrace-1.11-patched/src/greymap.c  2015-03-20 23:57:39.709432467 +0100
@@ -9,6 +9,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#include <errno.h>
 
 #include "greymap.h"
 #include "bitops.h"
@@ -23,10 +24,17 @@
 /* ---------------------------------------------------------------------- */
 /* basic greymap routines */
 
-/* return new un-initialized greymap. NULL with errno on error */
-
+/* return new un-initialized greymap. NULL with errno on error.
+   Assumes w, h >= 0. */
 greymap_t *gm_new(int w, int h) {
   greymap_t *gm;
+  ssize_t size = (ssize_t)w * (ssize_t)h * (ssize_t)sizeof(signed short int);
+  
+  /* check for overflow error */
+  if (size < 0 || size / w / h != sizeof(signed short int)) {
+    errno = ENOMEM;
+    return NULL;
+  }
 
   gm = (greymap_t *) malloc(sizeof(greymap_t));
   if (!gm) {
@@ -34,7 +42,7 @@
   }
   gm->w = w;
   gm->h = h;
-  gm->map = (signed short int *) malloc(w*h*sizeof(signed short int));
+  gm->map = (signed short int *) malloc(size);
   if (!gm->map) {
     free(gm);
     return NULL;
@@ -537,12 +545,18 @@
       TRY(bmp_readint(f, 4, &bmpinfo.BlueMask));
       TRY(bmp_readint(f, 4, &bmpinfo.AlphaMask));
     }
-    if ((signed int)bmpinfo.h < 0) {
-      bmpinfo.h = -bmpinfo.h;
+    if (bmpinfo.w > 0x7fffffff) {
+      goto format_error;
+    }
+    if (bmpinfo.h > 0x7fffffff) {
+      bmpinfo.h = (-bmpinfo.h) & 0xffffffff;
       bmpinfo.topdown = 1;
     } else {
       bmpinfo.topdown = 0;
     }
+    if (bmpinfo.h > 0x7fffffff) {
+      goto format_error;
+    }
   } else if (bmpinfo.InfoSize == 12) {
     /* old OS/2 format */
     bmpinfo.ctbits = 24; /* sample size in color table */
@@ -576,7 +590,7 @@
 
   /* color table, present only if bmpinfo.bits <= 8. */
   if (bmpinfo.bits <= 8) {
-    coltable = (int *) malloc(bmpinfo.ncolors * sizeof(int));
+    coltable = (int *) calloc(bmpinfo.ncolors, sizeof(int));
     if (!coltable) {
       goto std_error;
     }
diff -u -r potrace-1.11/src/greymap.h potrace-1.11-patched/src/greymap.h
--- potrace-1.11/src/greymap.h  2013-02-20 00:51:44.000000000 +0100
+++ potrace-1.11-patched/src/greymap.h  2015-03-20 23:57:39.710432465 +0100
@@ -22,7 +22,7 @@
 /* macros for accessing pixel at index (x,y). Note that the origin is
    in the *lower* left corner. U* macros omit the bounds check. */
 
-#define gm_index(gm, x, y) (&(gm)->map[(x)+(y)*(gm)->w])
+#define gm_index(gm, x, y) (&(gm)->map[(x)+(y)*(ssize_t)(gm)->w])
 #define gm_safe(gm, x, y) ((int)(x)>=0 && (int)(x)<(gm)->w && (int)(y)>=0 && 
(int)(y)<(gm)->h)
 #define gm_bound(x, m) ((x)<0 ? 0 : (x)>=(m) ? (m)-1 : (x))
 #define GM_UGET(gm, x, y) (*gm_index(gm, x, y))
diff -u -r potrace-1.11/src/mkbitmap.c potrace-1.11-patched/src/mkbitmap.c
--- potrace-1.11/src/mkbitmap.c 2013-02-20 00:51:44.000000000 +0100
+++ potrace-1.11-patched/src/mkbitmap.c 2015-03-20 23:57:39.712432461 +0100
@@ -22,8 +22,8 @@
 #include "config.h"
 #endif
 
-#define SAFE_MALLOC(var, n, typ) \
-  if ((var = (typ *)malloc((n)*sizeof(typ))) == NULL) goto malloc_error 
+#define SAFE_CALLOC(var, n, typ) \
+  if ((var = (typ *)calloc(n, sizeof(typ))) == NULL) goto calloc_error 
 
 /* structure to hold command line options */
 struct info_s {
@@ -258,7 +258,7 @@
 /* same as interpolate_linear, except use cubic interpolation (slower
    and better). */
 
-/* we need this typedef so that the SAFE_MALLOC macro will work */
+/* we need this typedef so that the SAFE_CALLOC macro will work */
 typedef double double4[4];
 
 static void *interpolate_cubic(greymap_t *gm, int s, int bilevel, double c) {
@@ -272,8 +272,8 @@
   greymap_t *gm_out = NULL;
   potrace_bitmap_t *bm_out = NULL;
 
-  SAFE_MALLOC(poly, s, double4);
-  SAFE_MALLOC(window, s, double4);
+  SAFE_CALLOC(poly, s, double4);
+  SAFE_CALLOC(window, s, double4);
 
   w = gm->w;
   h = gm->h;
@@ -282,14 +282,14 @@
   if (bilevel) {
     bm_out = bm_new(w*s, h*s);
     if (!bm_out) {
-      goto malloc_error;
+      goto calloc_error;
     }
     bm_clear(bm_out, 0);
     c1 = c * 255;
   } else {
     gm_out = gm_new(w*s, h*s);
     if (!gm_out) {
-      goto malloc_error;
+      goto calloc_error;
     }
   }
 
@@ -361,7 +361,7 @@
     return (void *)gm_out;
   }
 
- malloc_error:
+ calloc_error:
   free(poly);
   free(window);
   return NULL;
diff -u -r potrace-1.11/src/potracelib_demo.c 
potrace-1.11-patched/src/potracelib_demo.c
--- potrace-1.11/src/potracelib_demo.c  2013-02-20 00:51:44.000000000 +0100
+++ potrace-1.11-patched/src/potracelib_demo.c  2015-03-20 23:57:39.713432459 
+0100
@@ -43,7 +43,7 @@
   bm->w = w;
   bm->h = h;
   bm->dy = dy;
-  bm->map = (potrace_word *) malloc(dy * h * BM_WORDSIZE);
+  bm->map = (potrace_word *) calloc(h, dy * BM_WORDSIZE);
   if (!bm->map) {
     free(bm);
     return NULL;
diff -u -r potrace-1.11/src/render.c potrace-1.11-patched/src/render.c
--- potrace-1.11/src/render.c   2013-02-20 00:51:44.000000000 +0100
+++ potrace-1.11-patched/src/render.c   2015-03-20 23:57:39.714432457 +0100
@@ -52,7 +52,7 @@
   }
   memset(rm, 0, sizeof(render_t));
   rm->gm = gm;
-  rm->incrow_buf = (int *) malloc(gm->h * sizeof(int));
+  rm->incrow_buf = (int *) calloc(gm->h, sizeof(int));
   if (!rm->incrow_buf) {
     free(rm);
     return NULL;
diff -u -r potrace-1.11/src/trace.c potrace-1.11-patched/src/trace.c
--- potrace-1.11/src/trace.c    2013-02-20 00:51:44.000000000 +0100
+++ potrace-1.11-patched/src/trace.c    2015-03-20 23:57:39.716432453 +0100
@@ -21,8 +21,8 @@
 #define COS179 -0.999847695156  /* the cosine of 179 degrees */
 
 /* ---------------------------------------------------------------------- */
-#define SAFE_MALLOC(var, n, typ) \
-  if ((var = (typ *)malloc((n)*sizeof(typ))) == NULL) goto malloc_error 
+#define SAFE_CALLOC(var, n, typ) \
+  if ((var = (typ *)calloc(n, sizeof(typ))) == NULL) goto calloc_error 
 
 /* ---------------------------------------------------------------------- */
 /* auxiliary functions */
@@ -265,7 +265,7 @@
   int i, x, y;
   int n = pp->len;
 
-  SAFE_MALLOC(pp->sums, pp->len+1, sums_t);
+  SAFE_CALLOC(pp->sums, pp->len+1, sums_t);
 
   /* origin */
   pp->x0 = pp->pt[0].x;
@@ -284,7 +284,7 @@
   }
   return 0;  
 
- malloc_error:
+ calloc_error:
   return 1;
 }
 
@@ -331,8 +331,8 @@
   point_t dk;  /* direction of k-k1 */
   int a, b, c, d;
 
-  SAFE_MALLOC(pivk, n, int);
-  SAFE_MALLOC(nc, n, int);
+  SAFE_CALLOC(pivk, n, int);
+  SAFE_CALLOC(nc, n, int);
 
   /* initialize the nc data structure. Point from each point to the
      furthest future point to which it is connected by a vertical or
@@ -349,7 +349,7 @@
     nc[i] = k;
   }
 
-  SAFE_MALLOC(pp->lon, n, int);
+  SAFE_CALLOC(pp->lon, n, int);
 
   /* determine pivot points: for each i, let pivk[i] be the furthest k
      such that all j with i<j<k lie on a line connecting i,k. */
@@ -458,7 +458,7 @@
   free(nc);
   return 0;
 
- malloc_error:
+ calloc_error:
   free(pivk);
   free(nc);
   return 1;
@@ -537,12 +537,12 @@
   double best;
   int c;
 
-  SAFE_MALLOC(pen, n+1, double);
-  SAFE_MALLOC(prev, n+1, int);
-  SAFE_MALLOC(clip0, n, int);
-  SAFE_MALLOC(clip1, n+1, int);
-  SAFE_MALLOC(seg0, n+1, int);
-  SAFE_MALLOC(seg1, n+1, int);
+  SAFE_CALLOC(pen, n+1, double);
+  SAFE_CALLOC(prev, n+1, int);
+  SAFE_CALLOC(clip0, n, int);
+  SAFE_CALLOC(clip1, n+1, int);
+  SAFE_CALLOC(seg0, n+1, int);
+  SAFE_CALLOC(seg1, n+1, int);
 
   /* calculate clipped paths */
   for (i=0; i<n; i++) {
@@ -604,7 +604,7 @@
   }
 
   pp->m = m;
-  SAFE_MALLOC(pp->po, m, int);
+  SAFE_CALLOC(pp->po, m, int);
 
   /* read off shortest path */
   for (i=n, j=m-1; i>0; j--) {
@@ -620,7 +620,7 @@
   free(seg1);
   return 0;
   
- malloc_error:
+ calloc_error:
   free(pen);
   free(prev);
   free(clip0);
@@ -655,13 +655,13 @@
   dpoint_t s;
   int r;
 
-  SAFE_MALLOC(ctr, m, dpoint_t);
-  SAFE_MALLOC(dir, m, dpoint_t);
-  SAFE_MALLOC(q, m, quadform_t);
+  SAFE_CALLOC(ctr, m, dpoint_t);
+  SAFE_CALLOC(dir, m, dpoint_t);
+  SAFE_CALLOC(q, m, quadform_t);
 
   r = privcurve_init(&pp->curve, m);
   if (r) {
-    goto malloc_error;
+    goto calloc_error;
   }
   
   /* calculate "optimal" point-slope representation for each line
@@ -827,7 +827,7 @@
   free(q);
   return 0;
 
- malloc_error:
+ calloc_error:
   free(ctr);
   free(dir);
   free(q);
@@ -1075,12 +1075,12 @@
   int *convc = NULL; /* conv[m]: pre-computed convexities */
   double *areac = NULL; /* cumarea[m+1]: cache for fast area computation */
 
-  SAFE_MALLOC(pt, m+1, int);
-  SAFE_MALLOC(pen, m+1, double);
-  SAFE_MALLOC(len, m+1, int);
-  SAFE_MALLOC(opt, m+1, opti_t);
-  SAFE_MALLOC(convc, m, int);
-  SAFE_MALLOC(areac, m+1, double);
+  SAFE_CALLOC(pt, m+1, int);
+  SAFE_CALLOC(pen, m+1, double);
+  SAFE_CALLOC(len, m+1, int);
+  SAFE_CALLOC(opt, m+1, opti_t);
+  SAFE_CALLOC(convc, m, int);
+  SAFE_CALLOC(areac, m+1, double);
 
   /* pre-calculate convexity: +1 = right turn, -1 = left turn, 0 = corner */
   for (i=0; i<m; i++) {
@@ -1134,10 +1134,10 @@
   om = len[m];
   r = privcurve_init(&pp->ocurve, om);
   if (r) {
-    goto malloc_error;
+    goto calloc_error;
   }
-  SAFE_MALLOC(s, om, double);
-  SAFE_MALLOC(t, om, double);
+  SAFE_CALLOC(s, om, double);
+  SAFE_CALLOC(t, om, double);
 
   j = m;
   for (i=om-1; i>=0; i--) {
@@ -1182,7 +1182,7 @@
   free(areac);
   return 0;
 
- malloc_error:
+ calloc_error:
   free(pt);
   free(pen);
   free(len);

Reply via email to