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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions