]> granicus.if.org Git - postgis/commitdiff
#3404, ST_ClusterWithin crashes backend
authorDaniel Baston <dbaston@gmail.com>
Sun, 20 Dec 2015 21:29:38 +0000 (21:29 +0000)
committerDaniel Baston <dbaston@gmail.com>
Sun, 20 Dec 2015 21:29:38 +0000 (21:29 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@14507 b70326c6-7e19-0410-871a-916f4a2858ee

liblwgeom/cunit/cu_unionfind.c
liblwgeom/lwgeom_geos_cluster.c
liblwgeom/lwunionfind.c

index 5f679b9e5801dd83845a479d6262ff086cd24f4f..a9d1ec7fc5e14151b3fcdb80fa1e9c66ffc73c69 100644 (file)
@@ -87,6 +87,29 @@ static void test_unionfind_ordered_by_cluster(void)
        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 @@ void unionfind_suite_setup(void)
        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);
 }
index 9700aa66c7bf183359b24f3fb13d567dcf7656af..38e145fc48d0094db4c952a49690d21e8b2e2752 100644 (file)
@@ -349,10 +349,15 @@ combine_geometries(UNIONFIND* uf, void** geoms, uint32_t num_geoms, void*** clus
                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
index 84e6878958743c5c4a0a81eee6d7ffa4e486c4e4..8eae940bc03a16000159c6f84ca3c5a4fca5607d 100644 (file)
@@ -60,11 +60,17 @@ UF_destroy(UNIONFIND* uf)
 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;
 }