diff --git a/libcxx/include/locale b/libcxx/include/locale index 4f2716fa53d62..fa11ce3943b65 100644 --- a/libcxx/include/locale +++ b/libcxx/include/locale @@ -2386,6 +2386,8 @@ _LIBCPP_HIDE_FROM_ABI void __double_or_nothing(unique_ptr<_Tp, void (*)(void*)>& std::__throw_bad_alloc(); if (__owns) __b.release(); + else + std::memcpy(__t, __b.get(), __cur_cap); __b = unique_ptr<_Tp, void (*)(void*)>(__t, free); __new_cap /= sizeof(_Tp); __n = __b.get() + __n_off; @@ -2581,20 +2583,22 @@ _InputIterator money_get<_CharT, _InputIterator>::do_get( char_type __atoms[sizeof(__src) - 1]; __ct.widen(__src, __src + (sizeof(__src) - 1), __atoms); char __nbuf[__bz]; - char* __nc = __nbuf; + char* __nc = __nbuf; + const char* __nc_in = __nc; unique_ptr __h(nullptr, free); if (__wn - __wb.get() > __bz - 2) { __h.reset((char*)malloc(static_cast(__wn - __wb.get() + 2))); if (__h.get() == nullptr) std::__throw_bad_alloc(); - __nc = __h.get(); + __nc = __h.get(); + __nc_in = __nc; } if (__neg) *__nc++ = '-'; for (const char_type* __w = __wb.get(); __w < __wn; ++__w, ++__nc) *__nc = __src[std::find(__atoms, std::end(__atoms), *__w) - __atoms]; *__nc = char(); - if (sscanf(__nbuf, "%Lf", &__v) != 1) + if (sscanf(__nc_in, "%Lf", &__v) != 1) std::__throw_runtime_error("money_get error"); } if (__b == __e) diff --git a/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_overlong.pass.cpp b/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_overlong.pass.cpp new file mode 100644 index 0000000000000..8fe74cdaca5e4 --- /dev/null +++ b/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_overlong.pass.cpp @@ -0,0 +1,115 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// class money_get + +// iter_type get(iter_type b, iter_type e, bool intl, ios_base& iob, +// ios_base::iostate& err, long double& v) const; + +// Ensure that money_get::do_get correct works when the input doesn't fit into the stack buffer +// (100 characters currently). + +// XFAIL: FROZEN-CXX03-HEADERS-FIXME + +#include +#include +#include +#include +#include +#include + +#include "make_string.h" +#include "test_macros.h" +#include "test_iterators.h" + +template +class my_basic_facet : public std::money_get > { +private: + typedef std::money_get > Base; + +public: + explicit my_basic_facet(std::size_t refs = 0) : Base(refs) {} +}; + +template +void test() { + struct digit_result_case { + std::size_t digit; + long double result; + }; + const digit_result_case digit_result_cases[] = { + {60, 2.0E60L}, {120, 2.0E120L}, {180, 2.0E180L}, {240, 2.0E240L}, {300, 2.0E300L}}; + + std::ios ios(0); + { + const my_basic_facet f(1); + for (std::size_t i = 0; i != sizeof(digit_result_cases) / sizeof(digit_result_cases[0]); ++i) { + { + std::basic_string v = MAKE_STRING(CharT, "2"); + v.append(digit_result_cases[i].digit, static_cast('0')); + + typedef cpp17_input_iterator I; + long double ex; + std::ios_base::iostate err = std::ios_base::goodbit; + I iter = f.get(I(v.data()), I(v.data() + v.size()), false, ios, err, ex); + assert(base(iter) == v.data() + v.size()); + assert(err == std::ios_base::eofbit); + assert(ex == digit_result_cases[i].result); + } + { + std::basic_string v = MAKE_STRING(CharT, "-2"); + v.append(digit_result_cases[i].digit, static_cast('0')); + + typedef cpp17_input_iterator I; + long double ex; + std::ios_base::iostate err = std::ios_base::goodbit; + I iter = f.get(I(v.data()), I(v.data() + v.size()), false, ios, err, ex); + assert(base(iter) == v.data() + v.size()); + assert(err == std::ios_base::eofbit); + assert(ex == -digit_result_cases[i].result); + } + { + std::basic_string v = MAKE_STRING(CharT, "0."); + v.append(digit_result_cases[i].digit, static_cast('0')); + v += MAKE_CSTRING(CharT, "2"); + + typedef cpp17_input_iterator I; + long double ex; + std::ios_base::iostate err = std::ios_base::goodbit; + I iter = f.get(I(v.data()), I(v.data() + v.size()), false, ios, err, ex); + assert(base(iter) == v.data() + 1); + assert(err == std::ios_base::goodbit); + assert(ex == 0.0L); + } + { + std::basic_string v = MAKE_STRING(CharT, "-0."); + v.append(digit_result_cases[i].digit, static_cast('0')); + v += MAKE_CSTRING(CharT, "2"); + + typedef cpp17_input_iterator I; + long double ex; + std::ios_base::iostate err = std::ios_base::goodbit; + I iter = f.get(I(v.data()), I(v.data() + v.size()), false, ios, err, ex); + assert(base(iter) == v.data() + 2); + assert(err == std::ios_base::goodbit); + assert(ex == 0.0L); + } + } + } +} + +int main(int, char**) { + test(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif + + return 0; +}