mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-08 22:08:56 +00:00
Properly check strtol
for errors
We are now using a custom `strtol` implementation to make sure we're not missing any overflow errors.
This commit is contained in:
parent
b918ae40d1
commit
c6e65acae6
@ -164,6 +164,12 @@
|
||||
/** A reference with this name already exists */
|
||||
#define GIT_EEXISTS (GIT_ERROR - 23)
|
||||
|
||||
/** The given integer literal is too large to be parsed */
|
||||
#define GIT_EOVERFLOW (GIT_ERROR - 24)
|
||||
|
||||
/** The given literal is not a valid number */
|
||||
#define GIT_ENOTNUM (GIT_ERROR - 25)
|
||||
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
typedef struct {
|
||||
|
@ -29,7 +29,9 @@ static struct {
|
||||
{GIT_EREVWALKOVER, "The revision walker is empty; there are no more commits left to iterate"},
|
||||
{GIT_EINVALIDREFSTATE, "The state of the reference is not valid"},
|
||||
{GIT_ENOTIMPLEMENTED, "This feature has not been implemented yet"},
|
||||
{GIT_EEXISTS, "A reference with this name already exists"}
|
||||
{GIT_EEXISTS, "A reference with this name already exists"},
|
||||
{GIT_EOVERFLOW, "The given integer literal is too large to be parsed"},
|
||||
{GIT_ENOTNUM, "The given literal is not a valid number"},
|
||||
};
|
||||
|
||||
const char *git_strerror(int num)
|
||||
|
15
src/index.c
15
src/index.c
@ -411,6 +411,7 @@ static git_index_tree *read_tree_internal(
|
||||
{
|
||||
git_index_tree *tree;
|
||||
const char *name_start, *buffer;
|
||||
long count;
|
||||
|
||||
if ((tree = git__malloc(sizeof(git_index_tree))) == NULL)
|
||||
return NULL;
|
||||
@ -429,12 +430,22 @@ static git_index_tree *read_tree_internal(
|
||||
goto error_cleanup;
|
||||
|
||||
/* Blank-terminated ASCII decimal number of entries in this tree */
|
||||
tree->entries = strtol(buffer, (char **)&buffer, 10);
|
||||
if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS ||
|
||||
count < 0)
|
||||
goto error_cleanup;
|
||||
|
||||
tree->entries = (size_t)count;
|
||||
|
||||
if (*buffer != ' ' || ++buffer >= buffer_end)
|
||||
goto error_cleanup;
|
||||
|
||||
/* Number of children of the tree, newline-terminated */
|
||||
tree->children_count = strtol(buffer, (char **)&buffer, 10);
|
||||
if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS ||
|
||||
count < 0)
|
||||
goto error_cleanup;
|
||||
|
||||
tree->children_count = (size_t)count;
|
||||
|
||||
if (*buffer != '\n' || ++buffer >= buffer_end)
|
||||
goto error_cleanup;
|
||||
|
||||
|
@ -191,6 +191,7 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo
|
||||
unsigned char *parents_start;
|
||||
|
||||
int i, parents = 0;
|
||||
long commit_time;
|
||||
|
||||
buffer += STRLEN("tree ") + GIT_OID_HEXSZ + 1;
|
||||
|
||||
@ -227,10 +228,10 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo
|
||||
if (buffer == NULL)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
commit->time = strtol((char *)buffer + 2, NULL, 10);
|
||||
if (commit->time == 0)
|
||||
if (git__strtol32(&commit_time, (char *)buffer + 2, NULL, 10) < GIT_SUCCESS)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
commit->time = (time_t)commit_time;
|
||||
commit->parsed = 1;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
@ -66,13 +66,13 @@ git_signature *git_signature_dup(const git_signature *sig)
|
||||
}
|
||||
|
||||
|
||||
static int parse_timezone_offset(const char *buffer, int *offset_out)
|
||||
static int parse_timezone_offset(const char *buffer, long *offset_out)
|
||||
{
|
||||
int offset, dec_offset;
|
||||
long offset, dec_offset;
|
||||
int mins, hours;
|
||||
|
||||
const char *offset_start;
|
||||
char* offset_end;
|
||||
const char *offset_end;
|
||||
|
||||
offset_start = buffer + 1;
|
||||
|
||||
@ -84,7 +84,8 @@ static int parse_timezone_offset(const char *buffer, int *offset_out)
|
||||
if (offset_start[0] != '-' && offset_start[0] != '+')
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
dec_offset = strtol(offset_start + 1, &offset_end, 10);
|
||||
if (git__strtol32(&dec_offset, offset_start + 1, &offset_end, 10) < GIT_SUCCESS)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
if (offset_end - offset_start != 5)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
@ -117,7 +118,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
|
||||
int name_length, email_length;
|
||||
const char *buffer = *buffer_out;
|
||||
const char *line_end, *name_end, *email_end;
|
||||
int offset = 0;
|
||||
long offset = 0, time;
|
||||
|
||||
memset(sig, 0x0, sizeof(git_signature));
|
||||
|
||||
@ -159,11 +160,11 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
|
||||
if (buffer >= line_end)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
sig->when.time = strtol(buffer, (char **)&buffer, 10);
|
||||
|
||||
if (sig->when.time == 0)
|
||||
if (git__strtol32(&time, buffer, &buffer, 10) < GIT_SUCCESS)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
sig->when.time = (time_t)time;
|
||||
|
||||
if (parse_timezone_offset(buffer, &offset) < GIT_SUCCESS)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
|
@ -150,7 +150,8 @@ static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buf
|
||||
if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
entry->attr = strtol(buffer, (char **)&buffer, 8);
|
||||
if (git__strtol32((long *)&entry->attr, buffer, &buffer, 8) < GIT_SUCCESS)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
if (*buffer++ != ' ') {
|
||||
error = GIT_EOBJCORRUPTED;
|
||||
|
79
src/util.c
79
src/util.c
@ -2,6 +2,7 @@
|
||||
#include "common.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
void git_strarray_free(git_strarray *array)
|
||||
{
|
||||
@ -12,6 +13,84 @@ void git_strarray_free(git_strarray *array)
|
||||
free(array->strings);
|
||||
}
|
||||
|
||||
int git__strtol32(long *result, const char *nptr, const char **endptr, int base)
|
||||
{
|
||||
const char *p;
|
||||
long n, nn;
|
||||
int c, ovfl, v, neg, ndig;
|
||||
|
||||
p = nptr;
|
||||
neg = 0;
|
||||
n = 0;
|
||||
ndig = 0;
|
||||
ovfl = 0;
|
||||
|
||||
/*
|
||||
* White space
|
||||
*/
|
||||
while (isspace(*p))
|
||||
p++;
|
||||
|
||||
/*
|
||||
* Sign
|
||||
*/
|
||||
if (*p == '-' || *p == '+')
|
||||
if (*p++ == '-')
|
||||
neg = 1;
|
||||
|
||||
/*
|
||||
* Base
|
||||
*/
|
||||
if (base == 0) {
|
||||
if (*p != '0')
|
||||
base = 10;
|
||||
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)
|
||||
goto Return;
|
||||
|
||||
/*
|
||||
* Non-empty sequence of digits
|
||||
*/
|
||||
for (;; p++,ndig++) {
|
||||
c = *p;
|
||||
v = base;
|
||||
if ('0'<=c && c<='9')
|
||||
v = c - '0';
|
||||
else if ('a'<=c && c<='z')
|
||||
v = c - 'a' + 10;
|
||||
else if ('A'<=c && c<='Z')
|
||||
v = c - 'A' + 10;
|
||||
if (v >= base)
|
||||
break;
|
||||
nn = n*base + v;
|
||||
if (nn < n)
|
||||
ovfl = 1;
|
||||
n = nn;
|
||||
}
|
||||
|
||||
Return:
|
||||
if (ndig == 0)
|
||||
return GIT_ENOTNUM;
|
||||
|
||||
if (endptr)
|
||||
*endptr = p;
|
||||
|
||||
if (ovfl)
|
||||
return GIT_EOVERFLOW;
|
||||
|
||||
*result = neg ? -n : n;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git__fmt(char *buf, size_t buf_sz, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
@ -22,6 +22,8 @@ extern int git__fmt(char *, size_t, const char *, ...)
|
||||
extern int git__prefixcmp(const char *str, const char *prefix);
|
||||
extern int git__suffixcmp(const char *str, const char *suffix);
|
||||
|
||||
extern int git__strtol32(long *n, const char *buff, const char **end_buf, int base);
|
||||
|
||||
/*
|
||||
* The dirname() function shall take a pointer to a character string
|
||||
* that contains a pathname, and return a pointer to a string that is a
|
||||
|
Loading…
Reference in New Issue
Block a user