Subject: [Boost-bugs] [Boost C++ Libraries] #6193: lexical_cast overflow processing does not always work correctly
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2011-12-01 22:51:42
#6193: lexical_cast overflow processing does not always work correctly
------------------------------------------------------+---------------------
Reporter: David W. Birdsall <dave.birdsall@â¦> | Owner: nasonov
Type: Bugs | Status: new
Milestone: To Be Determined | Component: lexical_cast
Version: Boost 1.47.0 | Severity: Regression
Keywords: lexical_cast overflow |
------------------------------------------------------+---------------------
In the attached program, supplying a really long non-zero number with lots
of trailing zeros is not detected as an invalid number; instead no
exception is thrown and a value of zero is returned for the parameter.
Here are some sample executions of the attached program. The first three
executions behave correctly (note the third throws the expected
exception); the fourth execution manifests the bug:
/home/birdsall>./temp.exe --number 16
The value this code thinks was supplied for --number was: 16
/home/birdsall>./temp.exe --number 1600000
The value this code thinks was supplied for --number was: 1600000
/home/birdsall>./temp.exe --number 160000000000
ERROR: in option 'number': invalid option value
Allowed options:
--help produce this help message
--number arg (=0) a number parameter
/home/birdsall>./temp.exe --number
1600000000000000000000000000000000000000
The value this code thinks was supplied for --number was: 0
/home/birdsall>
I found this bug in Boost 1.47.0, and the code snippets below assume that
version. However, I checked the code in 1.48.0, and in the latest
repository, and the bug exists there as well.
The bug does not exist in Boost 1.43.0; the code there functions
correctly.
The bug seems to be in lexical_cast.hpp. In the 1.47.0 version, starting
at line 702, is the following code:
while ( begin <= end )
{
T const new_sub_value = multiplier * 10 * (*end - czero);
if (*end < czero || *end >= czero + 10
/* detecting overflow */
|| new_sub_value/10 != multiplier * (*end - czero)
||
static_cast<T>((std::numeric_limits<T>::max)()-new_sub_value) < value
)
return false;
value += new_sub_value;
multiplier *= 10;
--end;
}
The problem is, there is no check for overflow after the statement,
"multiplier *= 10". If this statement is executed enough times, and
overflows enough times, multiplier gets a value of zero. This defeats the
overflow checking code earlier in the loop; once multiplier becomes zero,
new_sub_value will be zero no matter what digit *end is. Therefore, value
remains zero, new_sub_value/10 remains zero and multiplier * anything
remains zero.
I fixed the bug in my own copy in the following way. I don't claim that
this is the most elegant or efficient fix.
bool multiplier_overflow = false;
while ( begin <= end )
{
T const new_sub_value = multiplier * 10 * (*end - czero);
if (*end < czero || *end >= czero + 10
/* detecting overflow */
|| new_sub_value/10 != multiplier * (*end - czero)
||
static_cast<T>((std::numeric_limits<T>::max)()-new_sub_value) < value
|| (multiplier_overflow && (value != 0))
)
return false;
value += new_sub_value;
T previous_multiplier = multiplier;
multiplier *= 10;
// If we let multiplier =* 10 happen enough times (e.g., because
// of a long string of trailing zeroes), it will overflow
multiple
// times and eventually happen to overflow to zero, defeating the
// overflow checks above. The check below prevents multiplier
// from becoming zero.
if (multiplier/10 != previous_multiplier)
{
multiplier_overflow = true; // remember that multiplier
overflowed
multiplier = 10;
}
--end;
}
A similar copy of the bug occurs earlier in the function, at lines 659
through 674.
-- Ticket URL: <https://svn.boost.org/trac/boost/ticket/6193> Boost C++ Libraries <http://www.boost.org/> Boost provides free peer-reviewed portable C++ source libraries.
This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:07 UTC