[SCM] PostGIS branch master updated. 3.7.0beta2-29-g321342d9e

git at osgeo.org git at osgeo.org
Tue Aug 11 10:35:45 PDT 2026


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, master has been updated
       via  321342d9e1b2f88dfeae3d7050539bfacfd27d10 (commit)
       via  ee01b53cd8449eee04548d11bf00a8a5d2b7dd3b (commit)
       via  5bbc1de9bf2c53f85a46a95b4726060454d6f213 (commit)
       via  58300a97ac7b2c454461771c53298b4bf1d63beb (commit)
      from  369235b92e0d03584916c42bf074cd02122addb9 (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 321342d9e1b2f88dfeae3d7050539bfacfd27d10
Merge: 369235b92 ee01b53cd
Author: Darafei Praliaskouski <komzpa at gmail.com>
Date:   Tue Aug 11 10:35:44 2026 -0700

    Merge pull request 'Handle topology and shp2pgsql allocation failures' (!728) from Komzpa/postgis:pick/gh-1170-1171-alloc-handlers into master
    
    Ports two allocation-failure hardening patches from GitHub mirror pull requests into the canonical Gitea review flow.
    
    - Handle failed topology ring-shell array allocation before constructing the shell polygon.
    - Handle shp2pgsql loader allocation failures during loader creation, field metadata setup, geometry array construction, polygon ring construction, and escaped attribute output.
    
    The branch also includes a review follow-up that replaces an assert-only polygon ring size guard with a runtime bounds check and shared allocation-failure cleanup.
    
    References https://github.com/postgis/postgis/pull/1170
    References https://github.com/postgis/postgis/pull/1171
    
    Reviewed-on: https://gitea.osgeo.org/postgis/postgis/pulls/728


commit ee01b53cd8449eee04548d11bf00a8a5d2b7dd3b
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Tue Aug 11 19:29:07 2026 +0400

    loader: harden allocation failure cleanup

diff --git a/liblwgeom/topo/lwgeom_topo.c b/liblwgeom/topo/lwgeom_topo.c
index 8e18e7be1..11fed9091 100644
--- a/liblwgeom/topo/lwgeom_topo.c
+++ b/liblwgeom/topo/lwgeom_topo.c
@@ -2072,9 +2072,9 @@ _lwt_MakeRingShell(LWT_TOPOLOGY *topo, LWT_ELEMID *signed_edge_ids, uint64_t num
   POINTARRAY **points = lwalloc(sizeof(POINTARRAY*));
   if (!points)
   {
-    ptarray_free(full_ring_pa);
-    lwerror("Could not allocate ring shell rings array");
-    return NULL;
+	  ptarray_free(full_ring_pa);
+	  lwerror("Could not allocate ring shell rings array");
+	  return NULL;
   }
   points[0] = full_ring_pa;
 
diff --git a/loader/shp2pgsql-core.c b/loader/shp2pgsql-core.c
index ded9472e1..74415c039 100644
--- a/loader/shp2pgsql-core.c
+++ b/loader/shp2pgsql-core.c
@@ -16,7 +16,7 @@
 #include "../postgis_config.h"
 
 #include <math.h> /* for isnan */
-#include <limits.h>
+#include <stdint.h>
 #include <strings.h>
 
 #include "shp2pgsql-core.h"
@@ -469,6 +469,39 @@ PIP(Point P, Point *V, int n)
 	return (cn&1);    /* 0 if even (out), and 1 if odd (in) */
 }
 
+static void
+ShpLoaderFreeFieldMetadata(SHPLOADERSTATE *state)
+{
+	for (int j = 0; j < state->num_fields; j++)
+	{
+		if (state->field_names)
+			free(state->field_names[j]);
+		if (state->pgfieldtypes)
+			free(state->pgfieldtypes[j]);
+	}
+
+	free(state->field_names);
+	state->field_names = NULL;
+	free(state->types);
+	state->types = NULL;
+	free(state->widths);
+	state->widths = NULL;
+	free(state->precisions);
+	state->precisions = NULL;
+	free(state->pgfieldtypes);
+	state->pgfieldtypes = NULL;
+	free(state->col_names);
+	state->col_names = NULL;
+	state->num_fields = 0;
+}
+
+static int
+ShpLoaderOpenShapeFieldAllocFailure(SHPLOADERSTATE *state)
+{
+	ShpLoaderFreeFieldMetadata(state);
+	snprintf(state->message, SHPLOADERMSGLEN, "unable to allocate memory for field information");
+	return SHPLOADERERR;
+}
 
 int
 FindPolygons(SHPObject *obj, Ring ***Out)
@@ -516,7 +549,23 @@ FindPolygons(SHPObject *obj, Ring ***Out)
 
 		/* Compute number of vertices */
 		nv = ve - vs;
-		assert(nv >= 0 && nv < INT_MAX / sizeof(Point));
+		if (nv <= 0 || (size_t)nv > SIZE_MAX / sizeof(*ring->list))
+		{
+			for (pi = 0; pi < out_index; pi++)
+			{
+				free(Outer[pi]->list);
+				free(Outer[pi]);
+			}
+			for (pi = 0; pi < in_index; pi++)
+			{
+				free(Inner[pi]->list);
+				free(Inner[pi]);
+			}
+			free(Outer);
+			free(Inner);
+			return -1;
+		}
+		size_t ring_list_size = sizeof(*ring->list) * (size_t)nv;
 
 		/* Allocate memory for a ring */
 		ring = (Ring *)malloc(sizeof(Ring));
@@ -537,7 +586,7 @@ FindPolygons(SHPObject *obj, Ring ***Out)
 			free(Inner);
 			return -1;
 		}
-		ring->list = (Point *)malloc(sizeof(Point) * (size_t)nv);
+		ring->list = (Point *)malloc(ring_list_size);
 		if (!ring->list)
 		{
 			free(ring);
@@ -1391,7 +1440,7 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state)
 	 * field_names and pgfieldtypes hold per-field strings that are freed
 	 * individually; use calloc so any slot never assigned stays NULL and
 	 * free(NULL) is safe on the allocation-failure cleanup path. */
-	state->field_names = calloc(state->num_fields, sizeof(char*));
+	state->field_names = calloc(state->num_fields, sizeof(char *));
 	state->types = (DBFFieldType *)malloc(state->num_fields * sizeof(int));
 	state->widths = malloc(state->num_fields * sizeof(int));
 	state->precisions = malloc(state->num_fields * sizeof(int));
@@ -1401,12 +1450,11 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state)
 			(state->config->readshape ? strlen(state->geo_col) : 0) + 1,
 		sizeof(char)
 	);
-	if (!state->col_names ||
-		(state->num_fields && (!state->field_names || !state->types ||
-			!state->widths || !state->precisions || !state->pgfieldtypes)))
+	int fields_allocated = !state->num_fields || (state->field_names && state->types && state->widths &&
+						      state->precisions && state->pgfieldtypes);
+	if (!state->col_names || !fields_allocated)
 	{
-		state->num_fields = 0;
-		goto open_shape_field_alloc_failure;
+		return ShpLoaderOpenShapeFieldAllocFailure(state);
 	}
 
 	/* Generate a string of comma separated column names of the form "col1, col2 ... colN" for the SQL
@@ -1496,7 +1544,7 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state)
 
 		state->field_names[j] = strdup(name);
 		if (!state->field_names[j])
-			goto open_shape_field_alloc_failure;
+			return ShpLoaderOpenShapeFieldAllocFailure(state);
 
 		/* Now generate the PostgreSQL type name string and width based upon the shapefile type */
 		switch (state->types[j])
@@ -1553,7 +1601,7 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state)
 		}
 
 		if (!state->pgfieldtypes[j])
-			goto open_shape_field_alloc_failure;
+			return ShpLoaderOpenShapeFieldAllocFailure(state);
 
 		strcat(state->col_names, "\"");
 		strcat(state->col_names, name);
@@ -1575,31 +1623,6 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state)
 
 	/* Return status */
 	return ret;
-
-open_shape_field_alloc_failure:
-	/* Release the per-field strings populated so far; free(NULL) is safe for
-	 * the slots that were never assigned. */
-	for (int j = 0; j < state->num_fields; j++)
-	{
-		free(state->field_names[j]);
-		free(state->pgfieldtypes[j]);
-	}
-	free(state->field_names);
-	state->field_names = NULL;
-	free(state->types);
-	state->types = NULL;
-	free(state->widths);
-	state->widths = NULL;
-	free(state->precisions);
-	state->precisions = NULL;
-	free(state->pgfieldtypes);
-	state->pgfieldtypes = NULL;
-	free(state->col_names);
-	state->col_names = NULL;
-	state->num_fields = 0;
-	state->num_records = 0;
-	snprintf(state->message, SHPLOADERMSGLEN, "unable to allocate memory for field information");
-	return SHPLOADERERR;
 }
 
 /* Return a pointer to an allocated string containing the header for the specified loader state */
@@ -1983,7 +2006,9 @@ ShpLoaderGenerateSQLRowStatement(SHPLOADERSTATE *state, int item, char **strreco
 
 			if (!escval)
 			{
-				snprintf(state->message, SHPLOADERMSGLEN, "unable to allocate memory for escaped attribute value");
+				snprintf(state->message,
+					 SHPLOADERMSGLEN,
+					 "unable to allocate memory for escaped attribute value");
 				SHPDestroyObject(obj);
 				stringbuffer_destroy(sbwarn);
 				stringbuffer_destroy(sb);
@@ -2233,35 +2258,13 @@ void
 ShpLoaderDestroy(SHPLOADERSTATE *state)
 {
 	/* Destroy a state object created with ShpLoaderOpenShape */
-	int i;
 	if (state != NULL)
 	{
 		if (state->hSHPHandle)
 			SHPClose(state->hSHPHandle);
 		if (state->hDBFHandle)
 			DBFClose(state->hDBFHandle);
-		if (state->field_names)
-		{
-			for (i = 0; i < state->num_fields; i++)
-				free(state->field_names[i]);
-
-			free(state->field_names);
-		}
-		if (state->pgfieldtypes)
-		{
-			for (i = 0; i < state->num_fields; i++)
-				free(state->pgfieldtypes[i]);
-
-			free(state->pgfieldtypes);
-		}
-		if (state->types)
-			free(state->types);
-		if (state->widths)
-			free(state->widths);
-		if (state->precisions)
-			free(state->precisions);
-		if (state->col_names)
-			free(state->col_names);
+		ShpLoaderFreeFieldMetadata(state);
 
 		/* Free any column map fieldnames if specified */
 		colmap_clean(&state->column_map);
diff --git a/loader/shp2pgsql-gui.c b/loader/shp2pgsql-gui.c
index 50f9c8623..16ba66a4b 100644
--- a/loader/shp2pgsql-gui.c
+++ b/loader/shp2pgsql-gui.c
@@ -1579,7 +1579,15 @@ pgui_action_import(GtkWidget *widget, gpointer data)
 		if (!state)
 		{
 			pgui_logf(_("Warning: Could not load shapefile %s"), loader_file_config->shp_file);
-			goto import_cleanup;
+			ret = SHPLOADERERR;
+			is_running = FALSE;
+			PQfinish(pg_connection);
+			pg_connection = NULL;
+			pgui_logf(_("Shapefile import failed."));
+			free(progress_shapefile);
+			progress_shapefile = NULL;
+			is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(import_file_list_store), &iter);
+			continue;
 		}
 
 		/* Open the shapefile */

commit 5bbc1de9bf2c53f85a46a95b4726060454d6f213
Author: Maksim Korotkov <m.korotkov at postgrespro.ru>
Date:   Tue Aug 11 19:29:06 2026 +0400

    loader: handle shp2pgsql allocation failures
    
    Check the return of malloc/calloc in the shp2pgsql loader paths and bail out cleanly instead of dereferencing NULL. Escaped-value and field-info allocation failures now error out before the value is written, so no unescaped attribute reaches the output buffer. The partial-allocation paths in FindPolygons and ShpLoaderOpenShape release what was already allocated and null the owning pointers so ShpLoaderDestroy stays safe.
    
    Found by PostgresPro with Svace Static Analyzer.
    
    Signed-off-by: Maksim Korotkov <m.korotkov at postgrespro.ru>

diff --git a/loader/shp2pgsql-cli.c b/loader/shp2pgsql-cli.c
index a7c6db37d..394140980 100644
--- a/loader/shp2pgsql-cli.c
+++ b/loader/shp2pgsql-cli.c
@@ -571,6 +571,11 @@ main (int argc, char **argv)
 
 	/* Create the shapefile state object */
 	state = ShpLoaderCreate(config);
+	if (!state)
+	{
+		fprintf(stderr, "Unable to allocate memory for loader state\n");
+		exit(1);
+	}
 
 	/* Open the shapefile */
 	ret = ShpLoaderOpenShape(state);
diff --git a/loader/shp2pgsql-core.c b/loader/shp2pgsql-core.c
index 9ebfa8fb4..ded9472e1 100644
--- a/loader/shp2pgsql-core.c
+++ b/loader/shp2pgsql-core.c
@@ -16,6 +16,7 @@
 #include "../postgis_config.h"
 
 #include <math.h> /* for isnan */
+#include <limits.h>
 #include <strings.h>
 
 #include "shp2pgsql-core.h"
@@ -170,6 +171,8 @@ escape_copy_string(char *str)
 
 	size = ptr - str + toescape + 1;
 	result = calloc(1, size);
+	if (!result)
+		return NULL;
 	optr = result;
 	ptr = str;
 
@@ -223,6 +226,8 @@ escape_insert_string(char *str)
 
 	size = ptr - str + toescape + 1;
 	result = calloc(1, size);
+	if (!result)
+		return NULL;
 	optr = result;
 	ptr = str;
 
@@ -271,6 +276,11 @@ GeneratePointGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry, in
 	{
 		/* Allocate memory for our array of LWPOINTs and our dynptarrays */
 		lwmultipoints = malloc(sizeof(LWPOINT *) * obj->nVertices);
+		if (!lwmultipoints)
+		{
+			snprintf(state->message, SHPLOADERMSGLEN, "unable to allocate memory for point geometry");
+			return SHPLOADERERR;
+		}
 
 		/* We need an array of pointers to each of our sub-geometries */
 		for (u = 0; u < obj->nVertices; u++)
@@ -361,6 +371,11 @@ GenerateLineStringGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometr
 
 	/* Allocate memory for our array of LWLINEs and our dynptarrays */
 	lwmultilinestrings = malloc(sizeof(LWPOINT *) * obj->nParts);
+	if (!lwmultilinestrings)
+	{
+		snprintf(state->message, SHPLOADERMSGLEN, "unable to allocate memory for linestring geometry");
+		return SHPLOADERERR;
+	}
 
 	/* We need an array of pointers to each of our sub-geometries */
 	for (u = 0; u < obj->nParts; u++)
@@ -474,6 +489,12 @@ FindPolygons(SHPObject *obj, Ring ***Out)
 	/* Allocate initial memory */
 	Outer = (Ring **)malloc(sizeof(Ring *) * obj->nParts);
 	Inner = (Ring **)malloc(sizeof(Ring *) * obj->nParts);
+	if (!Outer || !Inner)
+	{
+		free(Outer);
+		free(Inner);
+		return -1;
+	}
 
 	/* Iterate over rings dividing in Outers and Inners */
 	for (pi=0; pi < obj->nParts; pi++)
@@ -495,10 +516,46 @@ FindPolygons(SHPObject *obj, Ring ***Out)
 
 		/* Compute number of vertices */
 		nv = ve - vs;
+		assert(nv >= 0 && nv < INT_MAX / sizeof(Point));
 
 		/* Allocate memory for a ring */
 		ring = (Ring *)malloc(sizeof(Ring));
-		ring->list = (Point *)malloc(sizeof(Point) * nv);
+		if (!ring)
+		{
+			/* Free rings allocated so far (stored in Outer/Inner) */
+			for (pi = 0; pi < out_index; pi++)
+			{
+				free(Outer[pi]->list);
+				free(Outer[pi]);
+			}
+			for (pi = 0; pi < in_index; pi++)
+			{
+				free(Inner[pi]->list);
+				free(Inner[pi]);
+			}
+			free(Outer);
+			free(Inner);
+			return -1;
+		}
+		ring->list = (Point *)malloc(sizeof(Point) * (size_t)nv);
+		if (!ring->list)
+		{
+			free(ring);
+			/* Free rings allocated so far (stored in Outer/Inner) */
+			for (pi = 0; pi < out_index; pi++)
+			{
+				free(Outer[pi]->list);
+				free(Outer[pi]);
+			}
+			for (pi = 0; pi < in_index; pi++)
+			{
+				free(Inner[pi]->list);
+				free(Inner[pi]);
+			}
+			free(Outer);
+			free(Inner);
+			return -1;
+		}
 		ring->n = nv;
 		ring->next = NULL;
 		ring->linked = 0;
@@ -660,6 +717,12 @@ GeneratePolygonGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry)
 
 	polygon_total = FindPolygons(obj, &Outer);
 
+	if (polygon_total < 0)
+	{
+		snprintf(state->message, SHPLOADERMSGLEN, "unable to allocate memory for polygon rings");
+		return SHPLOADERERR;
+	}
+
 	if (state->config->simple_geometries == 1 && polygon_total != 1) /* We write Non-MULTI geometries, but have several parts: */
 	{
 		snprintf(state->message, SHPLOADERMSGLEN, _("We have a Multipolygon with %d parts, can't use -S switch!"), polygon_total);
@@ -669,6 +732,12 @@ GeneratePolygonGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry)
 
 	/* Allocate memory for our array of LWPOLYs */
 	lwpolygons = malloc(sizeof(LWPOLY *) * polygon_total);
+	if (!lwpolygons)
+	{
+		ReleasePolygons(Outer, polygon_total);
+		snprintf(state->message, SHPLOADERMSGLEN, "unable to allocate memory for polygon geometry");
+		return SHPLOADERERR;
+	}
 
 	/* Cycle through each individual polygon */
 	for (pi = 0; pi < polygon_total; pi++)
@@ -1000,6 +1069,8 @@ ShpLoaderCreate(SHPLOADERCONFIG *config)
 
 	/* Create a new state object and assign the config to it */
 	state = malloc(sizeof(SHPLOADERSTATE));
+	if (!state)
+		return NULL;
 	state->config = config;
 
 	/* Set any state defaults */
@@ -1316,17 +1387,27 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state)
 
 	state->num_records = DBFGetRecordCount(state->hDBFHandle);
 
-	/* Allocate storage for field information */
-	state->field_names = malloc(state->num_fields * sizeof(char*));
+	/* Allocate storage for field information.
+	 * field_names and pgfieldtypes hold per-field strings that are freed
+	 * individually; use calloc so any slot never assigned stays NULL and
+	 * free(NULL) is safe on the allocation-failure cleanup path. */
+	state->field_names = calloc(state->num_fields, sizeof(char*));
 	state->types = (DBFFieldType *)malloc(state->num_fields * sizeof(int));
 	state->widths = malloc(state->num_fields * sizeof(int));
 	state->precisions = malloc(state->num_fields * sizeof(int));
-	state->pgfieldtypes = malloc(state->num_fields * sizeof(char *));
+	state->pgfieldtypes = calloc(state->num_fields, sizeof(char *));
 	state->col_names = calloc(
 		(size_t)state->num_fields * (MAXFIELDNAMELEN + 2) +
 			(state->config->readshape ? strlen(state->geo_col) : 0) + 1,
 		sizeof(char)
 	);
+	if (!state->col_names ||
+		(state->num_fields && (!state->field_names || !state->types ||
+			!state->widths || !state->precisions || !state->pgfieldtypes)))
+	{
+		state->num_fields = 0;
+		goto open_shape_field_alloc_failure;
+	}
 
 	/* Generate a string of comma separated column names of the form "col1, col2 ... colN" for the SQL
 	   insertion string */
@@ -1414,6 +1495,8 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state)
 		}
 
 		state->field_names[j] = strdup(name);
+		if (!state->field_names[j])
+			goto open_shape_field_alloc_failure;
 
 		/* Now generate the PostgreSQL type name string and width based upon the shapefile type */
 		switch (state->types[j])
@@ -1469,6 +1552,9 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state)
 			return SHPLOADERERR;
 		}
 
+		if (!state->pgfieldtypes[j])
+			goto open_shape_field_alloc_failure;
+
 		strcat(state->col_names, "\"");
 		strcat(state->col_names, name);
 
@@ -1489,6 +1575,31 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state)
 
 	/* Return status */
 	return ret;
+
+open_shape_field_alloc_failure:
+	/* Release the per-field strings populated so far; free(NULL) is safe for
+	 * the slots that were never assigned. */
+	for (int j = 0; j < state->num_fields; j++)
+	{
+		free(state->field_names[j]);
+		free(state->pgfieldtypes[j]);
+	}
+	free(state->field_names);
+	state->field_names = NULL;
+	free(state->types);
+	state->types = NULL;
+	free(state->widths);
+	state->widths = NULL;
+	free(state->precisions);
+	state->precisions = NULL;
+	free(state->pgfieldtypes);
+	state->pgfieldtypes = NULL;
+	free(state->col_names);
+	state->col_names = NULL;
+	state->num_fields = 0;
+	state->num_records = 0;
+	snprintf(state->message, SHPLOADERMSGLEN, "unable to allocate memory for field information");
+	return SHPLOADERERR;
 }
 
 /* Return a pointer to an allocated string containing the header for the specified loader state */
@@ -1864,14 +1975,26 @@ ShpLoaderGenerateSQLRowStatement(SHPLOADERSTATE *state, int item, char **strreco
 			if (state->config->dump_format)
 			{
 				escval = escape_copy_string(val);
-				stringbuffer_aprintf(sb, "%s", escval);
 			}
 			else
 			{
 				escval = escape_insert_string(val);
-				stringbuffer_aprintf(sb, "'%s'", escval);
 			}
 
+			if (!escval)
+			{
+				snprintf(state->message, SHPLOADERMSGLEN, "unable to allocate memory for escaped attribute value");
+				SHPDestroyObject(obj);
+				stringbuffer_destroy(sbwarn);
+				stringbuffer_destroy(sb);
+				return SHPLOADERERR;
+			}
+
+			if (state->config->dump_format)
+				stringbuffer_aprintf(sb, "%s", escval);
+			else
+				stringbuffer_aprintf(sb, "'%s'", escval);
+
 			/* Free the escaped version if required */
 			if (val != escval)
 				free(escval);
diff --git a/loader/shp2pgsql-gui.c b/loader/shp2pgsql-gui.c
index 37a9a04d0..50f9c8623 100644
--- a/loader/shp2pgsql-gui.c
+++ b/loader/shp2pgsql-gui.c
@@ -1219,6 +1219,11 @@ validate_remote_loader_columns(SHPLOADERCONFIG *config, PGresult *result)
 				{
 					/* If we have a row then lets do some simple column validation... */
 					state = ShpLoaderCreate(config);
+					if (!state)
+					{
+						pgui_logf(_("Warning: Could not load shapefile %s"), config->shp_file);
+						return SHPLOADERERR;
+					}
 					ret = ShpLoaderOpenShape(state);
 					if (ret != SHPLOADEROK)
 					{
@@ -1571,6 +1576,11 @@ pgui_action_import(GtkWidget *widget, gpointer data)
 
 		/* Create the shapefile state object */
 		state = ShpLoaderCreate(loader_file_config);
+		if (!state)
+		{
+			pgui_logf(_("Warning: Could not load shapefile %s"), loader_file_config->shp_file);
+			goto import_cleanup;
+		}
 
 		/* Open the shapefile */
 		ret = ShpLoaderOpenShape(state);
@@ -1768,7 +1778,9 @@ import_cleanup:
 		pg_connection = NULL;
 
 		/* If we didn't finish inserting all of the items (and we expected to), an error occurred */
-		if ((state->config->plan.load_data && i != ShpLoaderGetRecordCount(state)) || !ret)
+		if (state && ((state->config->plan.load_data && i != ShpLoaderGetRecordCount(state)) || !ret))
+			pgui_logf(_("Shapefile import failed."));
+		else if (!state)
 			pgui_logf(_("Shapefile import failed."));
 		else
 			pgui_logf(_("Shapefile import completed."));

commit 58300a97ac7b2c454461771c53298b4bf1d63beb
Author: Maksim Korotkov <m.korotkov at postgrespro.ru>
Date:   Tue Aug 11 19:29:06 2026 +0400

    topo: handle ring shell allocation failure
    
    default_allocator can silently return NULL.
    
    Signed-off-by: Maksim Korotkov <m.korotkov at postgrespro.ru>

diff --git a/liblwgeom/topo/lwgeom_topo.c b/liblwgeom/topo/lwgeom_topo.c
index 5ac10cb83..8e18e7be1 100644
--- a/liblwgeom/topo/lwgeom_topo.c
+++ b/liblwgeom/topo/lwgeom_topo.c
@@ -2070,6 +2070,12 @@ _lwt_MakeRingShell(LWT_TOPOLOGY *topo, LWT_ELEMID *signed_edge_ids, uint64_t num
   *isccw = lwt_IsTopoRingCCW(full_ring_pa);
 
   POINTARRAY **points = lwalloc(sizeof(POINTARRAY*));
+  if (!points)
+  {
+    ptarray_free(full_ring_pa);
+    lwerror("Could not allocate ring shell rings array");
+    return NULL;
+  }
   points[0] = full_ring_pa;
 
   /* NOTE: the ring may very well have collapsed components,

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

Summary of changes:
 liblwgeom/topo/lwgeom_topo.c |   6 ++
 loader/shp2pgsql-cli.c       |   5 ++
 loader/shp2pgsql-core.c      | 184 ++++++++++++++++++++++++++++++++++++-------
 loader/shp2pgsql-gui.c       |  22 +++++-
 4 files changed, 187 insertions(+), 30 deletions(-)


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list