Skip to content

Commit

Permalink
Merge pull request #242 from Flamefire/zeroes
Browse files Browse the repository at this point in the history
Fix uninitialized values when parsing zeroes
  • Loading branch information
mborland authored Jan 2, 2025
2 parents 9846df1 + 685d4b1 commit ffd3e71
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 1 deletion.
24 changes: 23 additions & 1 deletion include/boost/charconv/detail/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,24 @@ inline from_chars_result from_chars_dispatch(const char* first, const char* last
}
#endif

template<typename Unsigned_Integer>
typename std::enable_if<std::is_unsigned<Unsigned_Integer>::value &&
std::numeric_limits<Unsigned_Integer>::is_integer &&
sizeof(Unsigned_Integer) < sizeof(std::uint64_t),
from_chars_result>::type
from_chars_dispatch(const char* first, const char* last, Unsigned_Integer& value, int base) noexcept
{
std::uint64_t tmp_value;
auto result = boost::charconv::detail::from_chars(first, last, tmp_value, base);
if (result) {
if (tmp_value > (std::numeric_limits<Unsigned_Integer>::max)())
result.ec = std::errc::result_out_of_range;
else
value = static_cast<Unsigned_Integer>(tmp_value);
}
return result;
}

template <typename Unsigned_Integer, typename Integer>
inline from_chars_result parser(const char* first, const char* last, bool& sign, Unsigned_Integer& significand, Integer& exponent, chars_format fmt = chars_format::general) noexcept
{
Expand Down Expand Up @@ -234,6 +252,8 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,

if (next == last)
{
significand = 0;
exponent = 0;
return {last, std::errc()};
}
}
Expand Down Expand Up @@ -344,9 +364,11 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,

if (round)
{
significand += 1;
significand = static_cast<Unsigned_Integer>(significand + 1u);
}
}
else
significand = 0;
}
else
{
Expand Down
40 changes: 40 additions & 0 deletions test/test_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,22 @@ void test_integer()
BOOST_TEST_EQ(exponent, 0);
BOOST_TEST_EQ(significand, max_sig_v);
}

// Small significant type
std::uint8_t significand_8{};
exponent = 0;
sign = false;

const char* val3 = "255";
auto r5 = boost::charconv::detail::parser(val3, val3 + std::strlen(val3), sign, significand_8, exponent);
BOOST_TEST(r5);
BOOST_TEST_EQ(sign, false);
BOOST_TEST_EQ(exponent, 0);
BOOST_TEST_EQ(significand_8, 255);

const char* val4 = "256";
auto r6 = boost::charconv::detail::parser(val4, val4 + std::strlen(val4), sign, significand_8, exponent);
BOOST_TEST(r6.ec == std::errc::result_out_of_range);
}

template <typename T>
Expand Down Expand Up @@ -195,6 +211,29 @@ void test_hex_scientific()
BOOST_TEST_EQ(significand, UINT64_C(80427));
}

void test_zeroes()
{
for (const char* val : {
"0", "00", "000", "0000",
"0.", "00.", "000.", "0000.",
"0.0", "00.0", "000.0", "0000.0",
"0e0", "00e0", "000e0", "0000e0",
"0.e0", "00.e0", "000.e0", "0000.e0",
"0.0e0", "00.0e0", "000.0e0", "0000.0e0",
}) {
// Use small integer type to reduce input test string lengths
std::uint8_t significand = 1;
std::int64_t exponent = 1;
bool sign = (std::strlen(val) % 2) == 0; // Different initial values

auto r1 = boost::charconv::detail::parser(val, val + std::strlen(val), sign, significand, exponent);
BOOST_TEST(r1);
BOOST_TEST_EQ(sign, false);
BOOST_TEST_EQ(significand, 0u);
BOOST_TEST_EQ(exponent, 0);
}
}

int main()
{
test_integer<float>();
Expand All @@ -213,5 +252,6 @@ int main()
test_hex_scientific<double>();
test_hex_scientific<long double>();

test_zeroes();
return boost::report_errors();
}

0 comments on commit ffd3e71

Please sign in to comment.