|
Boost : |
From: Steve Nutt (steve.nutt_at_[hidden])
Date: 2006-11-13 15:39:47
I've encountered a bug in the spirit library's numeric parsing. Deep in
boost::spirit::impl is a template extract_int_base which uses the two
templates positive_accumulate and negative_accumulate.
When a new digit is parsed, it is accumulated to the current value by
multiplying the current value by the radix and adding the new digit.
Overflow is detected at each stage by comparing the new and old values.
The overflow logic is flawed. It assumes that when the number overflows
it becomes a smaller number, which is only true if the radix is a power
of 2. It also requires that the arithmetic operation does
over/underflow.
My proposed fix detects overflow before it happens, fixing the parsing
of large base 10 numbers, and allowing for non overflowing numeric
types. The changes are only to the three classes mentioned.
Steve Nutt
Changed file:
include/spirit/core/primitives/impl/numerics.ipp
template <int Radix>
struct positive_accumulate
{
// Use this accumulator if number is positive
template <typename T, typename CharT>
static bool add(T& n, CharT ch)
{
// Ensure n *= Radix will not overflow
static const T val = std::numeric_limits<T>::max() / Radix;
if (n > val)
return false;
n *= Radix;
// Ensure n += digit will not overflow
const int digit = radix_traits<Radix>::digit(ch);
if (n > std::numeric_limits<T>::max() - digit)
return false;
n += digit;
return true;
}
};
template <int Radix>
struct negative_accumulate
{
// Use this accumulator if number is negative
template <typename T>
static T min()
{
if (std::numeric_limits<T>::is_integer)
return
std::numeric_limits<T>::min();
return -std::numeric_limits<T>::max();
}
template <typename T, typename CharT>
static bool add(T& n, CharT ch)
{
// Ensure n *= Radix will not underflow
static const T val = min<T>() / Radix;
if (n < val)
return false;
n *= Radix;
// Ensure n -= digit will not underflow
const int digit =
radix_traits<Radix>::digit(ch);
if (n < min<T>() + digit)
return false;
n -= digit;
return true;
}
};
template <int Radix, typename Accumulate>
struct extract_int_base
{
// Common code for extract_int specializations
template <typename ScannerT, typename T>
static bool
f(ScannerT& scan, T& n)
{
return Accumulate::add(n, *scan);
}
};
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk