Commit c0487bde7e3891af7b759a092751294d703fef9d

Patrick Steinhardt 2018-01-12T08:23:43

tree: reject writing null-OID entries to a tree In commit a96d3cc3f (cache-tree: reject entries with null sha1, 2017-04-21), the git.git project has changed its stance on null OIDs in tree objects. Previously, null OIDs were accepted in tree entries to help tools repair broken history. This resulted in some problems though in that many code paths mistakenly passed null OIDs to be added to a tree, which was not properly detected. Align our own code base according to the upstream change and reject writing tree entries early when the OID is all-zero.

diff --git a/src/tree.c b/src/tree.c
index 75fde2c..6a136a6 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -498,6 +498,9 @@ static int append_entry(
 	if (!valid_entry_name(bld->repo, filename))
 		return tree_error("failed to insert entry: invalid name for a tree entry", filename);
 
+	if (git_oid_iszero(id))
+		return tree_error("failed to insert entry: invalid null OID for a tree entry", filename);
+
 	entry = alloc_entry(filename, strlen(filename), id);
 	GITERR_CHECK_ALLOC(entry);
 
@@ -740,6 +743,9 @@ int git_treebuilder_insert(
 	if (!valid_entry_name(bld->repo, filename))
 		return tree_error("failed to insert entry: invalid name for a tree entry", filename);
 
+	if (git_oid_iszero(id))
+		return tree_error("failed to insert entry: invalid null OID", filename);
+
 	if (filemode != GIT_FILEMODE_COMMIT &&
 	    !git_object__is_valid(bld->repo, id, otype_from_mode(filemode)))
 		return tree_error("failed to insert entry: invalid object specified", filename);
diff --git a/tests/object/tree/write.c b/tests/object/tree/write.c
index a9decf9..9690ec4 100644
--- a/tests/object/tree/write.c
+++ b/tests/object/tree/write.c
@@ -512,3 +512,14 @@ void test_object_tree_write__object_validity(void)
 	test_inserting_submodule();
 }
 
+void test_object_tree_write__invalid_null_oid(void)
+{
+	git_treebuilder *bld;
+	git_oid null_oid = {{0}};
+
+	cl_git_pass(git_treebuilder_new(&bld, g_repo, NULL));
+	cl_git_fail(git_treebuilder_insert(NULL, bld, "null_oid_file", &null_oid, GIT_FILEMODE_BLOB));
+	cl_assert(giterr_last() && strstr(giterr_last()->message, "null OID") != NULL);
+
+	git_treebuilder_free(bld);
+}