Allow read_tree_internal to return an error code There are two reasons why read_tree_internal might return a NULL tree. The first one is a corrupt index, but the second one is an invalidated TREE extension. Up to now, its only way to communicate with its caller was through the return value being NULL or not. Allow read_tree_internal to report its exit status independently from the tree pointer. Signed-off-by: Carlos Martín Nieto <cmn@elego.de>
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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
diff --git a/src/index.c b/src/index.c
index c1edd15..0da2e18 100644
--- a/src/index.c
+++ b/src/index.c
@@ -99,7 +99,7 @@ static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffe
static int read_header(struct index_header *dest, const void *buffer);
static int read_tree(git_index *index, const char *buffer, size_t buffer_size);
-static git_index_tree *read_tree_internal(const char **, const char *, git_index_tree *);
+static int read_tree_internal(git_index_tree **, const char **, const char *, git_index_tree *);
static int parse_index(git_index *index, const char *buffer, size_t buffer_size);
static int is_index_extended(git_index *index);
@@ -485,52 +485,72 @@ const git_index_entry_unmerged *git_index_get_unmerged(git_index *index, const c
}
-static git_index_tree *read_tree_internal(
+static int read_tree_internal(git_index_tree **out,
const char **buffer_in, const char *buffer_end, git_index_tree *parent)
{
git_index_tree *tree;
const char *name_start, *buffer;
long count;
+ int error = GIT_SUCCESS;
if ((tree = git__malloc(sizeof(git_index_tree))) == NULL)
- return NULL;
+ return GIT_ENOMEM;
memset(tree, 0x0, sizeof(git_index_tree));
tree->parent = parent;
buffer = name_start = *buffer_in;
- if ((buffer = memchr(buffer, '\0', buffer_end - buffer)) == NULL)
- goto error_cleanup;
+ if ((buffer = memchr(buffer, '\0', buffer_end - buffer)) == NULL) {
+ error = GIT_EOBJCORRUPTED;
+ goto exit;
+ }
/* NUL-terminated tree name */
tree->name = git__strdup(name_start);
- if (++buffer >= buffer_end)
- goto error_cleanup;
+ if (tree->name == NULL) {
+ error = GIT_ENOMEM;
+ goto exit;
+ }
+
+ if (++buffer >= buffer_end) {
+ error = GIT_EOBJCORRUPTED;
+ goto exit;
+ }
/* Blank-terminated ASCII decimal number of entries in this tree */
if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS ||
- count < 0)
- goto error_cleanup;
+ count < 0) {
+ error = GIT_EOBJCORRUPTED;
+ goto exit;
+ }
tree->entries = (size_t)count;
- if (*buffer != ' ' || ++buffer >= buffer_end)
- goto error_cleanup;
+ if (*buffer != ' ' || ++buffer >= buffer_end) {
+ error = GIT_EOBJCORRUPTED;
+ goto exit;
+ }
/* Number of children of the tree, newline-terminated */
if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS ||
- count < 0)
- goto error_cleanup;
+ count < 0) {
+ error = GIT_EOBJCORRUPTED;
+ goto exit;
+ }
tree->children_count = (size_t)count;
- if (*buffer != '\n' || ++buffer >= buffer_end)
- goto error_cleanup;
+ if (*buffer != '\n' || ++buffer >= buffer_end) {
+ error = GIT_EOBJCORRUPTED;
+ goto exit;
+ }
/* 160-bit SHA-1 for this tree and it's children */
- if (buffer + GIT_OID_RAWSZ > buffer_end)
- goto error_cleanup;
+ if (buffer + GIT_OID_RAWSZ > buffer_end) {
+ error = GIT_EOBJCORRUPTED;
+ goto exit;
+ }
git_oid_mkraw(&tree->oid, (const unsigned char *)buffer);
buffer += GIT_OID_RAWSZ;
@@ -538,33 +558,38 @@ static git_index_tree *read_tree_internal(
/* Parse children: */
if (tree->children_count > 0) {
unsigned int i;
+ int err;
tree->children = git__malloc(tree->children_count * sizeof(git_index_tree *));
if (tree->children == NULL)
- goto error_cleanup;
+ goto exit;
for (i = 0; i < tree->children_count; ++i) {
- tree->children[i] = read_tree_internal(&buffer, buffer_end, tree);
+ err = read_tree_internal(&tree->children[i], &buffer, buffer_end, tree);
- if (tree->children[i] == NULL)
- goto error_cleanup;
+ if (err < GIT_SUCCESS)
+ goto exit;
}
}
+ exit:
*buffer_in = buffer;
- return tree;
-
-error_cleanup:
- free_tree(tree);
- return NULL;
+ if (error < GIT_SUCCESS) {
+ free_tree(tree);
+ } else {
+ *out = tree;
+ }
+ return error;
}
static int read_tree(git_index *index, const char *buffer, size_t buffer_size)
{
const char *buffer_end = buffer + buffer_size;
+ int error;
+
+ error = read_tree_internal(&index->tree, &buffer, buffer_end, NULL);
- index->tree = read_tree_internal(&buffer, buffer_end, NULL);
- return (index->tree != NULL && buffer == buffer_end) ? GIT_SUCCESS : GIT_EOBJCORRUPTED;
+ return (error == GIT_SUCCESS && buffer == buffer_end) ? GIT_SUCCESS : GIT_EOBJCORRUPTED;
}
static int read_unmerged(git_index *index, const char *buffer, size_t size)