JuliaGeo / LibGEOS.jl

Julia package for manipulation and analysis of planar geometric objects
MIT License
72 stars 24 forks source link

Error with destroyGeom when creating Polygons #133

Closed skygering closed 2 years ago

skygering commented 2 years ago

I am currently working on issue #129. However, when I was working on this, I was occasionally having my terminal crash when I was working with polygon pointers. I was having a hard time figuring out what was causing the issue as it did not happen consistently. However, while I was writing tests for part of the above issue, I think I have found the source of the problem. Within my tests I run the following:

poly_vec = LibGEOS.Polygon([
            [[-2.0, -2.0], [2.0, -2.0], [2.0, 2.0], [-2.0,2.0], [-2.0, -2.0]],
            [[0.0, 0.0], [1.0, 1.0], [1.0,0.0], [0.0, 0.0]]])

poly_ptr = LibGEOS.Polygon(poly_vec.ptr)

The first line is fine. I have written tests for construction by vector and they pass. However, the second line crashes the tests and the following error message is displayed.

Screen Shot 2022-09-08 at 5 07 20 PM

It is referencing the destroyer so I think that this agrees with my hypothesis that something is going on with releasing memory.

However, this does not happen when I run it in the terminal... most of the time. If I run

poly_vec = LibGEOS.Polygon([
            [[-2.0, -2.0], [2.0, -2.0], [2.0, 2.0], [-2.0,2.0], [-2.0, -2.0]],
            [[0.0, 0.0], [1.0, 1.0], [1.0,0.0], [0.0, 0.0]]])
for i in 1:100000
    poly_ptr = LibGEOS.Polygon(poly_vec.ptr)
end

then I do get a crash most of the time, but it usually requires quite a few runs through the second command to crash.

This is not a functionality I have changed from the original source code in my branch: https://github.com/skygering/LibGEOS.jl. I have added code around it to limit the types of pointers that can be passed into the constructor, but I commented that part out when these errors occurred so I could try to figure out what is going on. Perhaps I have misunderstood the use of the Polygon(ptr) constructor and am misusing it. If so, I would love to add some protection around it to prevent this misuse.

I would appreciate any advice. This seems like it would be a large problem as most constructors are created this way within geos_types.jl. Thanks!

evetion commented 2 years ago

Most constructors do indeed take a pointer, but the issue here is who (thinks that it) owns that piece of pointed to memory. poly_vec.ptr in your example is now owned by many Polygons, each of which will try to release that part of memory on exit or garbage collection. In a REPL, things are not cleaned up quickly, because Julia can't infer whether your Polygon will be used later in the session. In a script it can, so things are garbage collected more quickly, leading to crashes.

So memory should be copied first, so each Polygon gets its own unique piece of it. You can call cloneGeom for that. Or use higher level functions, such as exteriorRing that call cloneGeom itself.