From 43e9bc1c7a8268e4083127ab64028aef7bef2a10 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ra=C3=BAl=20Mar=C3=ADn=20Rodr=C3=ADguez?= Date: Thu, 15 Nov 2018 16:10:36 +0000 Subject: [PATCH] Avoid undefined behaviour in gserialized_estimate 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 | 1 + postgis/gserialized_estimate.c | 34 +++++++++++++++++++++++----------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/NEWS b/NEWS index 350d1f40f..18abb56ce 100644 --- 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 diff --git a/postgis/gserialized_estimate.c b/postgis/gserialized_estimate.c index aa9269016..f5f2ce5fa 100644 --- a/postgis/gserialized_estimate.c +++ b/postgis/gserialized_estimate.c @@ -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; -- 2.40.0