Improved overflow detection; removed debugging output statements.
This commit is contained in:
parent
6b78b5c2be
commit
4eafaab816
2 changed files with 48 additions and 46 deletions
47
src/json.hpp
47
src/json.hpp
|
@ -9223,14 +9223,6 @@ basic_json_parser_66:
|
||||||
value = -0.0;
|
value = -0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ok) {
|
|
||||||
std::cerr << "data:" << data
|
|
||||||
<< " token:" << std::string(m_start, len)
|
|
||||||
<< " value:" << value
|
|
||||||
<< " len:" << len
|
|
||||||
<< " parsed_len:" << (endptr - data) << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9252,31 +9244,40 @@ basic_json_parser_66:
|
||||||
++beg; // skip the leading sign
|
++beg; // skip the leading sign
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// using unsigned accumulator x because the signed
|
||||||
|
// type can't hold absolute value of largest
|
||||||
|
// negative value of this type, so overflow detection
|
||||||
|
// becomes problematic.
|
||||||
|
using unsigned_T = typename std::make_unsigned<T>::type;
|
||||||
|
unsigned_T x = 0;
|
||||||
|
|
||||||
bool valid = beg < end // must have some digits;
|
bool valid = beg < end // must have some digits;
|
||||||
and ( T(-1) < 0 // type must be signed
|
and ( T(-1) < 0 // type must be signed
|
||||||
or !is_negative); // if value is negative
|
or !is_negative); // if value is negative
|
||||||
value = 0;
|
|
||||||
|
|
||||||
while(beg < end and valid) {
|
while(beg < end and valid) {
|
||||||
const uint8_t c = static_cast<uint8_t>(*beg - '0');
|
const uint8_t c = static_cast<uint8_t>(*beg - '0');
|
||||||
const T upd_value = value * 10 + c;
|
const unsigned_T upd_x = x * 10 + c;
|
||||||
valid &= value <= std::numeric_limits<T>::max() / 10
|
|
||||||
and value <= upd_value // did not overflow
|
using lim_T = std::numeric_limits<T>;
|
||||||
and c < 10; // char was digit
|
constexpr unsigned_T thr1 = lim_T::max() / 10;
|
||||||
value = upd_value;
|
valid &= c < 10 // char was digit
|
||||||
|
and x <= thr1 // multiplication did not overflow
|
||||||
|
and x <= upd_x; // addition did not overflow.
|
||||||
|
|
||||||
|
// note that x <= upd_x alone can't detect overflow since
|
||||||
|
// we're not just adding a value of decltype(x) but
|
||||||
|
// also multiplying by 10
|
||||||
|
|
||||||
|
x = upd_x;
|
||||||
++beg;
|
++beg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_negative) {
|
value = static_cast<T>(is_negative ? 0 - x : x);
|
||||||
value = 0 - value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!valid) {
|
// the final check to make sure the value did not roll over
|
||||||
std::cerr << " token:" << std::string(m_start, m_end)
|
// into positives is for edge cases, e.g. -2^63
|
||||||
<< std::endl;
|
return valid && (is_negative == (value < 0));
|
||||||
}
|
|
||||||
|
|
||||||
return valid;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8372,14 +8372,6 @@ class basic_json
|
||||||
value = -0.0;
|
value = -0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ok) {
|
|
||||||
std::cerr << "data:" << data
|
|
||||||
<< " token:" << std::string(m_start, len)
|
|
||||||
<< " value:" << value
|
|
||||||
<< " len:" << len
|
|
||||||
<< " parsed_len:" << (endptr - data) << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8401,31 +8393,40 @@ class basic_json
|
||||||
++beg; // skip the leading sign
|
++beg; // skip the leading sign
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// using unsigned accumulator x because the signed
|
||||||
|
// type can't hold absolute value of largest
|
||||||
|
// negative value of this type, so overflow detection
|
||||||
|
// becomes problematic.
|
||||||
|
using unsigned_T = typename std::make_unsigned<T>::type;
|
||||||
|
unsigned_T x = 0;
|
||||||
|
|
||||||
bool valid = beg < end // must have some digits;
|
bool valid = beg < end // must have some digits;
|
||||||
and ( T(-1) < 0 // type must be signed
|
and ( T(-1) < 0 // type must be signed
|
||||||
or !is_negative); // if value is negative
|
or !is_negative); // if value is negative
|
||||||
value = 0;
|
|
||||||
|
|
||||||
while(beg < end and valid) {
|
while(beg < end and valid) {
|
||||||
const uint8_t c = static_cast<uint8_t>(*beg - '0');
|
const uint8_t c = static_cast<uint8_t>(*beg - '0');
|
||||||
const T upd_value = value * 10 + c;
|
const unsigned_T upd_x = x * 10 + c;
|
||||||
valid &= value <= std::numeric_limits<T>::max() / 10
|
|
||||||
and value <= upd_value // did not overflow
|
using lim_T = std::numeric_limits<T>;
|
||||||
and c < 10; // char was digit
|
constexpr unsigned_T thr1 = lim_T::max() / 10;
|
||||||
value = upd_value;
|
valid &= c < 10 // char was digit
|
||||||
|
and x <= thr1 // multiplication did not overflow
|
||||||
|
and x <= upd_x; // addition did not overflow.
|
||||||
|
|
||||||
|
// note that x <= upd_x alone can't detect overflow since
|
||||||
|
// we're not just adding a value of decltype(x) but
|
||||||
|
// also multiplying by 10
|
||||||
|
|
||||||
|
x = upd_x;
|
||||||
++beg;
|
++beg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_negative) {
|
value = static_cast<T>(is_negative ? 0 - x : x);
|
||||||
value = 0 - value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!valid) {
|
// the final check to make sure the value did not roll over
|
||||||
std::cerr << " token:" << std::string(m_start, m_end)
|
// into positives is for edge cases, e.g. -2^63
|
||||||
<< std::endl;
|
return valid && (is_negative == (value < 0));
|
||||||
}
|
|
||||||
|
|
||||||
return valid;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue