Fix issue 3 (memory corruption resize_tree_array) The tree array wasn't being initialized when instantiating a tree object in memory instead of loading it from disk. New unit tests added to check for the problem. 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 135 136 137
diff --git a/src/git/tree.h b/src/git/tree.h
index bec49f2..9e2d077 100644
--- a/src/git/tree.h
+++ b/src/git/tree.h
@@ -113,8 +113,9 @@ GIT_EXTERN(git_object *) git_tree_entry_2object(git_tree_entry *entry);
* @iparam id OID for the tree entry
* @param filename Filename for the tree entry
* @param attributes UNIX file attributes for the entry
+ * @return 0 on success; otherwise error code
*/
-GIT_EXTERN(void) git_tree_add_entry(git_tree *tree, const git_oid *id, const char *filename, int attributes);
+GIT_EXTERN(int) git_tree_add_entry(git_tree *tree, const git_oid *id, const char *filename, int attributes);
/**
* Remove an entry by its index.
diff --git a/src/tree.c b/src/tree.c
index b809290..28bc035 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -29,17 +29,24 @@
#include "tree.h"
#include "git/repository.h"
-static void resize_tree_array(git_tree *tree)
+static int resize_tree_array(git_tree *tree)
{
git_tree_entry **new_entries;
- tree->array_size = tree->array_size * 2;
+ tree->array_size *= 2;
+ if (tree->array_size == 0)
+ tree->array_size = 8;
new_entries = git__malloc(tree->array_size * sizeof(git_tree_entry *));
+ if (new_entries == NULL)
+ return GIT_ENOMEM;
+
memcpy(new_entries, tree->entries, tree->entry_count * sizeof(git_tree_entry *));
free(tree->entries);
tree->entries = new_entries;
+
+ return GIT_SUCCESS;
}
int entry_cmp(const void *key, const void *array_member)
@@ -166,17 +173,18 @@ size_t git_tree_entrycount(git_tree *tree)
return tree->entry_count;
}
-void git_tree_add_entry(git_tree *tree, const git_oid *id, const char *filename, int attributes)
+int git_tree_add_entry(git_tree *tree, const git_oid *id, const char *filename, int attributes)
{
git_tree_entry *entry;
assert(tree && id && filename);
if (tree->entry_count >= tree->array_size)
- resize_tree_array(tree);
+ if (resize_tree_array(tree) < 0)
+ return GIT_ENOMEM;
if ((entry = git__malloc(sizeof(git_tree_entry))) == NULL)
- return;
+ return GIT_ENOMEM;
memset(entry, 0x0, sizeof(git_tree_entry));
@@ -189,6 +197,7 @@ void git_tree_add_entry(git_tree *tree, const git_oid *id, const char *filename,
entry_resort(tree);
tree->object.modified = 1;
+ return GIT_SUCCESS;
}
int git_tree_remove_entry_byindex(git_tree *tree, int idx)
@@ -277,11 +286,15 @@ int git_tree__parse(git_tree *tree)
tree->array_size = (tree->object.source.raw.len / avg_entry_size) + 1;
tree->entries = git__malloc(tree->array_size * sizeof(git_tree_entry *));
+ if (tree->entries == NULL)
+ return GIT_ENOMEM;
+
while (buffer < buffer_end) {
git_tree_entry *entry;
if (tree->entry_count >= tree->array_size)
- resize_tree_array(tree);
+ if (resize_tree_array(tree) < 0)
+ return GIT_ENOMEM;
entry = git__malloc(sizeof(git_tree_entry));
if (entry == NULL) {
diff --git a/tests/t0902-modify.c b/tests/t0902-modify.c
index a321165..60a5cd7 100644
--- a/tests/t0902-modify.c
+++ b/tests/t0902-modify.c
@@ -9,6 +9,39 @@
static const char *odb_dir = "../resources/sample-odb";
static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd";
+BEGIN_TEST(tree_in_memory_add_test)
+ const unsigned int entry_count = 128;
+
+
+ git_odb *db;
+ git_repository *repo;
+ git_tree *tree;
+ unsigned int i;
+ git_oid entry_id;
+
+ must_pass(git_odb_open(&db, odb_dir));
+
+ repo = git_repository_alloc(db);
+ must_be_true(repo != NULL);
+
+ tree = git_tree_new(repo);
+ must_be_true(tree != NULL);
+
+ git_oid_mkstr(&entry_id, tree_oid);
+ for (i = 0; i < entry_count; ++i) {
+ char filename[32];
+ sprintf(filename, "file%d.txt", i);
+ must_pass(git_tree_add_entry(tree, &entry_id, filename, 040000));
+ }
+
+ must_be_true(git_tree_entrycount(tree) == entry_count);
+ must_pass(git_object_write((git_object *)tree));
+ must_pass(remove_loose_object(odb_dir, (git_object *)tree));
+
+ git_repository_free(repo);
+ git_odb_close(db);
+END_TEST
+
BEGIN_TEST(tree_add_entry_test)
git_odb *db;
git_oid id;