From b85ceaaba6e3de8419a8604cde426914a7915e13 Mon Sep 17 00:00:00 2001 From: Brenton Partridge Date: Sun, 19 Dec 2021 01:15:09 -0500 Subject: [PATCH] [4.0.x] Fixed #32600 -- Fixed Geometry collections and Polygon segmentation fault on macOS ARM64. Backport of 19fb838803f63eef0726a370050443b693f109be from main --- django/contrib/gis/geos/collections.py | 4 +--- django/contrib/gis/geos/polygon.py | 7 ++----- django/contrib/gis/geos/prototypes/geom.py | 17 +++++++++++------ docs/ref/contrib/gis/geos.txt | 2 ++ docs/releases/4.0.1.txt | 5 +++++ 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/django/contrib/gis/geos/collections.py b/django/contrib/gis/geos/collections.py index bf584c9021..3c1f0c858e 100644 --- a/django/contrib/gis/geos/collections.py +++ b/django/contrib/gis/geos/collections.py @@ -2,8 +2,6 @@ This module houses the Geometry Collection objects: GeometryCollection, MultiPoint, MultiLineString, and MultiPolygon """ -from ctypes import byref, c_int, c_uint - from django.contrib.gis.geos import prototypes as capi from django.contrib.gis.geos.geometry import GEOSGeometry, LinearGeometryMixin from django.contrib.gis.geos.libgeos import GEOM_PTR @@ -53,7 +51,7 @@ class GeometryCollection(GEOSGeometry): # allow GEOSGeometry types (python wrappers) or pointer types capi.geom_clone(getattr(g, 'ptr', g)) for g in items ]) - return capi.create_collection(c_int(self._typeid), byref(geoms), c_uint(length)) + return capi.create_collection(self._typeid, geoms, length) def _get_single_internal(self, index): return capi.get_geomn(self.ptr, index) diff --git a/django/contrib/gis/geos/polygon.py b/django/contrib/gis/geos/polygon.py index d857bf00f3..d75106a9a8 100644 --- a/django/contrib/gis/geos/polygon.py +++ b/django/contrib/gis/geos/polygon.py @@ -1,5 +1,3 @@ -from ctypes import byref, c_uint - from django.contrib.gis.geos import prototypes as capi from django.contrib.gis.geos.geometry import GEOSGeometry from django.contrib.gis.geos.libgeos import GEOM_PTR @@ -85,12 +83,11 @@ class Polygon(GEOSGeometry): n_holes = length - 1 if n_holes: - holes = (GEOM_PTR * n_holes)(*[self._clone(r) for r in rings]) - holes_param = byref(holes) + holes_param = (GEOM_PTR * n_holes)(*[self._clone(r) for r in rings]) else: holes_param = None - return capi.create_polygon(shell, holes_param, c_uint(n_holes)) + return capi.create_polygon(shell, holes_param, n_holes) def _clone(self, g): if isinstance(g, GEOM_PTR): diff --git a/django/contrib/gis/geos/prototypes/geom.py b/django/contrib/gis/geos/prototypes/geom.py index a84f710900..06dacdf854 100644 --- a/django/contrib/gis/geos/prototypes/geom.py +++ b/django/contrib/gis/geos/prototypes/geom.py @@ -1,4 +1,4 @@ -from ctypes import POINTER, c_char_p, c_int, c_ubyte +from ctypes import POINTER, c_char_p, c_int, c_ubyte, c_uint from django.contrib.gis.geos.libgeos import CS_PTR, GEOM_PTR, GEOSFuncFactory from django.contrib.gis.geos.prototypes.errcheck import ( @@ -56,11 +56,16 @@ create_point = GeomOutput('GEOSGeom_createPoint', argtypes=[CS_PTR]) create_linestring = GeomOutput('GEOSGeom_createLineString', argtypes=[CS_PTR]) create_linearring = GeomOutput('GEOSGeom_createLinearRing', argtypes=[CS_PTR]) -# Polygon and collection creation routines are special and will not -# have their argument types defined. -create_polygon = GeomOutput('GEOSGeom_createPolygon') -create_empty_polygon = GeomOutput('GEOSGeom_createEmptyPolygon') -create_collection = GeomOutput('GEOSGeom_createCollection') +# Polygon and collection creation routines need argument types defined +# for compatibility with some platforms, e.g. macOS ARM64. With argtypes +# defined, arrays are automatically cast and byref() calls are not needed. +create_polygon = GeomOutput( + 'GEOSGeom_createPolygon', argtypes=[GEOM_PTR, POINTER(GEOM_PTR), c_uint], +) +create_empty_polygon = GeomOutput('GEOSGeom_createEmptyPolygon', argtypes=[]) +create_collection = GeomOutput( + 'GEOSGeom_createCollection', argtypes=[c_int, POINTER(GEOM_PTR), c_uint], +) # Ring routines get_extring = GeomOutput('GEOSGetExteriorRing', argtypes=[GEOM_PTR]) diff --git a/docs/ref/contrib/gis/geos.txt b/docs/ref/contrib/gis/geos.txt index 84de1094fc..ed8dc2d893 100644 --- a/docs/ref/contrib/gis/geos.txt +++ b/docs/ref/contrib/gis/geos.txt @@ -766,6 +766,8 @@ Other Properties & Methods >>> if poly_1.area > poly_2.area: >>> pass +.. _geos-geometry-collections: + Geometry Collections ==================== diff --git a/docs/releases/4.0.1.txt b/docs/releases/4.0.1.txt index 5fea7aa8df..8caf9d56b1 100644 --- a/docs/releases/4.0.1.txt +++ b/docs/releases/4.0.1.txt @@ -23,3 +23,8 @@ Bugfixes * Fixed a regression in Django 4.0 that caused creating bogus migrations for models that reference swappable models such as ``auth.User`` (:ticket:`33366`). + +* Fixed a long standing bug in :ref:`geos-geometry-collections` and + :class:`~django.contrib.gis.geos.Polygon` that caused a crash on some + platforms (reported on macOS based on the ``ARM64`` architecture) + (:ticket:`32600`).