Git blame possible double free exception · Issue #3793 · libgit2/libgit2 · GitHub
Skip to content

Git blame possible double free exception #3793

Description

@ameily

I'm writing a tool that iterates over a repository's commit history and performs a blame on an entire tree for each iteration. I'm seeing a double free issue within libgit2 and am having difficulty tracing the problem down. I've confirmed that the problem exist in both master and v0.24.1. The line numbers below are from the v0.24.1 tag.

*** Error in `/home/user/repos/git-stock/build/git-stock': double free or corruption (!prev): 0x000000000f3062a0 ***


#0  0x00007ffff6aa7418 in __GI_raise (sig=sig@entry=6)
    at ../sysdeps/unix/sysv/linux/raise.c:54
#1  0x00007ffff6aa901a in __GI_abort () at abort.c:89
#2  0x00007ffff6ae972a in __libc_message (do_abort=do_abort@entry=2, 
    fmt=fmt@entry=0x7ffff6c026b0 "*** Error in `%s': %s: 0x%s ***\n")
    at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007ffff6af1f4a in malloc_printerr (ar_ptr=<optimized out>, 
    ptr=<optimized out>, str=0x7ffff6c027e0 "double free or corruption (!prev)", 
    action=3) at malloc.c:5007
#4  _int_free (av=<optimized out>, p=<optimized out>, have_lock=0) at malloc.c:3868
#5  0x00007ffff6af5abc in __GI___libc_free (mem=<optimized out>) at malloc.c:2969
#6  0x00007ffff7a9d3e1 in git__free (ptr=0xf3062a0)
    at /home/user/repos/libgit2/src/util.h:246
#7  0x00007ffff7a9d7d2 in git_odb_object__free (object=0xe6aac90)
    at /home/user/repos/libgit2/src/odb.c:105
#8  0x00007ffff7b2ab1c in git_cached_obj_decref (_obj=0xe6aac90)
    at /home/user/repos/libgit2/src/cache.c:269
#9  0x00007ffff7a9d8a7 in git_odb_object_free (object=0xe6aac90)
    at /home/user/repos/libgit2/src/odb.c:142
#10 0x00007ffff7add89f in git_object_lookup_prefix (object_out=0x7fffffffd678, 
    repo=0x6610a0, id=0x6d6e00, len=40, type=GIT_OBJ_COMMIT)
    at /home/user/repos/libgit2/src/object.c:192
#11 0x00007ffff7add8f4 in git_object_lookup (object_out=0x7fffffffd678, repo=0x6610a0, 
    id=0x6d6e00, type=GIT_OBJ_COMMIT) at /home/user/repos/libgit2/src/object.c:198
#12 0x00007ffff7ab1afe in git_commit_lookup (out=0x7fffffffd678, repo=0x6610a0, 
    id=0x6d6e00) at /home/user/repos/libgit2/src/object_api.c:22
#13 0x00007ffff7b2226d in git_commit_parent (parent=0x7fffffffd678, commit=0x6d6d60, 
    n=0) at /home/user/repos/libgit2/src/commit.c:555
#14 0x00007ffff7ab91ff in pass_blame (blame=0xf19b000, origin=0xf2e5c20, opt=0)
    at /home/user/repos/libgit2/src/blame_git.c:528
#15 0x00007ffff7ab9715 in git_blame__like_git (blame=0xf19b000, opt=0)
    at /home/user/repos/libgit2/src/blame_git.c:625
#16 0x00007ffff7ac6f7a in blame_internal (blame=0xf19b000)
    at /home/user/repos/libgit2/src/blame.c:338

It looks like libgit2 is attempting to free an already freed cached object. My code is essentially doing this repeatedly:

  1. Get a commit by id.
  2. Get the associated tree and build a list of paths within the tree.
  3. For each path, perform a git blame, passing in the commit id as the newest commit.
  4. For each hunk in the blame, get the associated final commit.
  5. Get the commit timestamp from the final commit.
  6. Free the final commit, free the blame, and then free the original commit from step 1.
  7. Repeat with the next commit we need to process.

I've tried removing all calls to git_*_free() within my code just in case the issue was being caused by something I was doing, but the problem still occurs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions