From f062b42c0ea8dddebdc6a152fd16152de215d614 Mon Sep 17 00:00:00 2001 From: Dan Bloomberg Date: Wed, 28 Oct 2020 17:37:30 -0700 Subject: [PATCH] Issue 26393: morphapp_fuzzer: Divide-by-zero in blockconvLow * Removed the code that allowed divide by zero for tiny pix * Ditto for 4 other block convolution functions. --- src/convolve.c | 90 ++++++++++++++++++++++---------------------------- 1 file changed, 40 insertions(+), 50 deletions(-) diff --git a/src/convolve.c b/src/convolve.c index 72afa9415..fda032ba6 100644 --- a/src/convolve.c +++ b/src/convolve.c @@ -114,7 +114,7 @@ static void blocksumLow(l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpl, /*! * \brief pixBlockconv() * - * \param[in] pix 8 or 32 bpp; or 2, 4 or 8 bpp with colormap + * \param[in] pix 8 or 32 bpp; or 2, 4 or 8 bpp with colormap * \param[in] wc, hc half width/height of convolution kernel * \return pixd, or NULL on error * @@ -122,9 +122,10 @@ static void blocksumLow(l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpl, * Notes: * (1) The full width and height of the convolution kernel * are (2 * wc + 1) and (2 * hc + 1) - * (2) Returns a copy if both wc and hc are 0 + * (2) Returns a copy if either wc or hc are 0 * (3) Require that w >= 2 * wc + 1 and h >= 2 * hc + 1, - * where (w,h) are the dimensions of pixs. + * where (w,h) are the dimensions of pixs. Otherwise, + * return a copy. * */ PIX * @@ -139,17 +140,14 @@ PIX *pixs, *pixd, *pixr, *pixrc, *pixg, *pixgc, *pixb, *pixbc; if (!pix) return (PIX *)ERROR_PTR("pix not defined", procName, NULL); - if (wc < 0) wc = 0; - if (hc < 0) hc = 0; + if (wc <= 0 || hc <= 0) + return pixCopy(NULL, pix); pixGetDimensions(pix, &w, &h, &d); if (w < 2 * wc + 1 || h < 2 * hc + 1) { - wc = L_MIN(wc, (w - 1) / 2); - hc = L_MIN(hc, (h - 1) / 2); - L_WARNING("kernel too large; reducing!\n", procName); - L_INFO("wc = %d, hc = %d\n", procName, wc, hc); + L_ERROR("kernel is too large: w = %d, wc = %d, h = %d, hc = %d\n", + procName, w, wc, h, hc); + return pixCopy(NULL, pix); /* no-op */ } - if (wc == 0 && hc == 0) /* no-op */ - return pixCopy(NULL, pix); /* Remove colormap if necessary */ if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) { @@ -205,9 +203,10 @@ PIX *pixs, *pixd, *pixr, *pixrc, *pixg, *pixgc, *pixb, *pixbc; * returning; otherwise, just use the input accum pix. * (2) The full width and height of the convolution kernel * are (2 * wc + 1) and (2 * hc + 1). - * (3) Returns a copy if both wc and hc are 0. + * (3) Returns a copy if either wc or hc are 0 * (4) Require that w >= 2 * wc + 1 and h >= 2 * hc + 1, - * where (w,h) are the dimensions of pixs. + * where (w,h) are the dimensions of pixs. Otherwise, + * return a copy. * */ PIX * @@ -227,16 +226,13 @@ PIX *pixd, *pixt; pixGetDimensions(pixs, &w, &h, &d); if (d != 8) return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); - if (wc < 0) wc = 0; - if (hc < 0) hc = 0; + if (wc <= 0 || hc <= 0) /* no-op */ + return pixCopy(NULL, pixs); if (w < 2 * wc + 1 || h < 2 * hc + 1) { - wc = L_MIN(wc, (w - 1) / 2); - hc = L_MIN(hc, (h - 1) / 2); - L_WARNING("kernel too large; reducing!\n", procName); - L_INFO("wc = %d, hc = %d\n", procName, wc, hc); + L_ERROR("kernel is too large: w = %d, wc = %d, h = %d, hc = %d\n", + procName, w, wc, h, hc); + return pixCopy(NULL, pixs); } - if (wc == 0 && hc == 0) /* no-op */ - return pixCopy(NULL, pixs); if (pixacc) { if (pixGetDepth(pixacc) == 32) { @@ -612,7 +609,7 @@ l_uint32 *lines, *lined, *linedp; * are (2 * wc + 1) and (2 * hc + 1). * (2) Require that w >= 2 * wc + 1 and h >= 2 * hc + 1, * where (w,h) are the dimensions of pixs. - * (3) Returns a copy if both wc and hc are 0. + * (3) Returns a copy if either wc or hc are 0. * (3) Adds mirrored border to avoid treating the boundary pixels * specially. Note that we add wc + 1 pixels to the left * and wc to the right. The added width is 2 * wc + 1 pixels, @@ -650,16 +647,13 @@ PIX *pixsb, *pixacc, *pixd; pixGetDimensions(pixs, &w, &h, &d); if (d != 8) return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); - if (wc < 0) wc = 0; - if (hc < 0) hc = 0; + if (wc <= 0 || hc <= 0) /* no-op */ + return pixCopy(NULL, pixs); if (w < 2 * wc + 1 || h < 2 * hc + 1) { - wc = L_MIN(wc, (w - 1) / 2); - hc = L_MIN(hc, (h - 1) / 2); - L_WARNING("kernel too large; reducing!\n", procName); - L_INFO("wc = %d, hc = %d\n", procName, wc, hc); - } - if (wc == 0 && hc == 0) /* no-op */ + L_ERROR("kernel is too large: w = %d, wc = %d, h = %d, hc = %d\n", + procName, w, wc, h, hc); return pixCopy(NULL, pixs); + } if ((pixsb = pixAddMirroredBorder(pixs, wc + 1, wc, hc + 1, hc)) == NULL) return (PIX *)ERROR_PTR("pixsb not made", procName, NULL); @@ -707,9 +701,10 @@ PIX *pixsb, *pixacc, *pixd; * Notes: * (1) The full width and height of the convolution kernel * are (2 * wc + 1) and (2 * hc + 1) - * (2) Returns a copy if both wc and hc are 0 + * (2) Returns a copy if either wc or hc are 0. * (3) Require that w >= 2 * wc + 1 and h >= 2 * hc + 1, - * where (w,h) are the dimensions of pixs. + * where (w,h) are the dimensions of pixs. Otherwise, + * return a copy. * (4) For nx == ny == 1, this defaults to pixBlockconv(), which * is typically about twice as fast, and gives nearly * identical results as pixBlockconvGrayTile(). @@ -741,19 +736,16 @@ PIXTILING *pt; if (!pix) return (PIX *)ERROR_PTR("pix not defined", procName, NULL); - if (wc < 0) wc = 0; - if (hc < 0) hc = 0; - pixGetDimensions(pix, &w, &h, &d); - if (w < 2 * wc + 3 || h < 2 * hc + 3) { - wc = L_MAX(0, L_MIN(wc, (w - 3) / 2)); - hc = L_MAX(0, L_MIN(hc, (h - 3) / 2)); - L_WARNING("kernel too large; reducing!\n", procName); - L_INFO("wc = %d, hc = %d\n", procName, wc, hc); - } - if (wc == 0 && hc == 0) /* no-op */ + if (wc <= 0 || hc <= 0) /* no-op */ return pixCopy(NULL, pix); if (nx <= 1 && ny <= 1) return pixBlockconv(pix, wc, hc); + pixGetDimensions(pix, &w, &h, &d); + if (w < 2 * wc + 3 || h < 2 * hc + 3) { + L_ERROR("kernel is too large: w = %d, wc = %d, h = %d, hc = %d\n", + procName, w, wc, h, hc); + return pixCopy(NULL, pix); + } /* Test to see if the tiles are too small. The required * condition is that the tile dimensions must be at least @@ -846,9 +838,10 @@ PIXTILING *pt; * left and right, and with (hc + 1) pixels on top and bottom. * The returned pix has these stripped off; they are only used * for computation. - * (3) Returns a copy if both wc and hc are 0 - * (4) Require that w > 2 * wc + 1 and h > 2 * hc + 1, - * where (w,h) are the dimensions of pixs. + * (3) Returns a copy if either wc or hc are 0. + * (4) Require that w > 2 * wc + 3 and h > 2 * hc + 3, + * where (w,h) are the dimensions of pixs. Otherwise, + * return a copy. * */ PIX * @@ -870,16 +863,13 @@ PIX *pixt, *pixd; pixGetDimensions(pixs, &w, &h, &d); if (d != 8) return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); - if (wc < 0) wc = 0; - if (hc < 0) hc = 0; + if (wc <= 0 || hc <= 0) /* no-op */ + return pixCopy(NULL, pixs); if (w < 2 * wc + 3 || h < 2 * hc + 3) { - wc = L_MAX(0, L_MIN(wc, (w - 3) / 2)); - hc = L_MAX(0, L_MIN(hc, (h - 3) / 2)); - L_WARNING("kernel too large; reducing!\n", procName); - L_INFO("wc = %d, hc = %d\n", procName, wc, hc); - } - if (wc == 0 && hc == 0) + L_ERROR("kernel is too large: w = %d, wc = %d, h = %d, hc = %d\n", + procName, w, wc, h, hc); return pixCopy(NULL, pixs); + } wd = w - 2 * wc; hd = h - 2 * hc;