id,summary,reporter,owner,description,type,status,milestone,component,version,severity,resolution,keywords,cc
6193,lexical_cast overflow processing does not always work correctly,David W. Birdsall ,nasonov,"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((std::numeric_limits::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((std::numeric_limits::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.",Bugs,closed,To Be Determined,lexical_cast,Boost 1.47.0,Regression,fixed,lexical_cast overflow,dave.birdsall@…