Boost C++ Libraries: Ticket #6193: lexical_cast overflow processing does not always work correctly https://svn.boost.org/trac10/ticket/6193 <p> 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. </p> <p> 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: </p> <p> /home/birdsall&gt;./temp.exe --number 16 The value this code thinks was supplied for --number was: 16 /home/birdsall&gt;./temp.exe --number 1600000 The value this code thinks was supplied for --number was: 1600000 /home/birdsall&gt;./temp.exe --number 160000000000 ERROR: in option 'number': invalid option value Allowed options: </p> <blockquote> <p> --help produce this help message --number arg (=0) a number parameter </p> </blockquote> <p> /home/birdsall&gt;./temp.exe --number 1600000000000000000000000000000000000000 The value this code thinks was supplied for --number was: 0 /home/birdsall&gt; </p> <p> 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. </p> <p> The bug does not exist in Boost 1.43.0; the code there functions correctly. </p> <p> The bug seems to be in lexical_cast.hpp. In the 1.47.0 version, starting at line 702, is the following code: </p> <blockquote> <p> while ( begin &lt;= end ) </p> <blockquote> <p> { T const new_sub_value = multiplier * 10 * (*end - czero); </p> </blockquote> </blockquote> <blockquote> <blockquote> <table class="wiki"> <tr>if (*end &lt; czero <td> *end &gt;= czero + 10 </td></tr></table> <blockquote> <p> /* detecting overflow */ </p> <table class="wiki"> <tr><td> new_sub_value/10 != multiplier * (*end - czero) </td></tr><tr><td> static_cast&lt;T&gt;((std::numeric_limits&lt;T&gt;::max)()-new_sub_value) &lt; value </td></tr></table> <blockquote> <p> ) </p> </blockquote> <p> return false; </p> </blockquote> </blockquote> </blockquote> <blockquote> <blockquote> <blockquote> <p> value += new_sub_value; multiplier *= 10; --end; } </p> </blockquote> </blockquote> </blockquote> <p> 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. </p> <p> 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. </p> <blockquote> <p> bool multiplier_overflow = false; </p> </blockquote> <blockquote> <p> while ( begin &lt;= end ) { </p> <blockquote> <p> T const new_sub_value = multiplier * 10 * (*end - czero); </p> </blockquote> </blockquote> <blockquote> <blockquote> <table class="wiki"> <tr>if (*end &lt; czero <td> *end &gt;= czero + 10 </td></tr></table> <blockquote> <p> /* detecting overflow */ </p> <table class="wiki"> <tr><td> new_sub_value/10 != multiplier * (*end - czero) </td></tr><tr><td> static_cast&lt;T&gt;((std::numeric_limits&lt;T&gt;::max)()-new_sub_value) &lt; value </td></tr><tr><td> (multiplier_overflow &amp;&amp; (value != 0)) </td></tr></table> <p> ) </p> </blockquote> <p> return false; </p> </blockquote> </blockquote> <blockquote> <blockquote> <p> value += new_sub_value; T previous_multiplier = multiplier; multiplier *= 10; <em> If we let multiplier =* 10 happen enough times (e.g., because </em> of a long string of trailing zeroes), it will overflow multiple <em> times and eventually happen to overflow to zero, defeating the </em> overflow checks above. The check below prevents multiplier <em> from becoming zero. if (multiplier/10 != previous_multiplier) { </em></p> <blockquote> <p> multiplier_overflow = true; <em> remember that multiplier overflowed multiplier = 10; </em></p> </blockquote> <p> } --end; </p> </blockquote> <p> } </p> </blockquote> <p> A similar copy of the bug occurs earlier in the function, at lines 659 through 674. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/6193 Trac 1.4.3 David W. Birdsall <dave.birdsall@…> Thu, 01 Dec 2011 22:52:53 GMT attachment set https://svn.boost.org/trac10/ticket/6193 https://svn.boost.org/trac10/ticket/6193 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">temp.cpp</span> </li> </ul> <p> Sample program that demonstrates the defect </p> Ticket Antony Polukhin Thu, 05 Jan 2012 12:09:18 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/6193#comment:1 https://svn.boost.org/trac10/ticket/6193#comment:1 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> (In <a class="changeset" href="https://svn.boost.org/trac10/changeset/76318" title="Fixes #6193">[76318]</a>) Fixes <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/6193" title="#6193: Bugs: lexical_cast overflow processing does not always work correctly (closed: fixed)">#6193</a> </p> Ticket