[SCM] PostGIS branch stable-3.0 updated. 3.0.11-21-g8736b619a
git at osgeo.org
git at osgeo.org
Mon Dec 15 16:15:22 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.0 has been updated
via 8736b619abe7f5c75848521b03e2e626e58d3e01 (commit)
from 58ef17e4fc45651f8b3e92ea9cefc34942f35e71 (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 8736b619abe7f5c75848521b03e2e626e58d3e01
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date: Mon Dec 15 15:58:43 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 d5bc6657c..1a7c37d08 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,8 @@ Proj 4.9+ required.
- #5795, [topology] Fix ST_NewEdgesSplit can cause invalid topology (Björn Harrtell)
- Handle null returns from wkb parser, Paul Ramsey
- #5818, GT-244 Fix CG_IsSolid function (Loïc Bartoletti)
+ - #6028, Crash indexing malformed empty polygon (Paul Ramsey)
+
PostGIS 3.0.11
2024/02/06
diff --git a/liblwgeom/cunit/cu_gserialized2.c b/liblwgeom/cunit/cu_gserialized2.c
index f88c74d00..34aa021f3 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 da6adb84d..572b36e2d 100644
--- a/liblwgeom/gserialized2.c
+++ b/liblwgeom/gserialized2.c
@@ -223,16 +223,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)
@@ -243,14 +246,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 1013ab89c..e2f3c7471 100644
--- a/liblwgeom/lwin_wkb.c
+++ b/liblwgeom/lwin_wkb.c
@@ -567,6 +567,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 | 2 ++
liblwgeom/cunit/cu_gserialized2.c | 56 ++++++++++++++++++++++++---------------
liblwgeom/gserialized2.c | 45 ++++++++++++++++++++++++++-----
liblwgeom/lwin_wkb.c | 8 ++++++
4 files changed, 84 insertions(+), 27 deletions(-)
hooks/post-receive
--
PostGIS
More information about the postgis-tickets
mailing list