]> granicus.if.org Git - postgis/commitdiff
Avoid undefined behaviour in gserialized_estimate
authorRaúl Marín Rodríguez <rmrodriguez@carto.com>
Thu, 15 Nov 2018 16:10:36 +0000 (16:10 +0000)
committerRaúl Marín Rodríguez <rmrodriguez@carto.com>
Thu, 15 Nov 2018 16:10:36 +0000 (16:10 +0000)
Closes #4190
Closes https://github.com/postgis/postgis/pull/315

git-svn-id: http://svn.osgeo.org/postgis/trunk@17022 b70326c6-7e19-0410-871a-916f4a2858ee

NEWS
postgis/gserialized_estimate.c

diff --git a/NEWS b/NEWS
index 350d1f40f86c1a34eb4c6073535374cc740c01a8..18abb56ceda3af8a195e0d98384c9f11398fec46 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -37,6 +37,7 @@ PostGIS 3.0.0
            ST_LocateBetween and ST_LocateBetweenElevations (Darafei Praliaskouski)
   - #2767, Documentation for AddRasterConstraint optional parameters (Sunveer Singh)
   - #4326, Allocate enough memory in gidx_to_string (Raúl Marín)
+  - #4190, Avoid undefined behaviour in gserialized_estimate (Raúl Marín)
 
 PostGIS 2.5.0
 2018/09/23
index aa92690168129edd4920f88a45f3369c9813c500..f5f2ce5fa6e0fcb0c99f39a1b8a6fa845391b4f3 100644 (file)
@@ -646,7 +646,9 @@ nd_box_expand(ND_BOX *nd_box, double expansion_factor)
        for ( d = 0; d < ND_DIMS; d++ )
        {
                size = nd_box->max[d] - nd_box->min[d];
-               if ( size <= 0 ) continue;
+               /* Avoid expanding boxes that are either too wide or too narrow*/
+               if (size < MIN_DIMENSION_WIDTH || size > MAX_DIMENSION_WIDTH)
+                       continue;
                nd_box->min[d] -= size * expansion_factor / 2;
                nd_box->max[d] += size * expansion_factor / 2;
        }
@@ -673,18 +675,26 @@ nd_box_overlap(const ND_STATS *nd_stats, const ND_BOX *nd_box, ND_IBOX *nd_ibox)
                double smin = nd_stats->extent.min[d];
                double smax = nd_stats->extent.max[d];
                double width = smax - smin;
-               int size = roundf(nd_stats->size[d]);
 
-               /* ... find cells the box overlaps with in this dimension */
-               nd_ibox->min[d] = floor(size * (nd_box->min[d] - smin) / width);
-               nd_ibox->max[d] = floor(size * (nd_box->max[d] - smin) / width);
+               if (width < MIN_DIMENSION_WIDTH)
+               {
+                       nd_ibox->min[d] = nd_ibox->max[d] = nd_stats->extent.min[d];
+               }
+               else
+               {
+                       int size = (int)roundf(nd_stats->size[d]);
+
+                       /* ... find cells the box overlaps with in this dimension */
+                       nd_ibox->min[d] = floor(size * (nd_box->min[d] - smin) / width);
+                       nd_ibox->max[d] = floor(size * (nd_box->max[d] - smin) / width);
 
-               POSTGIS_DEBUGF(5, " stats: dim %d: min %g: max %g: width %g", d, smin, smax, width);
-               POSTGIS_DEBUGF(5, " overlap: dim %d: (%d, %d)", d, nd_ibox->min[d], nd_ibox->max[d]);
+                       POSTGIS_DEBUGF(5, " stats: dim %d: min %g: max %g: width %g", d, smin, smax, width);
+                       POSTGIS_DEBUGF(5, " overlap: dim %d: (%d, %d)", d, nd_ibox->min[d], nd_ibox->max[d]);
 
-               /* Push any out-of range values into range */
-               nd_ibox->min[d] = Max(nd_ibox->min[d], 0);
-               nd_ibox->max[d] = Min(nd_ibox->max[d], size-1);
+                       /* Push any out-of range values into range */
+                       nd_ibox->min[d] = Max(nd_ibox->min[d], 0);
+                       nd_ibox->max[d] = Min(nd_ibox->max[d], size - 1);
+               }
        }
        return true;
 }
@@ -1893,7 +1903,9 @@ Datum gserialized_analyze_nd(PG_FUNCTION_ARGS)
 
        POSTGIS_DEBUGF(3, " attribute stat target: %d", attr->attstattarget);
 
-       /* Setup the minimum rows and the algorithm function */
+       /* Setup the minimum rows and the algorithm function.
+        * 300 matches the default value set in
+        * postgresql/src/backend/commands/analyze.c */
        stats->minrows = 300 * stats->attr->attstattarget;
        stats->compute_stats = compute_gserialized_stats;