Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid fallback routine buffer overruns #46

Merged
merged 8 commits into from
May 22, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 39 additions & 6 deletions include/boost/charconv/from_chars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <boost/charconv/config.hpp>
#include <boost/charconv/chars_format.hpp>
#include <system_error>
#include <cstdlib>
#include <cmath>

namespace boost { namespace charconv {
Expand Down Expand Up @@ -94,35 +95,36 @@ BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, co
namespace detail {

template <typename T>
from_chars_result from_chars_strtod(const char* first, const char* last, T& value) noexcept
from_chars_result from_chars_strtod_impl(const char* first, const char* last, T& value, char* buffer) noexcept
{
// For strto(f/d)
// Floating point value corresponding to the contents of str on success.
// If the converted value falls out of range of corresponding return type, range error occurs and HUGE_VAL, HUGE_VALF or HUGE_VALL is returned.
// If no conversion can be performed, 0 is returned and *str_end is set to str.

value = 0;
std::memcpy(buffer, first, static_cast<std::size_t>(last - first));
mborland marked this conversation as resolved.
Show resolved Hide resolved

char* str_end;
T return_value {};
BOOST_IF_CONSTEXPR (std::is_same<T, float>::value)
{
return_value = std::strtof(first, &str_end);
return_value = std::strtof(buffer, &str_end);
if (return_value == HUGE_VALF)
{
return {last, std::errc::result_out_of_range};
}
}
else BOOST_IF_CONSTEXPR (std::is_same<T, double>::value)
{
return_value = std::strtod(first, &str_end);
return_value = std::strtod(buffer, &str_end);
if (return_value == HUGE_VAL)
{
return {last, std::errc::result_out_of_range};
}
}
else
{
return_value = std::strtold(first, &str_end);
return_value = std::strtold(buffer, &str_end);
if (return_value == HUGE_VALL)
{
return {last, std::errc::result_out_of_range};
Expand All @@ -136,7 +138,31 @@ from_chars_result from_chars_strtod(const char* first, const char* last, T& valu
}

value = return_value;
return {str_end, std::errc()};
return {first + (str_end - buffer), std::errc()};
}

template <typename T>
inline from_chars_result from_chars_strtod(const char* first, const char* last, T& value) noexcept
{
if (last - first < 1024)
{
char buffer[1024] {};
mborland marked this conversation as resolved.
Show resolved Hide resolved
return from_chars_strtod_impl(first, last, value, buffer);
}

// If the string to be parsed does not fit into the 1024 byte static buffer than we have to allocate a buffer.
// malloc is used here because it does not throw on allocation failure.

char* buffer = static_cast<char*>(std::malloc(last - first + 1));
mborland marked this conversation as resolved.
Show resolved Hide resolved
if (buffer == nullptr)
{
return {first, std::errc::not_enough_memory};
}

auto r = from_chars_strtod_impl(first, last, value, buffer);
std::free(buffer);

return r;
}

template <typename T>
Expand All @@ -156,6 +182,13 @@ from_chars_result from_chars_float_impl(const char* first, const char* last, T&
value = sign ? static_cast<T>(-0.0L) : static_cast<T>(0.0L);
return r;
}
else if (exponent == -1)
{
// A full length significand e.g. -1985444280612224 with a power of -1 sometimes
// fails in compute_float64 but is trivial to calculate
// Found investigating GitHub issue #47
value = (sign ? -static_cast<T>(significand) : static_cast<T>(significand)) / 10;
}

bool success {};
T return_val {};
Expand Down
Loading