[PATCH v5 0/2] merge-tree: fix segmentation fault in read-only repositories
- From
Johannes Schindelin via GitGitGadget <gitgitgadget@gmail.com>
- Date
- Sep 28, 2022, 07:29 UTC
- Message-ID
- <pull.1362.v5.git.1664350162.gitgitgadget@gmail.com>
- In-Reply-To
- <pull.1362.v4.git.1664229348.gitgitgadget@gmail.com>
Turns out that the segmentation fault reported by Taylor [https://lore.kernel.org/git/YyopQD+LvPucnz3w@nand.local/] happened while testing merge-ort in a read-only repository, and that the upstream version of git merge-tree is as affected as GitHub's internal version.
Changes since v4:
* Corrected the commit message that claimed that the second patch was not fixing a real bug but just avoided unnecessary work. As pointed out by Elijah, there are scenarios where this second patch fixes a very real bug. * Added Elijah's "Reviewed-by" footer.
Changes since v3:
* I now consistently use the pattern int ret = 0; ... if (...) ret = -1. * I added a commit to properly propagate write failures through the handle_content_merge() call path, even if it is not really critical (it just fails sooner, but the merge would have failed just the same without this patch).
Changes since v2:
* Completely changed the approach by no longer touching builtin/merge-tree.c but instead fixing the underlying merge-ort layer: we no longer ignore the return value of write_tree() and write_object_file().
Changes since v1:
* Using the SANITY prereq now * If the merge was aborted due to a write error, exit with a non-zero code even if the (potentially partial) merge is clean * The test case now also verifies that the git merge-tree command fails in a read-only repository even if the merge would have succeeded
Johannes Schindelin (2): merge-ort: fix segmentation fault in read-only repositories merge-ort: return early when failing to write a blob
merge-ort.c | 94 ++++++++++++++++++++------------ t/t4301-merge-tree-write-tree.sh | 9 +++ 2 files changed, 69 insertions(+), 34 deletions(-)
base-commit: dda7228a83e2e9ff584bf6adbf55910565b41e14 Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1362%2Fdscho%2Fmerge-tree-in-read-only-repos-v5 Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1362/dscho/merge-tree-in-read-only-repos-v5 Pull-Request: https://github.com/gitgitgadget/git/pull/1362
Range-diff vs v4:
1: ab6df092eba ! 1: 63be9f9f717 merge-ort: fix segmentation fault in read-only repositories
@@ Commit message
Let's stop ignoring the return value of `write_object_file()` and
`write_tree()` and set `clean = -1` in the error case.
+ Reviewed-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
## merge-ort.c ##
2: 087207ae0b0 ! 2: bfc71a2d8ad merge-ort: return early when failing to write a blob
@@ Commit message
that already exists in the database). And this can fail, too, but we
ignore that write failure so far.
- Since we will always write out a new tree object in addition to the blob
- (and if the blob did not exist in the database yet, we can be certain
- that the tree object did not exist yet), the merge will _still_ fail at
- that point, but it does unnecessary work by continuing after the blob
- could not be written.
-
Let's pay close attention and error out early if the blob could not be
written. This reduces the error output of t4301.25 ("merge-ort fails
gracefully in a read-only repository") from:
@@ Commit message
error: error: Unable to add numbers to database
fatal: failure to merge
+ This is _not_ just a cosmetic change: Even though one might assume that
+ the operation would have failed anyway at the point when the new tree
+ object is written (and the corresponding tree object _will_ be new if it
+ contains a blob that is new), but that is not so: As pointed out by
+ Elijah Newren, when Git has previously been allowed to add loose objects
+ via `sudo` calls, it is very possible that the blob object cannot be
+ written (because the corresponding `.git/objects/??/` directory may be
+ owned by `root`) but the tree object can be written (because the
+ corresponding objects directory is owned by the current user). This
+ would result in a corrupt repository because it is missing the blob
+ object, and with this here patch we prevent that.
+
Note: This patch adjusts two variable declarations from `unsigned` to
`int` because their purpose is to hold the return value of
`handle_content_merge()`, which is of type `int`. The existing users of
those variables are only interested whether that variable is zero or
non-zero, therefore this type change does not affect the existing code.
+ Reviewed-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
## merge-ort.c ##-- gitgitgadget