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>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
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");