summaryrefslogtreecommitdiff
path: root/etc/patches/libgit2_v1.1.0_fix-fake-repo.patch
diff options
context:
space:
mode:
authorOliver Reiche <oliver.reiche@huawei.com>2022-08-04 13:52:16 +0200
committerOliver Reiche <oliver.reiche@huawei.com>2022-08-04 16:06:54 +0200
commitacb5da12d37158fdf8e05f3589cc2dd9b7721863 (patch)
treed0bce269d83f57b759b8145731d4ee217ebdfc86 /etc/patches/libgit2_v1.1.0_fix-fake-repo.patch
parentfe3b10643dd743c56db51b9ef4a090c460668e8d (diff)
downloadjustbuild-acb5da12d37158fdf8e05f3589cc2dd9b7721863.tar.gz
libgit2: Patch race condition with fake repositories
Diffstat (limited to 'etc/patches/libgit2_v1.1.0_fix-fake-repo.patch')
-rw-r--r--etc/patches/libgit2_v1.1.0_fix-fake-repo.patch146
1 files changed, 146 insertions, 0 deletions
diff --git a/etc/patches/libgit2_v1.1.0_fix-fake-repo.patch b/etc/patches/libgit2_v1.1.0_fix-fake-repo.patch
new file mode 100644
index 00000000..85bab5a6
--- /dev/null
+++ b/etc/patches/libgit2_v1.1.0_fix-fake-repo.patch
@@ -0,0 +1,146 @@
+From bf27a288adce36e2a57e26146d18c224ebc745be Mon Sep 17 00:00:00 2001
+From: Oliver Reiche <oliver.reiche@huawei.com>
+Date: Wed, 3 Aug 2022 16:27:58 +0200
+Subject: [PATCH] Do not register fake repository as owner of ODB
+
+Accessing ODB is guaranteed to be thread-safe. Registering a
+fake repository (created via git_repository_wrap_odb()) may
+not register itself as owner of the ODB in order to maintain
+that guarantee. Otherwise, accessing objects from ODB will
+try to obtain the cache from the owning repository (via
+odb_cache()) and produce a race if this ODB is concurrently
+used to create fake repositories in other threads.
+Consequently, operations on fake repositories will interact
+with the ODB's cache instead of the repository's cache.
+---
+ include/git2/sys/repository.h | 3 ++-
+ src/repository.c | 16 +++++++++-------
+ tests/odb/backend/nobackend.c | 2 +-
+ tests/repo/setters.c | 23 ++++++++++++++++++++++-
+ 4 files changed, 34 insertions(+), 10 deletions(-)
+
+diff --git a/include/git2/sys/repository.h b/include/git2/sys/repository.h
+index 892be6692..33bc5051f 100644
+--- a/include/git2/sys/repository.h
++++ b/include/git2/sys/repository.h
+@@ -97,9 +97,10 @@ GIT_EXTERN(int) git_repository_set_config(git_repository *repo, git_config *conf
+ *
+ * @param repo A repository object
+ * @param odb An ODB object
++ * @param set_owner Register repository as owner of ODB
+ * @return 0 on success, or an error code
+ */
+-GIT_EXTERN(int) git_repository_set_odb(git_repository *repo, git_odb *odb);
++GIT_EXTERN(int) git_repository_set_odb(git_repository *repo, git_odb *odb, bool set_owner);
+
+ /**
+ * Set the Reference Database Backend for this repository
+diff --git a/src/repository.c b/src/repository.c
+index 513dbd61f..9e5aa6a16 100644
+--- a/src/repository.c
++++ b/src/repository.c
+@@ -86,10 +86,12 @@ git_buf git_repository__reserved_names_posix[] = {
+ };
+ size_t git_repository__reserved_names_posix_len = 1;
+
+-static void set_odb(git_repository *repo, git_odb *odb)
++static void set_odb(git_repository *repo, git_odb *odb, bool set_owner)
+ {
+ if (odb) {
+- GIT_REFCOUNT_OWN(odb, repo);
++ if (set_owner) {
++ GIT_REFCOUNT_OWN(odb, repo);
++ }
+ GIT_REFCOUNT_INC(odb);
+ }
+
+@@ -150,7 +152,7 @@ int git_repository__cleanup(git_repository *repo)
+
+ set_config(repo, NULL);
+ set_index(repo, NULL);
+- set_odb(repo, NULL);
++ set_odb(repo, NULL, /*set_owner=*/true);
+ set_refdb(repo, NULL);
+
+ return 0;
+@@ -722,7 +724,7 @@ static int _git_repository_open_ext_from_env(
+ goto error;
+
+ if (odb)
+- git_repository_set_odb(repo, odb);
++ git_repository_set_odb(repo, odb, /*set_owner=*/true);
+
+ error = git__getenv(&alts_buf, "GIT_ALTERNATE_OBJECT_DIRECTORIES");
+ if (error == GIT_ENOTFOUND) {
+@@ -932,7 +934,7 @@ int git_repository_wrap_odb(git_repository **repo_out, git_odb *odb)
+ repo = repository_alloc();
+ GIT_ERROR_CHECK_ALLOC(repo);
+
+- git_repository_set_odb(repo, odb);
++ git_repository_set_odb(repo, odb, /*set_owner=*/false);
+ *repo_out = repo;
+
+ return 0;
+@@ -1139,10 +1141,10 @@ int git_repository_odb(git_odb **out, git_repository *repo)
+ return 0;
+ }
+
+-int git_repository_set_odb(git_repository *repo, git_odb *odb)
++int git_repository_set_odb(git_repository *repo, git_odb *odb, bool set_owner)
+ {
+ assert(repo && odb);
+- set_odb(repo, odb);
++ set_odb(repo, odb, set_owner);
+ return 0;
+ }
+
+diff --git a/tests/odb/backend/nobackend.c b/tests/odb/backend/nobackend.c
+index 7484d423b..d46a7fed9 100644
+--- a/tests/odb/backend/nobackend.c
++++ b/tests/odb/backend/nobackend.c
+@@ -16,7 +16,7 @@ void test_odb_backend_nobackend__initialize(void)
+ cl_git_pass(git_refdb_new(&refdb, _repo));
+
+ git_repository_set_config(_repo, config);
+- git_repository_set_odb(_repo, odb);
++ git_repository_set_odb(_repo, odb, /*set_owner=*/true);
+ git_repository_set_refdb(_repo, refdb);
+
+ /* The set increases the refcount and we don't want them anymore */
+diff --git a/tests/repo/setters.c b/tests/repo/setters.c
+index 1fac627f6..bf1b31783 100644
+--- a/tests/repo/setters.c
++++ b/tests/repo/setters.c
+@@ -94,7 +94,28 @@ void test_repo_setters__setting_a_new_odb_on_a_repo_which_already_loaded_one_pro
+ cl_git_pass(git_odb_open(&new_odb, "./testrepo.git/objects"));
+ cl_assert(((git_refcount *)new_odb)->refcount.val == 1);
+
+- git_repository_set_odb(repo, new_odb);
++ git_repository_set_odb(repo, new_odb, /*set_owner=*/true);
++ cl_assert(((git_refcount *)new_odb)->refcount.val == 2);
++
++ git_repository_free(repo);
++ cl_assert(((git_refcount *)new_odb)->refcount.val == 1);
++
++ git_odb_free(new_odb);
++
++ /*
++ * Ensure the cleanup method won't try to free the repo as it's already been taken care of
++ */
++ repo = NULL;
++}
++
++void test_repo_setters__setting_a_new_odb_on_a_non_owner_repo_which_already_loaded_one_properly_honors_the_refcount(void)
++{
++ git_odb *new_odb;
++
++ cl_git_pass(git_odb_open(&new_odb, "./testrepo.git/objects"));
++ cl_assert(((git_refcount *)new_odb)->refcount.val == 1);
++
++ git_repository_set_odb(repo, new_odb, /*set_owner=*/false);
+ cl_assert(((git_refcount *)new_odb)->refcount.val == 2);
+
+ git_repository_free(repo);
+--
+2.25.1
+