16028 Commits

Author SHA1 Message Date
Edward Thomson
f7164261c9 Merge pull request #7270 from libgit2/copilot/backport-v19-4
backports for v1.9.4
v1.9.4
2026-05-22 11:23:03 +01:00
Edward Thomson
9914c5c1d5 v1.9.4: update version numbers 2026-05-21 18:57:38 +01:00
Edward Thomson
f199afea5c v1.9.4: update changelog 2026-05-21 18:57:38 +01:00
Weihang Lo
e2e2cfb006 fix(sha256): thread-safety bug in builtin SHA-256
The implementation here seems to be sort of a copy
from the reference impl in RFC 6234 [2].
When multiple threads hash concurrently,
they race on this shared static variable.
It then corrupts the length-overflow detection,
and produces incorrect SHA-256 digests.

Here we replace it with a `static` function with a local variable.

The bug only affects the `GIT_SHA256_BUILTIN` backend.
The SHA-1 code path uses `sha1dc` which does not have this issue.

Reproducer:

```c
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <git2.h>

#define NUM_THREADS 8
#define ITERATIONS 100000

static volatile int found_bug = 0;

void *hash_thread(void *arg) {
    int id = *(int *)arg;
    const char *data = "hello world\n";
    size_t len = strlen(data);

    git_object_id_options opts = GIT_OBJECT_ID_OPTIONS_INIT;
    opts.object_type = GIT_OBJECT_BLOB;
    opts.oid_type = GIT_OID_SHA256;

    git_oid reference, result;
    git_object_id_from_buffer(&reference, data, len, &opts);

    for (int i = 0; i < ITERATIONS && !found_bug; i++) {
        git_object_id_from_buffer(&result, data, len, &opts);
        if (!git_oid_equal(&reference, &result)) {
            found_bug = 1;
            printf("BUG: thread %d, iteration %d\n", id, i);
            break;
        }
    }
    return NULL;
}

int main(void) {
    git_libgit2_init();
    pthread_t threads[NUM_THREADS];
    int ids[NUM_THREADS];
    for (int i = 0; i < NUM_THREADS; i++) {
        ids[i] = i;
        pthread_create(&threads[i], NULL, hash_thread, &ids[i]);
    }
    for (int i = 0; i < NUM_THREADS; i++)
        pthread_join(threads[i], NULL);
    if (!found_bug)
        printf("No bug triggered\n");
    git_libgit2_shutdown();
    return found_bug ? 1 : 0;
}
```

Build and run (from libgit2 repo root):

```sh
mkdir build && cd build
cmake .. -DEXPERIMENTAL_SHA256=ON -DUSE_SHA256=Builtin \
  -DUSE_HTTPS=OFF -DUSE_SSH=OFF -DUSE_NTLMCLIENT=OFF \
  -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Debug
make libgit2package
cd ..
cc -O0 -pthread -DGIT_EXPERIMENTAL_SHA256=1 \
  -I include -o repro repro.c \
  build/libgit2-experimental.a -lz -lpcre2-8
./repro
```

See <https://github.com/rust-lang/git2-rs/issues/1255> for more.

[1]: https://github.com/libgit2/libgit2/blob/1affb8b19/src/util/hash/rfc6234/sha224-256.c#L86-L91
[2]: https://www.rfc-editor.org/rfc/rfc6234#section-8.2.2
2026-05-21 18:57:38 +01:00
Edward Thomson
4d232e344d cmake: separate generated headers from translated headers
Make a distinction between generated headers and "translated" headers.
This is important to support build-time dependencies when headers are
updated.

Generated headers are those which contain build-time feature
specifications, like `git2_features.h` that are internal to the build
and `experimental.h` that contain API information.

Translated headers are the headers that are in `include/git2`, but may
be translated to have a unique prefix like `incklude/git2-experimental`.

This distinction is important so that the CMakeFiles.txt depend on the
in-tree include files (`src/include`) and the generated header files
_but not_ the translated header files. Otherwise there are two `pack.h`
and it's unclear whether the in-tree build is targeting the one in
`src/include` or the one in the build tree.

Without this, updating an in-tree header file like `pack.h` would not
cause a rebuild of its dependencies.
2026-05-21 18:57:38 +01:00
Edward Thomson
563b45c36c cmake: use configure_file for generated headers
Use `configure_file` to move the generated headers into place, to avoid
unnecessary updates (and unnecessary rebuilds). See #7241
2026-05-21 14:18:31 +01:00
Cameron Will
0516d66f82 fix: Recognize relative worktrees extension
Git supports relative worktrees since Git v2.48 - cf6f63ea6b/Documentation/RelNotes/2.48.0.adoc (L57)

This was already handled programatically in libgit2, but was
not recognized as an extension, meaning downstream consumers
like Nix had issues with relative worktree-enabled repos.

Fixes #7210
2026-05-21 14:18:31 +01:00
Edward Thomson
f342d50b24 cli: avoid uninitialized variable warnings 2026-05-21 14:18:31 +01:00
Edward Thomson
7523c4d7c8 midx: avoid uninitialized variable 2026-05-21 14:18:31 +01:00
Edward Thomson
c61e8e72b5 index: initialize best_len unnecessarily
gcc thinks this could be used uninitialized; cope with this.
2026-05-21 14:18:31 +01:00
Edward Thomson
cd16dbb60f runtime: avoid uninitialized variable
`init_common` could return an uninitialized variable when there are no
subsystems; simply return `0` in this case.
2026-05-21 14:18:31 +01:00
Edward Thomson
523eaf8774 hashmap: initialize the variable
gcc thinks this could be used uninitialized; cope with this.
2026-05-21 14:18:31 +01:00
Edward Thomson
51f6d90cb4 runtime: initialize the variable
gcc thinks this could be uninitialized; make it so.
2026-05-17 12:30:56 +01:00
Edward Thomson
1affb8b193 Final final v1.9.3 updates (#7250) v1.9.3 2026-05-04 22:25:59 +01:00
Edward Thomson
13458671f3 Merge pull request #7242 from libgit2/ethomson/v1.9.3 2026-05-02 09:14:46 +01:00
Edward Thomson
397548d94f v1.9.3: update changelog 2026-05-02 08:55:40 +01:00
Edward Thomson
1803dfa284 xdiff: don't try to malloc 0 bytes
For zero byte files, avoid allocation - this avoids undefined behavior
around malloc(0) and potentially memcpy(..., NULL, 0).
2026-05-02 08:55:40 +01:00
Edward Thomson
047da6a2ca merge_files: some simplification 2026-05-02 08:55:40 +01:00
Edward Thomson
244d6fd827 merge_files: test with zero-byte file
Test handing a zero byte but extant file to merge_files.
2026-05-02 08:55:40 +01:00
Edmundo Carmona Antoranz
e97c067038 merge_file.c - allow ours or theirs to be NULL in git_merge_file_from_index
Improve git_merge_file_from_index by adding suport to missing children.
2026-05-02 08:55:40 +01:00
Edmundo Carmona Antoranz
b93afbc48f merge.h - improve handling when there is no ancestor in merge_file__best_path
In cases when a path is missing from the ancestor and only of the two
children is defined (IOW, the object is added), then the path in the child
that is defined should be returned.

However, merge_file__best_path is only returning a path in cases when there
is no ancestor path only if both children are defined and they match each
other.

Improve merge_file__best_path by handling the case when it is present in
only one of the children paths returning this value.
2026-05-02 08:55:40 +01:00
Edmundo Carmona Antoranz
0bd182129f git_merge_file_from_index: add unit test for deleted/added file 2026-05-02 08:55:40 +01:00
Kevin Saul
84de50665b cmake: write git.h.tmp to current binary directory 2026-05-02 08:50:34 +01:00
Kan-Ru Chen
e2d2a04487 fix(pack): ensure pack_backend__read returns null terminated buffer
Depending on the zlib library used, the inflate() function may write
beyond the object size into the additional trailing buffer for aligned
memory copies. This may cause out-of-bounds memory read if the object
buffer is later used without checking the object size, as in
git_commit__extract_signature.

Link: https://github.com/zlib-ng/zlib-ng/issues/1767
Signed-off-by: Kan-Ru Chen <kanru@kanru.info>
2026-05-02 08:50:34 +01:00
Edward Thomson
927d919e23 Merge pull request #7233 from libgit2/ethomson/v1.9.3
v1.9.3
2026-04-30 23:48:51 +01:00
Edward Thomson
378d62d278 v1.9.3: update changelog 2026-04-30 23:28:37 +01:00
Edward Thomson
4ff809dd02 v1.9.3: update version numbers 2026-04-30 23:28:37 +01:00
Edward Thomson
45eb06c4d8 object: test looking up truncated objects
Add a test that looks up an invalid, truncated object, that is shorter
than the advertised length.
2026-04-30 23:28:37 +01:00
Rasheeq Azad
133597404b Check object lengths against headers in read_loose
Avoid a buffer overrun when an object's header specifies a short length
but the body is longer (fix #7177). Take care to preserve the behavior
that too-short object bodies are not an error but get zero-padded.
2026-04-30 23:23:26 +01:00
Edward Thomson
73d121f1ff cmake: don't recreate git2.h unnecessarily
Instead of regenerating `git2.h` on every cmake invocation, use
`configure_file` to avoid rewriting it. This keeps timestamps inline and
avoids unnecessarily rebuilding the library.
2026-04-29 21:36:52 +01:00
Kevin Saul
68bac3f8b9 config: fix crash after memory backend entry freed 2026-04-29 21:36:52 +01:00
Kevin Saul
19e5738d80 config: update memory backend test to reproduce crash 2026-04-29 21:36:52 +01:00
Oliver Chang
4c2fdc7ed2 Fixed a heap-buffer-overflow in the smart_pkt.c:set_data function.
The strstr call used to find the " object-format=" capability string did
not have a length limit, potentially reading past the end of the
allocated buffer if the capabilities string was not null-terminated
within the buffer bounds. Replaced strstr with git__memmem and
subsequent strchr calls with memchr, providing the remaining buffer
length as a limit to prevent out-of-bounds reads.

https: //oss-fuzz.com/testcase-detail/4895812384325632
https: //issues.oss-fuzz.com/issues/42524461
Change-Id: Id313af1bce48ea8763fa2dfd7eb9ee8934fa541f
2026-04-29 21:36:52 +01:00
Weihang Lo
28ccde8d72 fix(transport): get oid_type on local transport
Cache `oid_type` in `transport_local` struct during `connect()`
so `git_remote_oid_type()` keeps working after disconnect.

This matches the smart transport behavior.
2026-04-29 14:22:12 +01:00
Weihang Lo
db20a0511b test(transport): get oid_type on local transport
Exercise git_remote_oid_type on a SHA256 local transport.

The after-disconnect assertion is commented out because
local_oid_type dereferences `t->repo`, which local_close
has already freed (SIGSEGV).

I ran these commands to test btw:

```
cmake .. -DGIT_EXPERIMENTAL_SHA256=ON -DBUILD_TESTS=ON
cmake --build .
./libgit2_tests -snetwork::remote::local::sha256_oid_type
```
2026-04-29 14:22:12 +01:00
Weihang Lo
390654b83e fix(remote): apply insteadOf from global config for detached remotes
Detached remotes already read global/system config for http proxy
settings, but did not apply url.*.insteadOf or url.*.pushInsteadOf
rules. This inconsistency meant that `git_remote_create_detached`
behaved differently from git's `ls-remote`, which was the primary
use case for detached remotes.

This fixes it by loading the default config when no repository is
provided and apply insteadOf rules consistently.

While this is a behavior change, it still respects
`GIT_REMOTE_CREATE_SKIP_INSTEADOF`, meaning that user can restore
the previous behavior with minimal effort

Fixes https://github.com/libgit2/libgit2/issues/5469
2026-04-29 14:22:12 +01:00
Weihang Lo
95cbdc0386 test(remote): show buggy detached remote insteadOf behavior
`git_remote_create_detached` does not apply
`url.*.insteadOf` or url.*.pushInsteadOf from global config.

These tests currently pass, asserting the buggy behavior
and serving as a minimal reproduction.

The assertions will be updated when the fix is applied.

See <https://github.com/libgit2/libgit2/issues/5469>
2026-04-29 14:22:12 +01:00
Daniel Scherzer
dbe042bf85 GIT_REMOTE_DOWNLOAD_TAGS_ALL: remove stray "the" in docs 2026-04-29 14:22:12 +01:00
Edward Thomson
32d912f369 Apply suggestions from code review
Co-authored-by: Edward Thomson <ethomson@edwardthomson.com>
2026-04-29 14:22:12 +01:00
Weihang Lo
ebb93a0ef2 fix(clone): propagate object format in local clone
`clone_local_into()` copies objects from the source repository
but does not set the destination's object format.
This cause SHA256 repositories to be unreadable after a local clone
because the destination defaults to SHA1.

The remote clone path already handles this correctly
so local clone path follows suite.

See: <https://github.com/libgit2/libgit2/blob/1f34e2a57/src/libgit2/clone.c#L448-L450>
2026-04-29 14:22:11 +01:00
Weihang Lo
3f20e0c71b test(clone): document SHA256 local clone failure
Local clone, both hardlink and copy paths, does not propagate
the source repository's object format to the destination.

A SHA256 repository cloned locally is initialized as SHA1
and caused object lookup failures.

These tests are added as reproducible examples,
and will be fixed in the next commit

* `sha256_via_no_local`
  * `file://` URL + `GIT_CLONE_NO_LOCAL` -> remote code path
* `sha256_object_format_is_propagated`
  * `file://` URL + `GIT_CLONE_LOCAL` -> local code path with hardlinks
* `sha256_no_links_object_format_is_propagated`
  * `file://` URL + `GIT_CLONE_LOCAL_NO_LINKS` -> local code path with copy
2026-04-29 14:22:11 +01:00
Sven Strickroth
d5f5af2490 repo: Fix possible null pointer dereference
Signed-off-by: Sven Strickroth <email@cs-ware.de>
2026-04-29 14:22:11 +01:00
Kovacsics Robert
f223ba4257 revparse: Allow HEAD abbreviation @
The `@` alone (without predeeding refname in `<refname>@`) is an
alias for HEAD, and can then be used with other modifiers for example
`HEAD^{/...}`
2026-04-29 14:22:11 +01:00
Chris Hoffman
47e42db06b futils: fix undefined behavior in O_FSYNC fallback definition
The fallback definition of O_FSYNC uses `(1 << 31)`, which is undefined
behavior in C. The literal `1` is a signed int, and left-shifting into
the sign bit of a signed integer is undefined per the C standard.

This causes crashes on arm64 Linux with musl libc (which doesn't define
O_FSYNC), manifesting as:

    thread panic: left shift of 1 by 31 places cannot be represented
    in type 'int'

Fall back to O_SYNC when available, since it is the POSIX standard name
for the same flag. On platforms where neither is defined (e.g. Windows),
use (1 << 30) as a sentinel value that avoids the sign bit.
2026-04-29 14:22:11 +01:00
Carlos Martín Nieto
e2621b7528 camke: include libssh2 in Requires.private in the PC file
We need this in order for `pkg-config` to be able to tell what you should link
against when building libgit2 statically. We do include libssh2 in
`Libs.private` but not in `Requires.private`. The difference is a bit subtle but
has become important.

You can call `pkg-config --libs --static ${build}/libgit2.pc` and it will give
you what is in the Libs line, and also what the packages from the Requires field
have in theirs. This is what e.g. `rugged` does and it has been working until
recently. An update to openssl to require zstd now means that using `--libs
--static` returns `-lzstd` as well as many others. This means that those who
want to link using that command now need to have the development packages for
zstd installed, which should not be necessary as libgit2 itself doesn't want to
use anything from it.

A better command to use here seems to be `pkg-config --libs --static --pure
${build}/libgit2.pc`. The manpage and help output are not very precise but what
this does is limit the list of dependencies to a single layer, which is what we
want as we would only want to link statically against libgit2 and not the rest
of the libraries.

But trying to do so breaks building with libssh2 as it's included in the Libs
field rather than the Requires, so that command excludes any linking to libssh2.

Put libssh2 in the `Requires.private` field so we correctly express we need to
link to it when linking statically.

This is unfortunately an imperfect fix as now, if we did not find libssh2 via
pkg-config but rather via CMake's `find_package`, the combination of `--static
--pure` does not take `Libs.private` into account. However we only support this
as an edge case and we expect `pkg-config` to be available for the rest of our
dependencies.
2026-04-29 14:22:11 +01:00
Edward Thomson
e307ea42c2 pcre: actually fix dangling-pointer warning 2026-04-29 14:22:11 +01:00
Edward Thomson
93042e319c pcre: update cmake warnings for non-gcc 2026-04-29 14:22:11 +01:00
Edward Thomson
66aad27219 hashmap: tests initialize to NULL to avoid warnings 2026-04-29 14:22:11 +01:00
Edward Thomson
ee7f46abc7 config: tests set entry to NULL to avoid warnings 2026-04-29 14:22:11 +01:00
Edward Thomson
207827b0e7 pcre: avoid false positive dangling pointer warning
PCRE sets the contents of an external structure to a local pointer
temporarily. gcc warns about this. Silence that dangling pointer
warning.
2026-04-29 14:22:11 +01:00