diff options
author | Paul Cristian Sarbu <paul.cristian.sarbu@huawei.com> | 2023-03-27 18:15:08 +0200 |
---|---|---|
committer | Paul Cristian Sarbu <paul.cristian.sarbu@huawei.com> | 2023-03-30 13:45:00 +0200 |
commit | ed9bfe29a1d54a6dca1fa85853457c56108a6183 (patch) | |
tree | dcfa02e41e34cb727855e2d8cdbf0bcb9bbb2fba /src/buildtool/file_system/git_repo.hpp | |
parent | 0c90ad4bf580a385aa7056298452980b5f8ceb83 (diff) | |
download | justbuild-ed9bfe29a1d54a6dca1fa85853457c56108a6183.tar.gz |
GitRepo: Guard fake repository odb wrapping
In the current libgit2 implementation, a fake repository wrapped
around an existing odb is being registered as owner the same way
as a normal repository object. Therefore, one has to guard both
the creation and destruction of the fake repository against all
other git operations that might access the internal cache during
this transfer of ownership.
Diffstat (limited to 'src/buildtool/file_system/git_repo.hpp')
-rw-r--r-- | src/buildtool/file_system/git_repo.hpp | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/src/buildtool/file_system/git_repo.hpp b/src/buildtool/file_system/git_repo.hpp index eba826d9..c66a54db 100644 --- a/src/buildtool/file_system/git_repo.hpp +++ b/src/buildtool/file_system/git_repo.hpp @@ -19,6 +19,10 @@ #include "src/buildtool/file_system/git_cas.hpp" +extern "C" { +struct git_repository; +} + /// \brief Git repository logic. /// Models both a real repository, owning the underlying ODB /// (non-thread-safe), as well as a "fake" repository, which only wraps an @@ -196,11 +200,35 @@ class GitRepo { -> std::optional<bool>; private: + /// \brief Wrapped git_repository with guarded destructor. + /// Kept privately nested to avoid misuse of its raw pointer members. + class GuardedRepo { + public: + GuardedRepo() noexcept = delete; + explicit GuardedRepo(std::shared_mutex* mutex) noexcept; + ~GuardedRepo() noexcept; + + // prohibit moves and copies + GuardedRepo(GuardedRepo const&) = delete; + GuardedRepo(GuardedRepo&& other) = delete; + auto operator=(GuardedRepo const&) = delete; + auto operator=(GuardedRepo&& other) = delete; + + // get the bare pointer + [[nodiscard]] auto Ptr() -> git_repository*; + [[nodiscard]] auto PtrRef() -> git_repository**; + + private: + std::shared_mutex* mutex_; + git_repository* repo_{nullptr}; + }; + + using GuardedRepoPtr = std::shared_ptr<GuardedRepo>; + // IMPORTANT! The GitCAS object must be defined before the repo object to // keep the GitContext alive until cleanup ends. GitCASPtr git_cas_{nullptr}; - std::unique_ptr<git_repository, decltype(&repo_closer)> repo_{nullptr, - repo_closer}; + GuardedRepoPtr repo_{nullptr}; // default to real repo, as that is non-thread-safe bool is_repo_fake_{false}; @@ -210,8 +238,7 @@ class GitRepo { /// \brief Open real repository at given location. explicit GitRepo(std::filesystem::path const& repo_path) noexcept; - [[nodiscard]] auto GetRepoRef() const noexcept - -> std::unique_ptr<git_repository, decltype(&repo_closer)> const&; + [[nodiscard]] auto GetRepoRef() const noexcept -> GuardedRepoPtr; [[nodiscard]] auto GetGitPath() const noexcept -> std::filesystem::path const&; |