[postgis-tickets] r14508 - #3404, ST_ClusterWithin crashes backend

Daniel Baston dbaston at gmail.com
Sun Dec 20 13:43:11 PST 2015


Author: dbaston
Date: 2015-12-20 13:43:11 -0800 (Sun, 20 Dec 2015)
New Revision: 14508

Modified:
   branches/2.2/
   branches/2.2/liblwgeom/cunit/cu_unionfind.c
   branches/2.2/liblwgeom/lwgeom_geos_cluster.c
   branches/2.2/liblwgeom/lwunionfind.c
Log:
#3404, ST_ClusterWithin crashes backend


Property changes on: branches/2.2
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/1.5:7092,7136,7138,7460
/spike/pramsey/geodetic:4288-4493
/trunk:14474
   + /branches/1.5:7092,7136,7138,7460
/spike/pramsey/geodetic:4288-4493
/trunk:14474,14507

Modified: branches/2.2/liblwgeom/cunit/cu_unionfind.c
===================================================================
--- branches/2.2/liblwgeom/cunit/cu_unionfind.c	2015-12-20 21:29:38 UTC (rev 14507)
+++ branches/2.2/liblwgeom/cunit/cu_unionfind.c	2015-12-20 21:43:11 UTC (rev 14508)
@@ -87,6 +87,29 @@
 	lwfree(ids_by_cluster);
 }
 
+static void test_unionfind_path_compression(void)
+{
+	UNIONFIND* uf = UF_create(5);
+	uint32_t i;
+
+	uf->clusters[1] = 0;
+	uf->clusters[2] = 1;
+	uf->clusters[3] = 2;
+	uf->clusters[4] = 3;
+
+	/* Calling "find" on a leaf should attach all nodes between the root and the
+	 * leaf directly to the root. */
+	uint32_t root = UF_find(uf, 4);
+	for (i = 0; i < uf->N; i++)
+	{
+		/* Verify that all cluster references have been updated to point
+		 * directly to the root. */
+		CU_ASSERT_EQUAL(root, uf->clusters[i]);
+	}
+
+	UF_destroy(uf);
+}
+
 void unionfind_suite_setup(void);
 void unionfind_suite_setup(void)
 {
@@ -94,4 +117,5 @@
 	PG_ADD_TEST(suite, test_unionfind_create);
 	PG_ADD_TEST(suite, test_unionfind_union);
 	PG_ADD_TEST(suite, test_unionfind_ordered_by_cluster);
+	PG_ADD_TEST(suite, test_unionfind_path_compression);
 }

Modified: branches/2.2/liblwgeom/lwgeom_geos_cluster.c
===================================================================
--- branches/2.2/liblwgeom/lwgeom_geos_cluster.c	2015-12-20 21:29:38 UTC (rev 14507)
+++ branches/2.2/liblwgeom/lwgeom_geos_cluster.c	2015-12-20 21:43:11 UTC (rev 14508)
@@ -336,10 +336,15 @@
 		if ((i == num_geoms - 1) ||
 		        (UF_find(uf, ordered_components[i]) != UF_find(uf, ordered_components[i+1])))
 		{
+			if (k >= uf->num_clusters) {
+				/* Should not get here - it means that we have more clusters than uf->num_clusters thinks we should. */
+				return LW_FAILURE;
+			}
+
 			if (is_lwgeom)
 			{
-				LWGEOM** components = lwalloc(num_geoms * sizeof(LWGEOM*));
-				memcpy(components, geoms_in_cluster, num_geoms * sizeof(LWGEOM*));
+				LWGEOM** components = lwalloc(j * sizeof(LWGEOM*));
+				memcpy(components, geoms_in_cluster, j * sizeof(LWGEOM*));
 				(*clusterGeoms)[k++] = lwcollection_construct(COLLECTIONTYPE, components[0]->srid, NULL, j, (LWGEOM**) components);
 			}
 			else

Modified: branches/2.2/liblwgeom/lwunionfind.c
===================================================================
--- branches/2.2/liblwgeom/lwunionfind.c	2015-12-20 21:29:38 UTC (rev 14507)
+++ branches/2.2/liblwgeom/lwunionfind.c	2015-12-20 21:43:11 UTC (rev 14508)
@@ -47,11 +47,17 @@
 uint32_t
 UF_find (UNIONFIND* uf, uint32_t i)
 {
-	while (uf->clusters[i] != i)
-	{
-		uf->clusters[i] = uf->clusters[uf->clusters[i]];
-		i = uf->clusters[i];
+	uint32_t base = i;
+	while (uf->clusters[base] != base) {
+		base = uf->clusters[base];
 	}
+
+	while (i != base) {
+		uint32_t next = uf->clusters[i];
+		uf->clusters[i] = base;
+		i = next;
+	}
+
 	return i;
 }
 



More information about the postgis-tickets mailing list