summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2018-11-07 12:23:14 +0100
committerGitHub <noreply@github.com>2018-11-07 12:23:14 +0100
commitfa7aba70d8c1bc68cd2572d808c66059df6da989 (patch)
tree5dca2f4c35fabf0e43844a58d5792f8254153639 /src
parentb5ae83bfac53fa3a17435ebf2fc3b79db8055dae (diff)
parent7fafec0e53f8711b73912d46b43451c599aeceb3 (diff)
downloadlibgit2-fa7aba70d8c1bc68cd2572d808c66059df6da989.tar.gz
Merge pull request #4871 from pks-t/pks/tree-parsing-fixes
Tree parsing fixes
Diffstat (limited to 'src')
-rw-r--r--src/tree.c29
-rw-r--r--src/util.c40
2 files changed, 43 insertions, 26 deletions
diff --git a/src/tree.c b/src/tree.c
index d628aeb64..d9b59390a 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -356,21 +356,21 @@ static int tree_error(const char *str, const char *path)
return -1;
}
-static int parse_mode(unsigned int *modep, const char *buffer, const char **buffer_out)
+static int parse_mode(uint16_t *mode_out, const char *buffer, size_t buffer_len, const char **buffer_out)
{
- unsigned char c;
- unsigned int mode = 0;
+ int32_t mode;
+ int error;
- if (*buffer == ' ')
+ if (!buffer_len || git__isspace(*buffer))
return -1;
- while ((c = *buffer++) != ' ') {
- if (c < '0' || c > '7')
- return -1;
- mode = (mode << 3) + (c - '0');
- }
- *modep = mode;
- *buffer_out = buffer;
+ if ((error = git__strntol32(&mode, buffer, buffer_len, buffer_out, 8)) < 0)
+ return error;
+
+ if (mode < 0 || mode > UINT16_MAX)
+ return -1;
+
+ *mode_out = mode;
return 0;
}
@@ -392,11 +392,14 @@ int git_tree__parse_raw(void *_tree, const char *data, size_t size)
git_tree_entry *entry;
size_t filename_len;
const char *nul;
- unsigned int attr;
+ uint16_t attr;
- if (parse_mode(&attr, buffer, &buffer) < 0 || !buffer)
+ if (parse_mode(&attr, buffer, buffer_end - buffer, &buffer) < 0 || !buffer)
return tree_error("failed to parse tree: can't parse filemode", NULL);
+ if (buffer >= buffer_end || (*buffer++) != ' ')
+ return tree_error("failed to parse tree: missing space after filemode", NULL);
+
if ((nul = memchr(buffer, 0, buffer_end - buffer)) == NULL)
return tree_error("failed to parse tree: object is corrupted", NULL);
diff --git a/src/util.c b/src/util.c
index 52495f752..735f0b547 100644
--- a/src/util.c
+++ b/src/util.c
@@ -83,8 +83,11 @@ int git__strntol64(int64_t *result, const char *nptr, size_t nptr_len, const cha
/*
* White space
*/
- while (git__isspace(*p))
- p++;
+ while (nptr_len && git__isspace(*p))
+ p++, nptr_len--;
+
+ if (!nptr_len)
+ goto Return;
/*
* Sign
@@ -94,25 +97,36 @@ int git__strntol64(int64_t *result, const char *nptr, size_t nptr_len, const cha
neg = 1;
/*
- * Base
+ * Automatically detect the base if none was given to us.
+ * Right now, we assume that a number starting with '0x'
+ * is hexadecimal and a number starting with '0' is
+ * octal.
*/
if (base == 0) {
if (*p != '0')
base = 10;
- else {
+ else if (nptr_len > 2 && (p[1] == 'x' || p[1] == 'X'))
+ base = 16;
+ else
base = 8;
- if (p[1] == 'x' || p[1] == 'X') {
- p += 2;
- base = 16;
- }
- }
- } else if (base == 16 && *p == '0') {
- if (p[1] == 'x' || p[1] == 'X')
- p += 2;
- } else if (base < 0 || 36 < base)
+ }
+
+ if (base < 0 || 36 < base)
goto Return;
/*
+ * Skip prefix of '0x'-prefixed hexadecimal numbers. There is no
+ * need to do the same for '0'-prefixed octal numbers as a
+ * leading '0' does not have any impact. Also, if we skip a
+ * leading '0' in such a string, then we may end up with no
+ * digits left and produce an error later on which isn't one.
+ */
+ if (base == 16 && nptr_len > 2 && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
+ p += 2;
+ nptr_len -= 2;
+ }
+
+ /*
* Non-empty sequence of digits
*/
for (; nptr_len > 0; p++,ndig++,nptr_len--) {