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@xxxxxxxxx> Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> ## 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@xxxxxxxxx> Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> ## merge-ort.c ## -- gitgitgadget