Skip to content

Undefined behavior in Remote::list #1217

@Shir0kamii

Description

@Shir0kamii

Hello,

I'm pretty sure I encountered undefined behavior with Remote::list while writing tests for my application.

I managed to reproduce the problem with a minimal exemple. You can run cargo test with the following setup:

[package]
name = "git-ub-investigation"
version = "0.1.0"
edition = "2024"

[dependencies]
git2 = "0.20.3"
tempfile = "3.24.0"
fn main() {
    let repo_dir = tempfile::tempdir().unwrap();
    let repo = git2::Repository::init(repo_dir.path()).unwrap();
    let remote_dir = tempfile::tempdir().unwrap();
    let _remote_repo = git2::Repository::init_bare(remote_dir.path()).unwrap();
    let remote_url = format!("file://{}", remote_dir.path().display());
    let mut remote = repo.remote("origin", &remote_url).unwrap();
    remote.connect(git2::Direction::Fetch).unwrap();
    remote.list().unwrap().iter().for_each(|remote| {
        println!("remote: {}", remote.name());
    });
}

#[test]
fn test_main() {
    main();
}

It shows the following output:

   Compiling git-ub-investigation v0.1.0 (/home/foo/dev/git-ub-investigation)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.16s
     Running unittests src/main.rs (target/debug/deps/git_ub_investigation-aef9ec97e4f87283)

running 1 test

thread 'test_main' (2250680) panicked at /home/foo/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/git2-0.20.4/src/remote.rs:387:25:
unsafe precondition(s) violated: slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`

This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread caused non-unwinding panic. aborting.
error: test failed, to rerun pass `--bin git-ub-investigation`

Caused by:
  process didn't exit successfully: `/home/foo/dev/git-ub-investigation/target/debug/deps/git_ub_investigation-aef9ec97e4f87283` (signal: 6, SIGABRT: process abort signal)

I'm not used to low-level code, but from what I gathered looking at the sources and print-debugging:

  • the call to git_remote_ls in Remote::list does not set the base variable, which remains null.
  • the null-pointer is the sent to slice::from_raw_parts which triggers undefined behavior as per the docs stating "data must be non-null".
  • It only affects cases where no branches or tags have been pushed to the remote.
  • I don't know if using local directories is relevant or not.

I understand there might be something wrong with my setup, or that the root issue might lie in the underlying libgit2-sys, but I don't think a call to a safe method should be able to trigger undefined behavior.

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