Preserve against garbage collection in LibGit2

Maybe I am wrong but I have a concern about the implementation of LibGit2 regarding garbage collection. To ilustrate this, please have a look at the code of a simple function such as:

function Base.length(blob::GitBlob)
    ensure_initialized()
    return ccall((:git_blob_rawsize, libgit2), Int64, (Ptr{Cvoid},), blob.ptr)
end

in stdlib/LibGit2/src/blob.jl. My understanding is that there is nothing above to prevent blob to be garbage collected. This could be done by:

function Base.length(blob::GitBlob)
    ensure_initialized()
    GC.@preserve blob begin
        return ccall((:git_blob_rawsize, libgit2), Int64, (Ptr{Cvoid},), blob.ptr)
    end
end

Thanks to the specialization of the Base.unsafe_convert method for Git objects in stdlib/LibGit2/src/types.jl, another (better) possibility would be to just replace blob.ptr by blob:

Base.unsafe
function Base.length(blob::GitBlob)
    ensure_initialized()
    return ccall((:git_blob_rawsize, libgit2), Int64, (Ptr{Cvoid},), blob)
end

The same remark applies for other types of Git objects and other methods. If I am right, there are a number of ccalls in stdlib/LibGit2/src that could benefit from this (small) change.

1 Like

Yeah, the libgit2 wrappers weren’t written particularly carefully. Most of these sorts of issues that caused practical problems in CI’d usage were fixed, but there’s others remaining. PRs welcome.

OK I’d be happy to make a PR but do you confirm my analysis and the proposed fix? I do not want to introduce other errors.

You are correct.

The PR is here: Preserve Git objects from being garbage collected by emmt · Pull Request #55142 · JuliaLang/julia · GitHub

There are many changes and I have a few doubts (indicated by FIXME comments) but all tests in LibGit2 were successul.

9 Likes