Skip to content

Memory error in git_mwindow_open when running against multiple large repositories #5591

@andrewhickman

Description

@andrewhickman

Reproduction steps

The Rust program here reliably reproduces the issue on my system when run against a directory with 32 copies of a large repository (I used the rust repository).

The program spawns a thread for each repository which opens the repository and calls git_status_list_new.

Reducing the number of threads or the size of the repositories seems to prevent the issue occurring.

fn main() {
    let join_handles: Vec<thread::JoinHandle<()>> =
        std::fs::read_dir(std::env::args_os().nth(1).expect("expected argument"))
            .unwrap()
            .map(|entry| std::thread::spawn(|| get_status(entry.unwrap().path())))
            .collect();

    for handle in join_handles {
        handle.join().unwrap();
    }
}

fn get_status(path: PathBuf) {
    let repo = git2::Repository::open(path).unwrap();
    let _ = repo.statuses(None).unwrap();
}

Expected behavior

Success (or possibly an resouce exhaustion error?)

Actual behavior

The program crashes with (exit code: 0xc0000374, STATUS_HEAP_CORRUPTION). The stack trace of the failing thread:

mgit-crash-repro.exe!git_mwindow_close_lru_window() Line 269 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\mwindow.c:269)
mgit-crash-repro.exe!new_window(int fd, __int64 size, __int64 offset) Line 336 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\mwindow.c:336)
mgit-crash-repro.exe!git_mwindow_open(git_mwindow_file * mwf, git_mwindow * * cursor, __int64 offset, unsigned __int64 extra, unsigned int * left) Line 407 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\mwindow.c:407)
mgit-crash-repro.exe!git_packfile_unpack_header(unsigned __int64 * size_p, git_object_t * type_p, git_mwindow_file * mwf, git_mwindow * * w_curs, __int64 * curpos) Line 455 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\pack.c:455)
mgit-crash-repro.exe!pack_dependency_chain(git_dependency_chain * chain_out, git_pack_cache_entry * * cached_out, __int64 * cached_off, pack_chain_elem * small_stack, unsigned __int64 * stack_sz, git_pack_file * p, __int64 obj_offset) Line 581 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\pack.c:581)
mgit-crash-repro.exe!git_packfile_unpack(git_rawobj * obj, git_pack_file * p, __int64 * obj_offset) Line 637 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\pack.c:637)
mgit-crash-repro.exe!pack_backend__read(void * * buffer_p, unsigned __int64 * len_p, git_object_t * type_p, git_odb_backend * backend, const git_oid * oid) Line 399 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\odb_pack.c:399)
mgit-crash-repro.exe!odb_read_1(git_odb_object * * out, git_odb * db, const git_oid * id, unsigned char only_refreshed) Line 1065 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\odb.c:1065)
mgit-crash-repro.exe!git_odb_read(git_odb_object * * out, git_odb * db, const git_oid * id) Line 1116 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\odb.c:1116)
mgit-crash-repro.exe!git_object_lookup_prefix(git_object * * object_out, git_repository * repo, const git_oid * id, unsigned __int64 len, git_object_t type) Line 222 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\object.c:222)
mgit-crash-repro.exe!git_object_lookup(git_object * * object_out, git_repository * repo, const git_oid * id, git_object_t type) Line 254 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\object.c:254)
mgit-crash-repro.exe!git_tree_lookup(git_tree * * out, git_repository * repo, const git_oid * id) Line 57 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\object_api.c:57)
mgit-crash-repro.exe!tree_iterator_frame_push(tree_iterator * iter, tree_iterator_entry * entry) Line 661 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\iterator.c:661)
mgit-crash-repro.exe!tree_iterator_advance(const git_index_entry * * out, git_iterator * i) Line 813 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\iterator.c:813)
mgit-crash-repro.exe!git_iterator_advance(const git_index_entry * * entry, git_iterator * iter) Line 185 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\iterator.h:185)
mgit-crash-repro.exe!iterator_advance(const git_index_entry * * entry, git_iterator * iterator) Line 925 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\diff_generate.c:925)
mgit-crash-repro.exe!handle_matched_item(git_diff_generated * diff, diff_in_progress * info) Line 1179 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\diff_generate.c:1179)
mgit-crash-repro.exe!git_diff__from_iterators(git_diff * * out, git_repository * repo, git_iterator * old_iter, git_iterator * new_iter, const git_diff_options * opts) Line 1249 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\diff_generate.c:1249)
mgit-crash-repro.exe!git_diff_tree_to_index(git_diff * * out, git_repository * repo, git_tree * old_tree, git_index * index, const git_diff_options * opts) Line 1372 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\diff_generate.c:1372)
mgit-crash-repro.exe!git_status_list_new(git_status_list * * out, git_repository * repo, const git_status_options * opts) Line 341 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\libgit2-sys-0.12.9+1.0.1\libgit2\src\status.c:341)
mgit-crash-repro.exe!git2::repo::Repository::statuses(core::option::Option<mut git2::status::StatusOptions*> self) Line 848 (c:\Users\andre\.cargo\registry\src\github.com-1ecc6299db9ec823\git2-0.13.8\src\repo.rs:848)
mgit-crash-repro.exe!mgit_crash_repro::get_status(std::path::PathBuf path) Line 20 (c:\Users\andre\Repositories\mgit-crash-repro\src\main.rs:20)
mgit-crash-repro.exe!mgit_crash_repro::main::{{closure}}::{{closure}}(mgit_crash_repro::main::{{closure}}::closure-0) Line 10 (c:\Users\andre\Repositories\mgit-crash-repro\src\main.rs:10)
mgit-crash-repro.exe!std::sys_common::backtrace::__rust_begin_short_backtrace<closure-0,()>(mgit_crash_repro::main::{{closure}}::closure-0 f) Line 131 (c:\Users\andre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\sys_common\backtrace.rs:131)
mgit-crash-repro.exe!std::thread::{{impl}}::spawn_unchecked::{{closure}}::{{closure}}<closure-0,()>(std::thread::{{impl}}::spawn_unchecked::{{closure}}::closure-0) Line 476 (c:\Users\andre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\thread\mod.rs:476)
mgit-crash-repro.exe!std::panic::{{impl}}::call_once<(),closure-0>(std::panic::AssertUnwindSafe<closure-0> self) Line 319 (c:\Users\andre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\panic.rs:319)
mgit-crash-repro.exe!std::panicking::try::do_call<std::panic::AssertUnwindSafe<closure-0>,()>(unsigned char * data) Line 299 (c:\Users\andre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\panicking.rs:299)
mgit-crash-repro.exe!_ZN3std9panicking3try17h47d996d239b4b0a6E�() (Unknown Source:0)
mgit-crash-repro.exe!std::panicking::try<(),std::panic::AssertUnwindSafe<closure-0>>(std::panic::AssertUnwindSafe<closure-0> f) Line 274 (c:\Users\andre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\panicking.rs:274)
mgit-crash-repro.exe!std::panic::catch_unwind<std::panic::AssertUnwindSafe<closure-0>,()>(std::panic::AssertUnwindSafe<closure-0> f) Line 394 (c:\Users\andre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\panic.rs:394)
mgit-crash-repro.exe!std::thread::{{impl}}::spawn_unchecked::{{closure}}<closure-0,()>(std::thread::{{impl}}::spawn_unchecked::closure-0) Line 474 (c:\Users\andre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\thread\mod.rs:474)
mgit-crash-repro.exe!core::ops::function::FnOnce::call_once<closure-0,()>(std::thread::{{impl}}::spawn_unchecked::closure-0 *) Line 232 (c:\Users\andre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\ops\function.rs:232)
[Inline Frame] mgit-crash-repro.exe!alloc::boxed::{{impl}}::call_once() Line 1076 (c:\rustc\c367798cfd3817ca6ae908ce675d1d99242af148\src\liballoc\boxed.rs:1076)
[Inline Frame] mgit-crash-repro.exe!alloc::boxed::{{impl}}::call_once() Line 1076 (c:\rustc\c367798cfd3817ca6ae908ce675d1d99242af148\src\liballoc\boxed.rs:1076)
mgit-crash-repro.exe!std::sys::windows::thread::{{impl}}::new::thread_start() Line 56 (c:\rustc\c367798cfd3817ca6ae908ce675d1d99242af148\src\libstd\sys\windows\thread.rs:56)
kernel32.dll!00007ffadb5e7bd4() (Unknown Source:0)
ntdll.dll!00007ffadc62ce51() (Unknown Source:0)

I noted most of the other threads were blocked on the mutex lock in git_mwindow_open on line 386

Version of libgit2 (release number or SHA1)

Commit a83fd51

(Used in the rust bindings here)

Operating system(s) tested

Windows 10. I also tested with WSL but didn't manage to reproduce it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions