summaryrefslogtreecommitdiffstats
path: root/Utilities/cmlibarchive
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2013-11-25 16:16:45 (GMT)
committerBrad King <brad.king@kitware.com>2013-12-09 17:55:21 (GMT)
commit61b39af353c401e1c188ab33c23ee06698f4fc30 (patch)
tree961bde47dab00239158ca1ea50ee7a43ee5cafd7 /Utilities/cmlibarchive
parent5ee1297d6be6ffc946ac4b7947bfd60443583afc (diff)
downloadCMake-61b39af353c401e1c188ab33c23ee06698f4fc30.zip
CMake-61b39af353c401e1c188ab33c23ee06698f4fc30.tar.gz
CMake-61b39af353c401e1c188ab33c23ee06698f4fc30.tar.bz2
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>
Diffstat (limited to 'Utilities/cmlibarchive')
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c68
1 files changed, 48 insertions, 20 deletions
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
index a4dc710..bb9d533 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
@@ -2412,9 +2412,10 @@ tar_atol(const char *p, size_t char_cnt)
static int64_t
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;
+ maxval = INT64_MAX;
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;
p++;
char_cnt--;
+
+ maxval = INT64_MIN;
+ limit = -(INT64_MIN / base);
+ last_digit_limit = INT64_MIN % base;
}
l = 0;
@@ -2438,8 +2443,7 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base)
digit = *p - '0';
while (digit >= 0 && digit < base && char_cnt != 0) {
if (l>limit || (l == limit && digit > last_digit_limit)) {
- l = INT64_MAX; /* Truncate on overflow. */
- break;
+ return maxval; /* Truncate on overflow. */
}
l = (l * base) + digit;
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
- * value in big-endian order, except that the high-order bit is
- * ignored.
+ * Parse a base-256 integer. This is just a variable-length
+ * twos-complement signed binary value in big-endian order, except
+ * 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
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;
+ unsigned char c, neg;
+
+ /* Extend 7-bit 2s-comp to 8-bit 2s-comp, decide sign. */
+ c = *p;
+ if (c & 0x40) {
+ neg = 0xff;
+ c |= 0x80;
+ l = ~0ULL;
+ } else {
+ neg = 0;
+ c &= 0x7f;
+ l = 0;
+ }
- upper_limit = INT64_MAX / 256;
- lower_limit = INT64_MIN / 256;
+ /* 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;
+ }
- /* Sign-extend the 7-bit value to 64 bits. */
- if ((0x40 & *p) == 0x40)
- l = ~((int64_t)0x3f) | *p++;
- else
- l = 0x3f & *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) {
- if (l > upper_limit)
- return (INT64_MAX); /* Truncate on overflow */
- else if (l < lower_limit)
- return (INT64_MIN);
- l = (l << 8) | (0xff & (int64_t)*p++);
+ l = (l << 8) | c;
+ c = *++p;
}
- return (l);
+ l = (l << 8) | c;
+ /* Return signed twos-complement value. */
+ return (int64_t)(l);
}
/*