Skip to content

Conversation

@mattwigway
Copy link

@mattwigway mattwigway commented Oct 30, 2025

insert!, intersects, and knn all have code that looks something like this:

        result = C.Index_Intersects_id(rtree.index, pointer(minvalues),
            pointer(maxvalues), UInt32(rtree.ndim), items, nresults
        )

The problem is that pointer uses the vector it's passed implicitly, so does not prevent garbage collection of minvalues and maxvalues between when the pointer is created and when the C function is called. (see this and the last example in the first section here.

This has probably been an issue for a long time, but it does seem at first unlikely that GC would happen to run in between allocation and use here - which is probably why it hasn't been noticed before. It seems changes in the garbage collection in Julia 1.12 make it much more likely that this will happen - I discovered it when this test started reliably failing on 1.12, specifically because this line started returning incorrect results because the correct values are not being inserted.

This builds on #36 and #38.

GeoInterface = "1"
LibSpatialIndex_jll = "1.9"
julia = "1.6"
Test = "1.6"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Test = "1.6"
Test = "1"

Copy link
Member

@asinghvi17 asinghvi17 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! And it looks like there are tests as well. If no one objects I'll merge this on Friday

@evetion
Copy link
Member

evetion commented Dec 3, 2025

LGTM, thanks for testing and making a PR. The rest of the ecosystem has moved away from using pointers indeed, and lets Julia take care of the convert (by defining Base.unsafe_convert to Ptr) which results in Julia tracking the lifetime for us. For Arrays this is already defined:

julia> Base.unsafe_convert(Ptr{eltype(A)}, A)
Ptr{Float64}(0x000000010bb686b0)

For completeness sake, note that an alternative method is to use https://docs.julialang.org/en/v1/base/base/#Base.GC.@preserve.

@mattwigway
Copy link
Author

mattwigway commented Dec 3, 2025

For completeness sake, note that an alternative method is to use https://docs.julialang.org/en/v1/base/base/#Base.GC.@preserve.

Indeed, and this is extremely useful if you need to work around this issue if you can't immediately upgrade your version of libspatialindex, because you can use GC.@preserve externally to the package functions - for instance, [this is what I'm currently doing to work around this issue in production] (https://github.com/mattwigway/MissingLinks.jl/blob/main/src/spidx.jl)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants