diff options
| author | Patrick Steinhardt <ps@pks.im> | 2018-11-07 12:23:14 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-11-07 12:23:14 +0100 |
| commit | fa7aba70d8c1bc68cd2572d808c66059df6da989 (patch) | |
| tree | 5dca2f4c35fabf0e43844a58d5792f8254153639 /src | |
| parent | b5ae83bfac53fa3a17435ebf2fc3b79db8055dae (diff) | |
| parent | 7fafec0e53f8711b73912d46b43451c599aeceb3 (diff) | |
| download | libgit2-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.c | 29 | ||||
| -rw-r--r-- | src/util.c | 40 |
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--) { |
