libarchive: Port upstream issue 320 second fix

Port upstream commit 6cf33c93 (Issue 320: Rewrite (again) to avoid
the left shift that CLang dislikes so much, 2013-12-07) into CMake.

Inspired-by: Tim Kientzle <kientzle@freebsd.org>
This commit is contained in:
Brad King 2013-11-25 11:16:45 -05:00
parent 5ee1297d6b
commit 61b39af353
1 changed files with 50 additions and 22 deletions

View File

@ -2412,9 +2412,10 @@ tar_atol(const char *p, size_t char_cnt)
static int64_t static int64_t
tar_atol_base_n(const char *p, size_t char_cnt, int base) tar_atol_base_n(const char *p, size_t char_cnt, int base)
{ {
int64_t l, limit, last_digit_limit; int64_t l, maxval, limit, last_digit_limit;
int digit, sign; int digit, sign;
maxval = INT64_MAX;
limit = INT64_MAX / base; limit = INT64_MAX / base;
last_digit_limit = INT64_MAX % base; last_digit_limit = INT64_MAX % base;
@ -2431,6 +2432,10 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base)
sign = -1; sign = -1;
p++; p++;
char_cnt--; char_cnt--;
maxval = INT64_MIN;
limit = -(INT64_MIN / base);
last_digit_limit = INT64_MIN % base;
} }
l = 0; l = 0;
@ -2438,8 +2443,7 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base)
digit = *p - '0'; digit = *p - '0';
while (digit >= 0 && digit < base && char_cnt != 0) { while (digit >= 0 && digit < base && char_cnt != 0) {
if (l>limit || (l == limit && digit > last_digit_limit)) { if (l>limit || (l == limit && digit > last_digit_limit)) {
l = INT64_MAX; /* Truncate on overflow. */ return maxval; /* Truncate on overflow. */
break;
} }
l = (l * base) + digit; l = (l * base) + digit;
digit = *++p - '0'; digit = *++p - '0';
@ -2462,32 +2466,56 @@ tar_atol10(const char *p, size_t char_cnt)
} }
/* /*
* Parse a base-256 integer. This is just a straight signed binary * Parse a base-256 integer. This is just a variable-length
* value in big-endian order, except that the high-order bit is * twos-complement signed binary value in big-endian order, except
* ignored. * that the high-order bit is ignored. The values here can be up to
* 12 bytes, so we need to be careful about overflowing 64-bit
* (8-byte) integers.
*
* This code unashamedly assumes that the local machine uses 8-bit
* bytes and twos-complement arithmetic.
*/ */
static int64_t static int64_t
tar_atol256(const char *_p, size_t char_cnt) tar_atol256(const char *_p, size_t char_cnt)
{ {
int64_t l, upper_limit, lower_limit; uint64_t l;
const unsigned char *p = (const unsigned char *)_p; const unsigned char *p = (const unsigned char *)_p;
unsigned char c, neg;
upper_limit = INT64_MAX / 256; /* Extend 7-bit 2s-comp to 8-bit 2s-comp, decide sign. */
lower_limit = INT64_MIN / 256; c = *p;
if (c & 0x40) {
/* Sign-extend the 7-bit value to 64 bits. */ neg = 0xff;
if ((0x40 & *p) == 0x40) c |= 0x80;
l = ~((int64_t)0x3f) | *p++; l = ~0ULL;
else } else {
l = 0x3f & *p++; neg = 0;
while (--char_cnt > 0) { c &= 0x7f;
if (l > upper_limit) l = 0;
return (INT64_MAX); /* Truncate on overflow */
else if (l < lower_limit)
return (INT64_MIN);
l = (l << 8) | (0xff & (int64_t)*p++);
} }
return (l);
/* If more than 8 bytes, check that we can ignore
* high-order bits without overflow. */
while (char_cnt > sizeof(int64_t)) {
--char_cnt;
if (c != neg)
return neg ? INT64_MIN : INT64_MAX;
c = *++p;
}
/* c is first byte that fits; if sign mismatch, return overflow */
if ((c ^ neg) & 0x80) {
return neg ? INT64_MIN : INT64_MAX;
}
/* Accumulate remaining bytes. */
while (--char_cnt > 0) {
l = (l << 8) | c;
c = *++p;
}
l = (l << 8) | c;
/* Return signed twos-complement value. */
return (int64_t)(l);
} }
/* /*