Skip to content
This repository was archived by the owner on Sep 19, 2023. It is now read-only.
This repository was archived by the owner on Sep 19, 2023. It is now read-only.

Panics on prepared geometry calls #11

@dim

Description

@dim

I have observed panics when prepared geometry objects are used:

pure virtual method called
terminate called without an active exception
SIGABRT: abort
PC=0x7fbe473fbd27
signal arrived during cgo execution

goroutine 6 [syscall, locked to thread]:
runtime.cgocall_errno(0x408920, 0xc2080d9218, 0x0)
  $GOROOT/src/runtime/cgocall.go:130 +0xf5 fp=0xc2080d91f8 sp=0xc2080d91d0
github.com/paulsmith/gogeos/geos._Cfunc_GEOSPreparedCovers_r(0x2a7eb50, 0x7fbe3c127880, 0x2bb87e0, 0xc208034900)
  github.com/paulsmith/gogeos/geos/_obj/_cgo_gotypes.go:672 +0x40 fp=0xc2080d9218 sp=0xc2080d91f8
github.com/paulsmith/gogeos/geos.cGEOSPreparedCovers(0x7fbe3c127880, 0x2bb87e0, 0x4d3200)
  $GOPATH/src/github.com/paulsmith/gogeos/geos/cwrappers.go:547 +0x74 fp=0xc2080d9240 sp=0xc2080d9218
github.com/paulsmith/gogeos/geos.(*PGeometry).predicate(0xc20802e068, 0x7c8480, 0x6, 0x87a250, 0xc20802e600, 0x8, 0x0, 0x0)
  $GOPATH/src/github.com/paulsmith/gogeos/geos/prepared.go:95 +0x5b fp=0xc2080d92b0 sp=0xc2080d9240
github.com/paulsmith/gogeos/geos.(*PGeometry).Covers(0xc20802e068, 0xc20802e600, 0x348, 0x0, 0x0)
  $GOPATH/src/github.com/paulsmith/gogeos/geos/prepared.go:55 +0x63 fp=0xc2080d92f8 sp=0xc2080d92b0

I tried to recreate the behaviour in a test, but I couldn't, at least not consistently. It is related to Go's GC cycles and the finalizer calling cGEOSGeom_destroy(ptr) on the original Geometry. As a workaround, I added:

diff --git a/geos/prepared.go b/geos/prepared.go
index a7af6d1..3383fe8 100644
--- a/geos/prepared.go
+++ b/geos/prepared.go
@@ -14,12 +14,13 @@ import (
 // optimized for a limited set of operations.
 type PGeometry struct {
        p *C.GEOSPreparedGeometry
+       g *Geometry
 }

 // PrepareGeometry constructs a prepared geometry from a normal geometry object.
 func PrepareGeometry(g *Geometry) *PGeometry {
        ptr := cGEOSPrepare(g.g)
-       p := &PGeometry{ptr}
+       p := &PGeometry{ptr, g}
        runtime.SetFinalizer(p, (*PGeometry).destroy)
        return p
 }
@@ -27,6 +28,7 @@ func PrepareGeometry(g *Geometry) *PGeometry {
 func (p *PGeometry) destroy() {
        cGEOSPreparedGeom_destroy(p.p)
        p.p = nil
+       p.g = nil
 }

 // Prepared geometry binary predicates

It fixes the problem by preventing the Geometry from being garbage-collected, but it is not very elegant.

Thoughts? Thanks

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions