Commit e544a5b8e5f823ff50049a4bd1b357c2e027c89d

Vicent Martí 2013-11-19T04:54:31

Merge pull request #1968 from libgit2/ntk/fix/bad_index Corrupted index is bad for your health

diff --git a/src/index.c b/src/index.c
index ecab150..09e7b23 100644
--- a/src/index.c
+++ b/src/index.c
@@ -321,6 +321,7 @@ void git_index__set_ignore_case(git_index *index, bool ignore_case)
 int git_index_open(git_index **index_out, const char *index_path)
 {
 	git_index *index;
+	int error;
 
 	assert(index_out);
 
@@ -346,10 +347,15 @@ int git_index_open(git_index **index_out, const char *index_path)
 	index->entries_search_path = index_srch_path;
 	index->reuc_search = reuc_srch;
 
+	if ((index_path != NULL) && ((error = git_index_read(index, true)) < 0)) {
+		git_index_free(index);
+		return error;
+	}
+
 	*index_out = index;
 	GIT_REFCOUNT_INC(index);
 
-	return (index_path != NULL) ? git_index_read(index, true) : 0;
+	return 0;
 }
 
 int git_index_new(git_index **out)
diff --git a/src/tree-cache.c b/src/tree-cache.c
index 97ffc2a..1d39971 100644
--- a/src/tree-cache.c
+++ b/src/tree-cache.c
@@ -138,9 +138,11 @@ static int read_tree_internal(git_tree_cache **out,
 		tree->children = git__malloc(tree->children_count * sizeof(git_tree_cache *));
 		GITERR_CHECK_ALLOC(tree->children);
 
+		memset(tree->children, 0x0, tree->children_count * sizeof(git_tree_cache *));
+
 		for (i = 0; i < tree->children_count; ++i) {
 			if (read_tree_internal(&tree->children[i], &buffer, buffer_end, tree) < 0)
-				return -1;
+				goto corrupted;
 		}
 	}
 
@@ -150,7 +152,7 @@ static int read_tree_internal(git_tree_cache **out,
 
  corrupted:
 	git_tree_cache_free(tree);
-	giterr_set(GITERR_INDEX, "Corruped TREE extension in index");
+	giterr_set(GITERR_INDEX, "Corrupted TREE extension in index");
 	return -1;
 }
 
@@ -162,7 +164,7 @@ int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer
 		return -1;
 
 	if (buffer < buffer_end) {
-		giterr_set(GITERR_INDEX, "Corruped TREE extension in index (unexpected trailing data)");
+		giterr_set(GITERR_INDEX, "Corrupted TREE extension in index (unexpected trailing data)");
 		return -1;
 	}
 
@@ -176,9 +178,12 @@ void git_tree_cache_free(git_tree_cache *tree)
 	if (tree == NULL)
 		return;
 
-	for (i = 0; i < tree->children_count; ++i)
-		git_tree_cache_free(tree->children[i]);
+	if (tree->children != NULL) {
+		for (i = 0; i < tree->children_count; ++i)
+			git_tree_cache_free(tree->children[i]);
+
+		git__free(tree->children);
+	}
 
-	git__free(tree->children);
 	git__free(tree);
 }
diff --git a/tests/index/tests.c b/tests/index/tests.c
index e520298..217e1bb 100644
--- a/tests/index/tests.c
+++ b/tests/index/tests.c
@@ -6,6 +6,7 @@ static const size_t index_entry_count_2 = 1437;
 #define TEST_INDEX_PATH cl_fixture("testrepo.git/index")
 #define TEST_INDEX2_PATH cl_fixture("gitgit.index")
 #define TEST_INDEXBIG_PATH cl_fixture("big.index")
+#define TEST_INDEXBAD_PATH cl_fixture("bad.index")
 
 
 /* Suite data */
@@ -535,3 +536,11 @@ void test_index_tests__reload_from_disk(void)
 	git_index_free(write_index);
 	git_repository_free(repo);
 }
+
+void test_index_tests__corrupted_extension(void)
+{
+	/* sort the entires in an empty index */
+	git_index *index;
+
+	cl_git_fail_with(git_index_open(&index, TEST_INDEXBAD_PATH), GIT_ERROR);
+}
diff --git a/tests/resources/bad.index b/tests/resources/bad.index
new file mode 100644
index 0000000..5374654
Binary files /dev/null and b/tests/resources/bad.index differ