Commit ff85adf0d7919ac37946875997aeec119f7a6374

Edward Thomson 2022-04-12T15:29:11

Merge pull request #6269 from libgit2/ethomson/14_backports Backports to v1.4

diff --git a/fuzzers/corpora/midx/666a779eed16847c6930a71c0547a34e52db409e b/fuzzers/corpora/midx/666a779eed16847c6930a71c0547a34e52db409e
new file mode 100644
index 0000000..ed9e0d0
Binary files /dev/null and b/fuzzers/corpora/midx/666a779eed16847c6930a71c0547a34e52db409e differ
diff --git a/src/diff_print.c b/src/diff_print.c
index 03d25b0..6c5a2cd 100644
--- a/src/diff_print.c
+++ b/src/diff_print.c
@@ -316,6 +316,11 @@ static int diff_print_oid_range(
 static int diff_delta_format_path(
 	git_str *out, const char *prefix, const char *filename)
 {
+	if (!filename) {
+		/* don't prefix "/dev/null" */
+ 		return git_str_puts(out, "/dev/null");
+	}
+
 	if (git_str_joinpath(out, prefix, filename) < 0)
 		return -1;
 
diff --git a/src/fetch.c b/src/fetch.c
index 03d3845..e9f30d9 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -76,8 +76,11 @@ static int maybe_want_oid(git_remote *remote, git_refspec *spec)
 	GIT_ERROR_CHECK_ALLOC(oid_head);
 
 	git_oid_fromstr(&oid_head->oid, spec->src);
-	oid_head->name = git__strdup(spec->dst);
-	GIT_ERROR_CHECK_ALLOC(oid_head->name);
+
+	if (spec->dst) {
+		oid_head->name = git__strdup(spec->dst);
+		GIT_ERROR_CHECK_ALLOC(oid_head->name);
+	}
 
 	if (git_vector_insert(&remote->local_heads, oid_head) < 0 ||
 	    git_vector_insert(&remote->refs, oid_head) < 0)
diff --git a/src/midx.c b/src/midx.c
index eb99e73..0092601 100644
--- a/src/midx.c
+++ b/src/midx.c
@@ -225,8 +225,13 @@ int git_midx_parse(
 	chunk_hdr = data + sizeof(struct git_midx_header);
 	last_chunk = NULL;
 	for (i = 0; i < hdr->chunks; ++i, chunk_hdr += 12) {
-		chunk_offset = ((off64_t)ntohl(*((uint32_t *)(chunk_hdr + 4)))) << 32 |
-				((off64_t)ntohl(*((uint32_t *)(chunk_hdr + 8))));
+		uint32_t chunk_id = ntohl(*((uint32_t *)(chunk_hdr + 0)));
+		uint64_t high_offset = ((uint64_t)ntohl(*((uint32_t *)(chunk_hdr + 4)))) & 0xffffffffu;
+		uint64_t low_offset = ((uint64_t)ntohl(*((uint32_t *)(chunk_hdr + 8)))) & 0xffffffffu;
+
+		if (high_offset >= INT32_MAX)
+			return midx_error("chunk offset out of range");
+		chunk_offset = (off64_t)(high_offset << 32 | low_offset);
 		if (chunk_offset < last_chunk_offset)
 			return midx_error("chunks are non-monotonic");
 		if (chunk_offset >= trailer_offset)
@@ -235,7 +240,7 @@ int git_midx_parse(
 			last_chunk->length = (size_t)(chunk_offset - last_chunk_offset);
 		last_chunk_offset = chunk_offset;
 
-		switch (ntohl(*((uint32_t *)(chunk_hdr + 0)))) {
+		switch (chunk_id) {
 		case MIDX_PACKFILE_NAMES_ID:
 			chunk_packfile_names.offset = last_chunk_offset;
 			last_chunk = &chunk_packfile_names;
diff --git a/src/remote.c b/src/remote.c
index f6421b9..1a79faa 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -1895,8 +1895,11 @@ static int update_tips_for_spec(
 	if (git_oid__is_hexstr(spec->src)) {
 		git_oid id;
 
-		if ((error = git_oid_fromstr(&id, spec->src)) < 0 ||
-		    (error = update_ref(remote, spec->dst, &id, log_message, callbacks)) < 0)
+		if ((error = git_oid_fromstr(&id, spec->src)) < 0)
+			goto on_error;
+
+		if (spec->dst &&
+		     (error = update_ref(remote, spec->dst, &id, log_message, callbacks)) < 0)
 			goto on_error;
 
 		git_oid_cpy(&oid_head.oid, &id);
diff --git a/tests/diff/parse.c b/tests/diff/parse.c
index d3a0c8d..9c3f798 100644
--- a/tests/diff/parse.c
+++ b/tests/diff/parse.c
@@ -431,6 +431,32 @@ void test_diff_parse__new_file_with_space(void)
 	git_diff_free(diff);
 }
 
+void test_diff_parse__new_file_with_space_and_regenerate_patch(void)
+{
+	const char *content = PATCH_ORIGINAL_NEW_FILE_WITH_SPACE;
+	git_diff *diff = NULL;
+	git_buf buf = GIT_BUF_INIT;
+
+	cl_git_pass(git_diff_from_buffer(&diff, content, strlen(content)));
+	cl_git_pass(git_diff_to_buf(&buf, diff, GIT_DIFF_FORMAT_PATCH));
+
+	git_buf_dispose(&buf);
+	git_diff_free(diff);
+}
+
+void test_diff_parse__delete_file_with_space_and_regenerate_patch(void)
+{
+	const char *content = PATCH_DELETE_FILE_WITH_SPACE;
+	git_diff *diff = NULL;
+	git_buf buf = GIT_BUF_INIT;
+
+	cl_git_pass(git_diff_from_buffer(&diff, content, strlen(content)));
+	cl_git_pass(git_diff_to_buf(&buf, diff, GIT_DIFF_FORMAT_PATCH));
+
+	git_buf_dispose(&buf);
+	git_diff_free(diff);
+}
+
 void test_diff_parse__crlf(void)
 {
 	const char *text = PATCH_CRLF;
diff --git a/tests/online/fetch.c b/tests/online/fetch.c
index 7334f7e..5beb5b6 100644
--- a/tests/online/fetch.c
+++ b/tests/online/fetch.c
@@ -321,3 +321,32 @@ void test_online_fetch__reachable_commit(void)
 	git_object_free(obj);
 	git_remote_free(remote);
 }
+
+void test_online_fetch__reachable_commit_without_destination(void)
+{
+	git_remote *remote;
+	git_strarray refspecs;
+	git_object *obj;
+	git_oid expected_id;
+	git_str fetchhead = GIT_STR_INIT;
+	char *refspec = "2c349335b7f797072cf729c4f3bb0914ecb6dec9";
+
+	refspecs.strings = &refspec;
+	refspecs.count = 1;
+
+	git_oid_fromstr(&expected_id, "2c349335b7f797072cf729c4f3bb0914ecb6dec9");
+
+	cl_git_pass(git_remote_create(&remote, _repo, "test",
+		"https://github.com/libgit2/TestGitRepository"));
+	cl_git_pass(git_remote_fetch(remote, &refspecs, NULL, NULL));
+
+	cl_git_fail_with(GIT_ENOTFOUND, git_revparse_single(&obj, _repo, "refs/success"));
+
+	cl_git_pass(git_futils_readbuffer(&fetchhead, "./fetch/.git/FETCH_HEAD"));
+	cl_assert_equal_s(fetchhead.ptr,
+		"2c349335b7f797072cf729c4f3bb0914ecb6dec9\t\t'2c349335b7f797072cf729c4f3bb0914ecb6dec9' of https://github.com/libgit2/TestGitRepository\n");
+
+	git_str_dispose(&fetchhead);
+	git_object_free(obj);
+	git_remote_free(remote);
+}
diff --git a/tests/patch/patch_common.h b/tests/patch/patch_common.h
index 1e03889..7e2cb6a 100644
--- a/tests/patch/patch_common.h
+++ b/tests/patch/patch_common.h
@@ -933,6 +933,15 @@
 	"@@ -0,0 +1 @@\n" \
 	"+a\n"
 
+#define PATCH_DELETE_FILE_WITH_SPACE \
+	"diff --git a/sp ace.txt b/sp ace.txt\n" \
+	"deleted file mode 100644\n" \
+	"index 789819226..000000000\n" \
+	"--- a/sp ace.txt\n" \
+	"+++ /dev/null\n" \
+	"@@ -1 +0,0 @@\n" \
+	"-a\n"
+
 #define PATCH_CRLF \
 	"diff --git a/test-file b/test-file\r\n" \
 	"new file mode 100644\r\n" \