diff --git a/archive-tar.c b/archive-tar.c index a1c66024d4dff4..2da6e554842b8b 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -210,6 +210,8 @@ static size_t get_path_prefix(const char *path, size_t pathlen, size_t maxlen) i--; if (i > maxlen) i = maxlen; + if (!i) + return 0; do { i--; } while (i > 0 && path[i] != '/'); diff --git a/date.c b/date.c index 014065b419aee7..0d65804d2f939b 100644 --- a/date.c +++ b/date.c @@ -1298,7 +1298,18 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm while (tl->type) { size_t len = strlen(tl->type); if (match_string(date, tl->type) >= len-1) { - update_tm(tm, now, tl->length * *num); + time_t length = tl->length, num_t = *num; + time_t seconds; +#ifndef is_unsigned_type + seconds = length * num_t; +#else + time_t max_val = is_unsigned_type(length) + ? maximum_unsigned_value_of_type(length) + : maximum_signed_value_of_type(length); + seconds = mult_overflows(length, num_t) + ? max_val : length * num_t; +#endif + update_tm(tm, now, seconds); *num = 0; *touched = 1; return end; @@ -1368,8 +1379,15 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num, } /* Accept zero-padding only for small numbers ("Dec 02", never "Dec 0002") */ - if (date[0] != '0' || end - date <= 2) + if (date[0] != '0' || end - date <= 2) { +#ifdef is_unsigned_type + if (is_unsigned_type((time_t)0) && + (number > INT_MAX || + number > maximum_unsigned_value_of_type((time_t)0))) + return NULL; +#endif *num = number; + } return end; } @@ -1398,6 +1416,10 @@ static timestamp_t approxidate_str(const char *date, if (isdigit(c)) { pending_number(&tm, &number); date = approxidate_digit(date-1, &tm, &number, time_sec); + if (!date) { + *error_ret = 1; + return 0; + } touched = 1; continue; } diff --git a/git-compat-util.h b/git-compat-util.h index a0f901ce793ed6..077fa948733d9c 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -85,9 +85,27 @@ struct strbuf; #define bitsizeof(x) (CHAR_BIT * sizeof(x)) +#if GIT_GNUC_PREREQ(3, 1) +#define is_unsigned_type(a) ((__typeof__(a))-1 >= 0) +#elif __STDC_VERSION__ >= 201112L +#define is_unsigned_type(a) _Generic((a), \ + unsigned char: 1, \ + unsigned short: 1, \ + unsigned int: 1, \ + unsigned long: 1, \ + unsigned long long: 1, \ + _Bool: 1, \ + char: (CHAR_MIN == 0), \ + default: 0) +#endif + #define maximum_signed_value_of_type(a) \ (INTMAX_MAX >> (bitsizeof(intmax_t) - bitsizeof(a))) +/* Account for the extra negative value on two's-complement targets. */ +#define minimum_signed_value_of_type(a) \ + (-maximum_signed_value_of_type(a) - (INTMAX_MIN < -INTMAX_MAX)) + #define maximum_unsigned_value_of_type(a) \ (UINTMAX_MAX >> (bitsizeof(uintmax_t) - bitsizeof(a))) @@ -111,6 +129,38 @@ struct strbuf; #define unsigned_mult_overflows(a, b) \ ((a) && (b) > maximum_unsigned_value_of_type(a) / (a)) +/* + * Returns true if the multiplication of "a" and "b" will + * overflow or underflow a signed type. The types of "a" and "b" + * must match and must be signed. Note that this macro evaluates + * both "a" and "b" twice! + */ +#define signed_mult_overflows(a, b) \ + (((a) > 0 && (b) > 0 && (a) > maximum_signed_value_of_type(a) / (b)) || \ + ((a) < 0 && (b) < 0 && (a) < maximum_signed_value_of_type(a) / (b)) || \ + ((a) > 0 && (b) < 0 && (b) < minimum_signed_value_of_type(a) / (a)) || \ + ((a) < 0 && (b) > 0 && (a) < minimum_signed_value_of_type(b) / (b))) + +/* + * Returns true if the product of "a" and "b", after the usual arithmetic + * conversions, cannot be represented in the multiplication expression's + * type. The operands must be integers and may be evaluated more than once. + */ +#if GIT_GNUC_PREREQ(3, 1) +#define mult_overflows(a, b) \ + (is_unsigned_type((a) * (b)) \ + ? unsigned_mult_overflows((__typeof__((a) * (b)))(a), \ + (__typeof__((a) * (b)))(b)) \ + : signed_mult_overflows((__typeof__((a) * (b)))(a), \ + (__typeof__((a) * (b)))(b))) +#else +/* + * This implementation needs GNU `typeof` to convert both operands to the + * multiplication's type. Skip the check without that extension. + */ +#define mult_overflows(a, b) 0 +#endif + /* * Returns true if the left shift of "a" by "shift" bits will * overflow. The type of "a" must be unsigned. @@ -740,6 +790,10 @@ static inline uint64_t u64_add(uint64_t a, uint64_t b) */ #define DEFAULT_IO_BUFFER_SIZE (128 * 1024) +#ifndef SSIZE_MAX +# define SSIZE_MAX ((ssize_t)(((size_t)-1) >> 1)) +#endif + #ifdef HAVE_ALLOCA_H # include # define xalloca(size) (alloca(size)) diff --git a/http.c b/http.c index 4af3c29c769559..809471f436b7ba 100644 --- a/http.c +++ b/http.c @@ -2848,7 +2848,7 @@ static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb, { unsigned char expn[4096]; size_t size = eltsize * nmemb; - int posn = 0; + size_t posn = 0; struct http_object_request *freq = data; struct active_request_slot *slot = freq->slot; diff --git a/wrapper.c b/wrapper.c index 05a9cd369c5971..ea9c14f834f793 100644 --- a/wrapper.c +++ b/wrapper.c @@ -288,6 +288,11 @@ ssize_t read_in_full(int fd, void *buf, size_t count) char *p = buf; ssize_t total = 0; + if (count > SSIZE_MAX) { + errno = EINVAL; + return -1; + } + while (count > 0) { ssize_t loaded = xread(fd, p, count); if (loaded < 0) @@ -307,6 +312,11 @@ ssize_t write_in_full(int fd, const void *buf, size_t count) const char *p = buf; ssize_t total = 0; + if (count > SSIZE_MAX) { + errno = EINVAL; + return -1; + } + while (count > 0) { ssize_t written = xwrite(fd, p, count); if (written < 0)