Opened 5 years ago

Closed 4 years ago

#30274 closed Bug (fixed)

Segfault on iteration of GEOS Polygons/LinearRings.

Reported by: Murray Christopherson Owned by: Sergey Fedoseev
Component: GIS Version: dev
Severity: Normal Keywords: geos gis
Cc: Fabian Schindler Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Environment Details
Ubuntu 14.04 (trusty)
Python 3.6.8 (via package manager, unofficial repo: ppa:deadsnakes/ppa)
Django 2.1.7 (via pip)
libgeos (both 3.4.2 via apt-get, and 3.7.1 via source distribution)

First and foremost, I am aware that the OS is a bit older (hence the unofficial installation routes of some newer dependencies), but I was unable to find any reason these components shouldn't play nice.

Steps to reproduce
I have a minimal script showcasing the issue:

from django.contrib.gis.geos import Polygon

def main():
    polygon = Polygon( ((0.0, 0.0), (0.0, 50.0), (50.0, 50.0), (50.0, 0.0), (0.0, 0.0)) )

    for p in polygon[0]:
        print('Longitude:', p[0])
        print('Latitude:', p[1])

if __name__ == '__main__':
    main()

Expected Behaviour
Output to stdout, something like:

Latitude: 0.0
Longitude: 0.0
Latitude: 0.0
Longitude: 50.0
...

Observed Behaviour
Output to stderr:

Segmentation fault (core dumped)

Notes
It should be noted, when originally observed, there was a stacktrace (which I won't post in full, as it's mostly uWSGI functions), but the relevant section suggested the segfault is in GEOSCoordSeq_getSize in libgeos.so, which leads me to believe the issue may be in https://github.com/django/django/blob/master/django/contrib/gis/geos/prototypes/coordseq.py.

Furthermore, this issue was uncovered during a Python 2 to 3 migration attempt. The issue did not manifest in this environment:
Ubuntu 14.04 (trusty)
Python 2.7.12 (via package manager, unofficial repo: ppa:deadsnakes/ppa)
Django 1.11.18 (via pip)
libgeos 3.4.2 (via apt-get)

Lastly, I was able to find a workaround (in case anyone else encounters this). This un-Pythonic variation seems to work:

from django.contrib.gis.geos import Polygon

def main():
    polygon = Polygon( ((0.0, 0.0), (0.0, 50.0), (50.0, 50.0), (50.0, 0.0), (0.0, 0.0)) )

    for i in range(len(polygon[0])):
        p = polygon[0][i]
        print('Longitude:', p[0])
        print('Latitude:', p[1])

if __name__ == '__main__':
    main()

Change History (8)

comment:1 by Tim Graham, 5 years ago

Resolution: needsinfo
Status: newclosed

Generally a segmentation fault suggests an issue outside of Django's control as none of Django is written in C. If you identify that Django is at fault, please reopen and give the fix.

comment:2 by Simon Charette, 5 years ago

Hello Murray, in order to identify the origin of segfault I suggest you enable faulthandler and rely on catchsegv.

That would be catchsegv python -X faulthandler script.py.

comment:3 by Fabian Schindler, 4 years ago

Cc: Fabian Schindler added
Resolution: needsinfo
Status: closednew

I'm still experiencing this issue (Django 2.2.9), I could reproduce it with the above script or a similar one:

# python3
Python 3.7.5 (default, Nov 20 2019, 09:21:52)
[GCC 9.2.1 20191008] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from django.contrib.gis.geos import Polygon
>>> polygon = Polygon( ((0.0, 0.0), (0.0, 50.0), (50.0, 50.0), (50.0, 0.0), (0.0, 0.0)) )
>>>
>>> for p in polygon[0]:
...         print('Longitude:', p[0])
...         print('Latitude:', p[1])
...
Segmentation fault

My OS details are as follows:

Ubuntu 19.10
libgeos-3.7.2/eoan (apt)
Python 3.7.5 (apt)
Django 2.2.9 (via pip)

For what version should this issue be fixed? Is it possible to backport the fix if it is only available for Django 3?

Also, I could not find any commit related to this issue.

comment:4 by Claude Paroz, 4 years ago

I can reproduce too. Note that putting polygon[0] in a variable runs fine:

>>> from django.contrib.gis.geos import Polygon
>>> polygon = Polygon( ((0.0, 0.0), (0.0, 50.0), (50.0, 50.0), (50.0, 0.0), (0.0, 0.0)) )
>>>
>>> line = polygon[0]
>>> for p in line:
...         print('Longitude:', p[0])
...         print('Latitude:', p[1])
Longitude: 0.0
Latitude: 0.0
etc.

comment:5 by Mariusz Felisiak, 4 years ago

Summary: Segfault on iteration of GEOS Polygons/LinearRingsSegfault on iteration of GEOS Polygons/LinearRings.
Triage Stage: UnreviewedAccepted
Version: 2.1master

Segmentation fault is raised in:

  File "django/django/contrib/gis/geos/prototypes/threadsafe.py", line 47 in __call__
  File "django/django/contrib/gis/geos/libgeos.py", line 154 in __call__
  File "django/django/contrib/gis/geos/coordseq.py", line 157 in size
  File "django/django/contrib/gis/geos/coordseq.py", line 29 in __iter__

Regression in 138a78ec8cab5e1df0c8ba2a3ee895cb756ff1ae.

comment:6 by Sergey Fedoseev, 4 years ago

Owner: changed from nobody to Sergey Fedoseev
Status: newassigned

comment:7 by Sergey Fedoseev, 4 years ago

Has patch: set

comment:8 by Mariusz Felisiak <felisiak.mariusz@…>, 4 years ago

Resolution: fixed
Status: assignedclosed

In f2a725fb:

Fixed #30274 -- Prevented segmentation fault on LineString iteration.

This reverts commit 138a78ec8cab5e1df0c8ba2a3ee895cb756ff1ae and adds
a test for the regression.

Note: See TracTickets for help on using tickets.
Back to Top