[SCM] PostGIS branch stable-3.2 updated. 3.2.7-57-g87f9a82db

git at osgeo.org git at osgeo.org
Mon Dec 15 16:13:29 PST 2025


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "PostGIS".

The branch, stable-3.2 has been updated
       via  87f9a82dbf195c0f3d57e12b32be4d4b5b5eb4ac (commit)
      from  6e2102f01c0f9019c53ba5ca7a975834805326e5 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 87f9a82dbf195c0f3d57e12b32be4d4b5b5eb4ac
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date:   Mon Dec 15 15:56:20 2025 -0800

    Convert POLYGON(EMPTY) a polygon with an empty ring into
    POLYGON EMPTY a polygon with no rings, in the WKB input
    routine. Handle any existing POLYGON(EMPTY) in the
    gserialized_is_empty routine. References #6028

diff --git a/NEWS b/NEWS
index 3832d8c37..fcbb2210c 100644
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,7 @@ Proj 4.9+ required.
  - #5991, CircularString distance error (Paul Ramsey)
  - #5962, Consistent clipping of MULTI/POINT (Paul Ramsey)
  - #5989, CurvePolygon distance error (Paul Ramsey)
+ - #6028, Crash indexing malformed empty polygon (Paul Ramsey)
 
 
 PostGIS 3.2.8
diff --git a/liblwgeom/cunit/cu_gserialized2.c b/liblwgeom/cunit/cu_gserialized2.c
index 1f86dd080..6f8217c15 100644
--- a/liblwgeom/cunit/cu_gserialized2.c
+++ b/liblwgeom/cunit/cu_gserialized2.c
@@ -271,33 +271,48 @@ static void test_gserialized2_is_empty(void)
 {
 	int i = 0;
 	struct gserialized_empty_cases {
-		const char* wkt;
+		int ishex;
+		const char* txt;
 		int isempty;
 	};
 
 	struct gserialized_empty_cases cases[] = {
-		{ "POINT EMPTY", 1 },
-		{ "POINT(1 1)", 0 },
-		{ "LINESTRING EMPTY", 1 },
-		{ "MULTILINESTRING EMPTY", 1 },
-		{ "MULTILINESTRING(EMPTY)", 1 },
-		{ "MULTILINESTRING(EMPTY,EMPTY)", 1 },
-		{ "MULTILINESTRING(EMPTY,(0 0,1 1))", 0 },
-		{ "MULTILINESTRING((0 0,1 1),EMPTY)", 0 },
-		{ "MULTILINESTRING(EMPTY,(0 0,1 1),EMPTY)", 0 },
-		{ "MULTILINESTRING(EMPTY,EMPTY,EMPTY)", 1 },
-		{ "GEOMETRYCOLLECTION(POINT EMPTY,MULTILINESTRING(EMPTY,EMPTY,EMPTY))", 1 },
-		{ "GEOMETRYCOLLECTION(POINT EMPTY,MULTILINESTRING(EMPTY),POINT(1 1))", 0 },
-		{ "GEOMETRYCOLLECTION(POINT EMPTY,MULTILINESTRING(EMPTY, (0 0)),POINT EMPTY)", 0 },
-		{ "GEOMETRYCOLLECTION(POLYGON EMPTY,POINT EMPTY,MULTILINESTRING(EMPTY,EMPTY),POINT EMPTY)", 1 },
-		{ "GEOMETRYCOLLECTION(POLYGON EMPTY,GEOMETRYCOLLECTION(POINT EMPTY),MULTILINESTRING(EMPTY,EMPTY),POINT EMPTY)", 1 },
-		{ NULL, 0 }
+		{ 0, "POINT EMPTY", 1 },
+		{ 0, "POINT(1 1)", 0 },
+		{ 0, "LINESTRING EMPTY", 1 },
+		{ 0, "MULTILINESTRING EMPTY", 1 },
+		{ 0, "MULTILINESTRING(EMPTY)", 1 },
+		{ 0, "MULTILINESTRING(EMPTY,EMPTY)", 1 },
+		{ 0, "MULTILINESTRING(EMPTY,(0 0,1 1))", 0 },
+		{ 0, "MULTILINESTRING((0 0,1 1),EMPTY)", 0 },
+		{ 0, "MULTILINESTRING(EMPTY,(0 0,1 1),EMPTY)", 0 },
+		{ 0, "MULTILINESTRING(EMPTY,EMPTY,EMPTY)", 1 },
+		{ 0, "MULTIPOLYGON (((9 9, 9 1, 1 1, 2 4, 7 7, 9 9)), EMPTY)", 0 },
+		{ 0, "GEOMETRYCOLLECTION(POINT EMPTY,MULTILINESTRING(EMPTY,EMPTY,EMPTY))", 1 },
+		{ 0, "GEOMETRYCOLLECTION(POINT EMPTY,MULTILINESTRING(EMPTY),POINT(1 1))", 0 },
+		{ 0, "GEOMETRYCOLLECTION(POINT EMPTY,MULTILINESTRING(EMPTY, (0 0)),POINT EMPTY)", 0 },
+		{ 0, "GEOMETRYCOLLECTION(POLYGON EMPTY,POINT EMPTY,MULTILINESTRING(EMPTY,EMPTY),POINT EMPTY)", 1 },
+		{ 0, "GEOMETRYCOLLECTION(POLYGON EMPTY,GEOMETRYCOLLECTION(POINT EMPTY),MULTILINESTRING(EMPTY,EMPTY),POINT EMPTY)", 1 },
+		{ 1, "0101000000000000000000F87F000000000000F87F", 1 }, /* POINT EMPTY */
+		{ 1, "010200000000000000", 1 }, /* LINESTRING EMPTY */
+		{ 1, "010400000000000000", 1 }, /* MULTIPOINT EMPTY */
+		{ 1, "0105000000020000000102000000020000000000000000000000000000000000000000000000000000000000000000000000010200000000000000", 0 }, /* MULTILINESTRING ((0 0, 0 0), EMPTY) */
+		{ 1, "0105000000020000000102000000000000000102000000020000000000000000000000000000000000000000000000000000000000000000000000", 0 }, /* MULTILINESTRING (EMPTY,(0 0, 0 0)) */
+		{ 1, "010300000000000000", 1 }, /* POLYGON EMPTY */
+		{ 1, "01030000000100000000000000", 1 }, /* POLYGON(EMPTY) */
+		{ 1, "010300000002000000000000000100000000000000000000000000000000000000", 0 }, /* POLYGON(EMPTY, (0 0)) */
+		{ 1, "0107000000030000000102000000000000000103000000020000000000000000000000010200000000000000", 1}, /* GEOMETRYCOLLECTION(LINESTRING EMPTY, POLYGON(EMPTY, EMPTY), LINESTRING EMPTY) */
+		{ 1, NULL, 0 }
 	};
 
-	while( cases[i].wkt )
+	while( cases[i].txt )
 	{
-		// i = 11;
-		LWGEOM *lw = lwgeom_from_wkt(cases[i].wkt, LW_PARSER_CHECK_NONE);
+		LWGEOM *lw = NULL;
+		if (cases[i].ishex)
+			lw = lwgeom_from_hexwkb(cases[i].txt, LW_PARSER_CHECK_NONE);
+		else
+			lw = lwgeom_from_wkt(cases[i].txt, LW_PARSER_CHECK_NONE);
+
 		GSERIALIZED *g = gserialized2_from_lwgeom(lw, 0);
 		int ie = gserialized2_is_empty(g);
 		// printf("%s: we say %d, they say %d\n", cases[i].wkt, cases[i].isempty, ie);
@@ -309,7 +324,6 @@ static void test_gserialized2_is_empty(void)
 }
 
 
-
 static void test_on_gser2_lwgeom_count_vertices(void)
 {
 	LWGEOM *lwgeom;
diff --git a/liblwgeom/gserialized2.c b/liblwgeom/gserialized2.c
index 353c107c1..ddf8250ed 100644
--- a/liblwgeom/gserialized2.c
+++ b/liblwgeom/gserialized2.c
@@ -224,16 +224,19 @@ void gserialized2_set_srid(GSERIALIZED *g, int32_t srid)
 static size_t gserialized2_is_empty_recurse(const uint8_t *p, int *isempty);
 static size_t gserialized2_is_empty_recurse(const uint8_t *p, int *isempty)
 {
-	int i;
-	int32_t type, num;
+	uint32_t type = 0, num = 0;
+
+	/* Short circuit if we found any non-empty component */
+	if (!*isempty) return 0;
 
 	memcpy(&type, p, 4);
 	memcpy(&num, p+4, 4);
 
 	if (lwtype_is_collection(type))
 	{
+		/* Recurse into collections */
 		size_t lz = 8;
-		for ( i = 0; i < num; i++ )
+		for ( uint32_t i = 0; i < num; i++ )
 		{
 			lz += gserialized2_is_empty_recurse(p+lz, isempty);
 			if (!*isempty)
@@ -244,14 +247,44 @@ static size_t gserialized2_is_empty_recurse(const uint8_t *p, int *isempty)
 	}
 	else
 	{
-		*isempty = (num == 0 ? LW_TRUE : LW_FALSE);
-		return 8;
+		size_t lz = 8;
+		/* Any non-collection with zero elements is empty */
+		if ( num == 0 )
+		{
+			*isempty = LW_TRUE;
+		}
+		/*
+		 * Special case to handle polygon with a non-zero
+		 * set of empty rings
+		 * https://trac.osgeo.org/postgis/ticket/6028
+		 */
+		else if ( num > 0 && type == POLYGONTYPE )
+		{
+			for ( uint32_t i = 0; i < num; i++ )
+			{
+				uint32_t lrnum;
+				memcpy(&lrnum, p+lz, 4);
+				lz += 4;
+				if ( lrnum > 0 )
+				{
+					*isempty = LW_FALSE;
+					return lz;
+				}
+			}
+			*isempty = LW_TRUE;
+		}
+		/* Any other non-collection with more than zero elements is not empty */
+		else
+		{
+			*isempty = LW_FALSE;
+		}
+		return lz;
 	}
 }
 
 int gserialized2_is_empty(const GSERIALIZED *g)
 {
-	int isempty = 0;
+	int isempty = LW_TRUE;
 	uint8_t *p = gserialized2_get_geometry_p(g);
 	gserialized2_is_empty_recurse(p, &isempty);
 	return isempty;
diff --git a/liblwgeom/lwin_wkb.c b/liblwgeom/lwin_wkb.c
index f1b0a568e..f92256cb5 100644
--- a/liblwgeom/lwin_wkb.c
+++ b/liblwgeom/lwin_wkb.c
@@ -578,6 +578,14 @@ static LWPOLY* lwpoly_from_wkb_state(wkb_parse_state *s)
 			return NULL;
 		}
 
+		/* Skip zero-member rings, they add nothing */
+		if ( pa->npoints == 0)
+		{
+			LWDEBUGF(2, "Skipping empty ring [%d]", i);
+			ptarray_free(pa);
+			continue;
+		}
+
 		/* Add ring to polygon */
 		if ( lwpoly_add_ring(poly, pa) == LW_FAILURE )
 		{

-----------------------------------------------------------------------

Summary of changes:
 NEWS                              |  1 +
 liblwgeom/cunit/cu_gserialized2.c | 56 ++++++++++++++++++++++++---------------
 liblwgeom/gserialized2.c          | 45 ++++++++++++++++++++++++++-----
 liblwgeom/lwin_wkb.c              |  8 ++++++
 4 files changed, 83 insertions(+), 27 deletions(-)


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list