Hello,

This patch fixes bug 4485 and adjusts related test cases
to fully check Parser::Tokenizer::int64() post-conditions.

Regards,
Eduard.
Fixed bug 4485:
off-by-one out-of-bounds Parser::Tokenizer::int64() read errors.
Also adjusted related test cases to fully check Parser::Tokenizer::int64()
post-conditions.

=== modified file 'src/parser/Tokenizer.cc'
--- src/parser/Tokenizer.cc	2016-01-01 00:12:18 +0000
+++ src/parser/Tokenizer.cc	2016-05-21 12:00:33 +0000
@@ -200,85 +200,86 @@
         debugs(24, 8, "no match when trying to skip " << skippable.name);
         return 0;
     }
     debugs(24, 8, "skipping in " << skippable.name << " len " << suffixLen);
     return successTrailing(suffixLen);
 }
 
 /* reworked from compat/strtoll.c */
 bool
 Parser::Tokenizer::int64(int64_t & result, int base, bool allowSign, const SBuf::size_type limit)
 {
     if (atEnd() || limit == 0)
         return false;
 
     const SBuf range(buf_.substr(0,limit));
 
     //fixme: account for buf_.size()
     bool neg = false;
     const char *s = range.rawContent();
     const char *end = range.rawContent() + range.length();
 
     if (allowSign) {
         if (*s == '-') {
             neg = true;
             ++s;
         } else if (*s == '+') {
             ++s;
         }
         if (s >= end) return false;
     }
-    if (( base == 0 || base == 16) && *s == '0' && (s+1 <= end ) &&
+    if (( base == 0 || base == 16) && *s == '0' && (s+1 < end ) &&
             tolower(*(s+1)) == 'x') {
         s += 2;
         base = 16;
     }
     if (base == 0) {
         if ( *s == '0') {
             base = 8;
             ++s;
         } else {
             base = 10;
         }
     }
     if (s >= end) return false;
 
     uint64_t cutoff;
 
     cutoff = neg ? -static_cast<uint64_t>(INT64_MIN) : INT64_MAX;
     const int cutlim = cutoff % static_cast<int64_t>(base);
     cutoff /= static_cast<uint64_t>(base);
 
     int any = 0, c;
     int64_t acc = 0;
-    for (c = *s++; s <= end; c = *s++) {
+    do {
+        c = *s;
         if (xisdigit(c)) {
             c -= '0';
         } else if (xisalpha(c)) {
             c -= xisupper(c) ? 'A' - 10 : 'a' - 10;
         } else {
             break;
         }
         if (c >= base)
             break;
         if (any < 0 || static_cast<uint64_t>(acc) > cutoff || (static_cast<uint64_t>(acc) == cutoff && c > cutlim))
             any = -1;
         else {
             any = 1;
             acc *= base;
             acc += c;
         }
-    }
+    } while (++s < end);
 
     if (any == 0) // nothing was parsed
         return false;
     if (any < 0) {
         acc = neg ? INT64_MIN : INT64_MAX;
         errno = ERANGE;
         return false;
     } else if (neg)
         acc = -acc;
 
     result = acc;
-    return success(s - range.rawContent() - 1);
+    return success(s - range.rawContent());
 }
 

=== modified file 'src/tests/testTokenizer.cc'
--- src/tests/testTokenizer.cc	2016-01-01 00:12:18 +0000
+++ src/tests/testTokenizer.cc	2016-05-21 20:59:43 +0000
@@ -177,134 +177,142 @@
 
     // match until the end of the sample
     CPPUNIT_ASSERT(t.suffix(s, all));
     CPPUNIT_ASSERT_EQUAL(SBuf(), t.remaining());
 
     // an empty buffer does not end with a token
     s = canary;
     CPPUNIT_ASSERT(!t.suffix(s, all));
     CPPUNIT_ASSERT_EQUAL(canary, s); // no parameter changes
 
     // we cannot skip an empty suffix, even in an empty buffer
     CPPUNIT_ASSERT(!t.skipSuffix(SBuf()));
 }
 
 void
 testTokenizer::testCharacterSet()
 {
 
 }
 
 void
 testTokenizer::testTokenizerInt64()
 {
     // successful parse in base 10
     {
         int64_t rv;
         Parser::Tokenizer t(SBuf("1234"));
         const int64_t benchmark = 1234;
         CPPUNIT_ASSERT(t.int64(rv, 10));
         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+        CPPUNIT_ASSERT(t.buf().isEmpty());
     }
 
     // successful parse, autodetect base
     {
         int64_t rv;
         Parser::Tokenizer t(SBuf("1234"));
         const int64_t benchmark = 1234;
         CPPUNIT_ASSERT(t.int64(rv));
         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+        CPPUNIT_ASSERT(t.buf().isEmpty());
     }
 
     // successful parse, autodetect base
     {
         int64_t rv;
         Parser::Tokenizer t(SBuf("01234"));
         const int64_t benchmark = 01234;
         CPPUNIT_ASSERT(t.int64(rv));
         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+        CPPUNIT_ASSERT(t.buf().isEmpty());
     }
 
     // successful parse, autodetect base
     {
         int64_t rv;
         Parser::Tokenizer t(SBuf("0x12f4"));
         const int64_t benchmark = 0x12f4;
         CPPUNIT_ASSERT(t.int64(rv));
         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+        CPPUNIT_ASSERT(t.buf().isEmpty());
     }
 
     // API mismatch: don't eat leading space
     {
         int64_t rv;
         Parser::Tokenizer t(SBuf(" 1234"));
         CPPUNIT_ASSERT(!t.int64(rv));
+        CPPUNIT_ASSERT_EQUAL(SBuf(" 1234"), t.buf());
     }
 
     // API mismatch: don't eat multiple leading spaces
     {
         int64_t rv;
         Parser::Tokenizer t(SBuf("  1234"));
         CPPUNIT_ASSERT(!t.int64(rv));
+        CPPUNIT_ASSERT_EQUAL(SBuf("  1234"), t.buf());
     }
 
     // trailing spaces
     {
         int64_t rv;
         Parser::Tokenizer t(SBuf("1234  foo"));
         const int64_t benchmark = 1234;
         CPPUNIT_ASSERT(t.int64(rv));
         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
         CPPUNIT_ASSERT_EQUAL(SBuf("  foo"), t.buf());
     }
 
     // trailing nonspaces
     {
         int64_t rv;
         Parser::Tokenizer t(SBuf("1234foo"));
         const int64_t benchmark = 1234;
         CPPUNIT_ASSERT(t.int64(rv));
         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
         CPPUNIT_ASSERT_EQUAL(SBuf("foo"), t.buf());
     }
 
     // trailing nonspaces
     {
         int64_t rv;
         Parser::Tokenizer t(SBuf("0x1234foo"));
         const int64_t benchmark = 0x1234f;
         CPPUNIT_ASSERT(t.int64(rv));
         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
         CPPUNIT_ASSERT_EQUAL(SBuf("oo"), t.buf());
     }
 
     // overflow
     {
         int64_t rv;
         Parser::Tokenizer t(SBuf("1029397752385698678762234"));
         CPPUNIT_ASSERT(!t.int64(rv));
+        CPPUNIT_ASSERT_EQUAL(SBuf("1029397752385698678762234"), t.buf());
     }
 
     // buffered sub-string parsing
     {
         int64_t rv;
         SBuf base("1029397752385698678762234");
         const int64_t benchmark = 22;
         Parser::Tokenizer t(base.substr(base.length()-4,2));
         CPPUNIT_ASSERT_EQUAL(SBuf("22"),t.buf());
         CPPUNIT_ASSERT(t.int64(rv));
         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+        CPPUNIT_ASSERT(t.buf().isEmpty());
     }
 
     // base-16, prefix
     {
         int64_t rv;
         SBuf base("deadbeefrow");
         const int64_t benchmark=0xdeadbeef;
         Parser::Tokenizer t(base);
         CPPUNIT_ASSERT(t.int64(rv,16));
         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
         CPPUNIT_ASSERT_EQUAL(SBuf("row"),t.buf());
 
     }
 }
 

_______________________________________________
squid-dev mailing list
squid-dev@lists.squid-cache.org
http://lists.squid-cache.org/listinfo/squid-dev

Reply via email to