Commit c4b5bedc972d9238db5d6422bc6f4de35b4b67ed

Vicent Marti 2010-10-07T00:07:32

Fix possible segfaults in src/tree.c (issue 1) git_tree_entry_byname was dereferencing a NULL pointer when the searched file couldn't be found on the tree. New test cases have been added to check for entry access methods. Signed-off-by: Vicent Marti <tanoku@gmail.com>

diff --git a/src/tree.c b/src/tree.c
index 43a5042..b809290 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -124,26 +124,36 @@ unsigned int git_tree_entry_attributes(git_tree_entry *entry)
 
 const char *git_tree_entry_name(git_tree_entry *entry)
 {
+	assert(entry);
 	return entry->filename;
 }
 
 const git_oid *git_tree_entry_id(git_tree_entry *entry)
 {
+	assert(entry);
 	return &entry->oid;
 }
 
 git_object *git_tree_entry_2object(git_tree_entry *entry)
 {
+	assert(entry);
 	return git_repository_lookup(entry->owner->object.repo, &entry->oid, GIT_OBJ_ANY);
 }
 
 git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
 {
-	return *(git_tree_entry **)bsearch(filename, tree->entries, tree->entry_count, sizeof(git_tree_entry *), entry_cmp);
+	git_tree_entry **found;
+
+	assert(tree && filename);
+
+	found = bsearch(filename, tree->entries, tree->entry_count, sizeof(git_tree_entry *), entry_cmp);
+	return found ? *found : NULL;
 }
 
 git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx)
 {
+	assert(tree);
+
 	if (tree->entries == NULL)
 		return NULL;
 
@@ -152,6 +162,7 @@ git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx)
 
 size_t git_tree_entrycount(git_tree *tree)
 {
+	assert(tree);
 	return tree->entry_count;
 }
 
@@ -159,6 +170,8 @@ void git_tree_add_entry(git_tree *tree, const git_oid *id, const char *filename,
 {
 	git_tree_entry *entry;
 
+	assert(tree && id && filename);
+
 	if (tree->entry_count >= tree->array_size)
 		resize_tree_array(tree);
 
@@ -182,6 +195,8 @@ int git_tree_remove_entry_byindex(git_tree *tree, int idx)
 {
 	git_tree_entry *remove_ptr;
 
+	assert(tree);
+
 	if (idx < 0 || idx >= (int)tree->entry_count)
 		return GIT_ENOTFOUND;
 
@@ -200,6 +215,8 @@ int git_tree_remove_entry_byname(git_tree *tree, const char *filename)
 	git_tree_entry **entry_ptr;
 	int idx;
 
+	assert(tree && filename);
+
 	entry_ptr = bsearch(filename, tree->entries, tree->entry_count, sizeof(git_tree_entry *), entry_cmp);
 	if (entry_ptr == NULL)
 		return GIT_ENOTFOUND;
@@ -212,6 +229,8 @@ int git_tree__writeback(git_tree *tree, git_odb_source *src)
 {
 	size_t i;
 
+	assert(tree && src);
+
 	if (tree->entries == NULL)
 		return GIT_ERROR;
 
diff --git a/tests/t0901-readtree.c b/tests/t0901-readtree.c
index c28ad23..eba6ecf 100644
--- a/tests/t0901-readtree.c
+++ b/tests/t0901-readtree.c
@@ -9,6 +9,34 @@
 static const char *odb_dir = "../resources/sample-odb";
 static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd";
 
+BEGIN_TEST(tree_entry_access_test)
+	git_odb *db;
+	git_oid id;
+	git_repository *repo;
+	git_tree *tree;
+
+	must_pass(git_odb_open(&db, odb_dir));
+
+	repo = git_repository_alloc(db);
+	must_be_true(repo != NULL);
+
+	git_oid_mkstr(&id, tree_oid);
+
+	tree = git_tree_lookup(repo, &id);
+	must_be_true(tree != NULL);
+
+	must_be_true(git_tree_entry_byname(tree, "README") != NULL);
+	must_be_true(git_tree_entry_byname(tree, "NOTEXISTS") == NULL);
+	must_be_true(git_tree_entry_byname(tree, "") == NULL);
+	must_be_true(git_tree_entry_byindex(tree, 0) != NULL);
+	must_be_true(git_tree_entry_byindex(tree, 2) != NULL);
+	must_be_true(git_tree_entry_byindex(tree, 3) == NULL);
+	must_be_true(git_tree_entry_byindex(tree, -1) == NULL);
+
+	git_repository_free(repo);
+	git_odb_close(db);
+END_TEST
+
 BEGIN_TEST(tree_read_test)
 	git_odb *db;
 	git_oid id;
@@ -26,8 +54,6 @@ BEGIN_TEST(tree_read_test)
 	tree = git_tree_lookup(repo, &id);
 	must_be_true(tree != NULL);
 
-	must_pass(git_tree__parse(tree));
-
 	must_be_true(git_tree_entrycount(tree) == 3);
 
 	entry = git_tree_entry_byname(tree, "README");