[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