From 1e1c4a618ec6d29e8addf919a5eea5bab61eef5a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ra=C3=BAl=20Mar=C3=ADn=20Rodr=C3=ADguez?= Date: Fri, 7 Sep 2018 11:19:22 +0000 Subject: [PATCH] Fix undefined behaviour in ptarray_segmentize2d Closes #4173 References #4153 Closes https://github.com/postgis/postgis/pull/292 git-svn-id: http://svn.osgeo.org/postgis/trunk@16723 b70326c6-7e19-0410-871a-916f4a2858ee --- NEWS | 1 + liblwgeom/cunit/cu_measures.c | 16 ++++++++++++---- liblwgeom/ptarray.c | 13 ++++++++++++- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 555a6a29a..c71fa9188 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ PostGIS 3.0.0 - #4163, MVT: Fix resource leak when the first geometry is NULL (Raúl Marín) - #4161, MVT: Drop geometries smaller than the resolution (Raúl Marín) - #4172, Fix memory leak in lwgeom_offsetcurve (Raúl Marín) + - #4173, Fix undefined behaviour in ptarray_segmentize2d (Raúl Marín) PostGIS 2.5.0rc1 2018/08/19 diff --git a/liblwgeom/cunit/cu_measures.c b/liblwgeom/cunit/cu_measures.c index 569a7e9c4..d94b15487 100644 --- a/liblwgeom/cunit/cu_measures.c +++ b/liblwgeom/cunit/cu_measures.c @@ -527,17 +527,23 @@ test_lwgeom_segmentize2d(void) lwgeom_free(linein); lwgeom_free(lineout); + /* test too many segments */ + linein = lwgeom_from_wkt("LINESTRING(0 0,10 0)", LW_PARSER_CHECK_NONE); + lineout = lwgeom_segmentize2d(linein, 1e-100); + CU_ASSERT_EQUAL(lineout, NULL); + lwgeom_free(linein); + /* test interruption */ linein = lwgeom_from_wkt("LINESTRING(0 0,10 0)", LW_PARSER_CHECK_NONE); lwgeom_request_interrupt(); - lineout = lwgeom_segmentize2d(linein, 1e-100); + lineout = lwgeom_segmentize2d(linein, INT32_MAX); CU_ASSERT_EQUAL(lineout, NULL); lwgeom_free(linein); linein = lwgeom_from_wkt("MULTILINESTRING((0 0,10 0),(20 0, 30 0))", LW_PARSER_CHECK_NONE); lwgeom_request_interrupt(); - lineout = lwgeom_segmentize2d(linein, 1e-100); + lineout = lwgeom_segmentize2d(linein, INT32_MAX); CU_ASSERT_EQUAL(lineout, NULL); lwgeom_free(linein); @@ -545,7 +551,7 @@ test_lwgeom_segmentize2d(void) "MULTIPOLYGON(((0 0,20 0,20 20,0 20,0 0),(2 2,2 4,4 4,4 2,2 2),(6 6,6 8,8 8,8 6,6 6)),((40 0,40 20,60 20,60 0,40 0),(42 2,42 4,44 4,44 2,42 2)))" , LW_PARSER_CHECK_NONE); lwgeom_request_interrupt(); - lineout = lwgeom_segmentize2d(linein, 1e-100); + lineout = lwgeom_segmentize2d(linein, INT32_MAX); CU_ASSERT_EQUAL(lineout, NULL); lwgeom_free(linein); @@ -554,13 +560,15 @@ test_lwgeom_segmentize2d(void) , LW_PARSER_CHECK_NONE); CU_ASSERT_FATAL(linein != NULL); lwgeom_request_interrupt(); - lineout = lwgeom_segmentize2d(linein, 1e-100); + lineout = lwgeom_segmentize2d(linein, INT32_MAX); CU_ASSERT_EQUAL(lineout, NULL); lwgeom_free(linein); linein = lwgeom_from_wkt("LINESTRING(20 0, 30 0)", LW_PARSER_CHECK_NONE); + CU_ASSERT_FATAL(linein != NULL); /* NOT INTERRUPTED */ lineout = lwgeom_segmentize2d(linein, 5); + CU_ASSERT_NOT_EQUAL_FATAL(lineout, NULL); strout = lwgeom_to_ewkt(lineout); ASSERT_STRING_EQUAL(strout, "LINESTRING(20 0,25 0,30 0)"); lwfree(strout); diff --git a/liblwgeom/ptarray.c b/liblwgeom/ptarray.c index 1e51119cd..c8ef97ebb 100644 --- a/liblwgeom/ptarray.c +++ b/liblwgeom/ptarray.c @@ -442,12 +442,23 @@ ptarray_segmentize2d(const POINTARRAY *ipa, double dist) * breaks those "strict" rules. */ POINT4D *p1ptr=&p1, *p2ptr=&p2; + double segments; getPoint4d_p(ipa, i, &p2); segdist = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr); /* Split input segment into shorter even chunks */ - nseg = ceil(segdist / dist); + segments = ceil(segdist / dist); + + /* Uses INT32_MAX instead of UINT32_MAX to be safe that it fits */ + if (segments >= INT32_MAX) + { + lwnotice("%s:%d - %s: Too many segments required (%e)", + __FILE__, __LINE__,__func__, segments); + ptarray_free(opa); + return NULL; + } + nseg = segments; for (j = 1; j < nseg; j++) { -- 2.40.0