[libcxx-commits] [libcxx] ca0612c - [libc++] Fix `money_get::do_get` with huge input (#126273)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Mar 2 15:13:42 PST 2025
Author: A. Jiang
Date: 2025-03-03T07:13:38+08:00
New Revision: ca0612c383bc1c487b8dabff9e5830af173a7da8
URL: https://github.com/llvm/llvm-project/commit/ca0612c383bc1c487b8dabff9e5830af173a7da8
DIFF: https://github.com/llvm/llvm-project/commit/ca0612c383bc1c487b8dabff9e5830af173a7da8.diff
LOG: [libc++] Fix `money_get::do_get` with huge input (#126273)
`money_get::do_get` needs to be fixed to handle extremely huge input
(e.g. more than 100 digits).
1. `__double_or_nothing` needs to copy the contents of the stack buffer
on the initial allocation.
2. The `sscanf` call in `do_get` needs to scan the dynamic buffer if
dynamic allocation happens.
Added:
libcxx/test/std/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_overlong.pass.cpp
Modified:
libcxx/include/locale
Removed:
################################################################################
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<char, void (*)(void*)> __h(nullptr, free);
if (__wn - __wb.get() > __bz - 2) {
__h.reset((char*)malloc(static_cast<size_t>(__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
+//
+//===----------------------------------------------------------------------===//
+
+// <locale>
+
+// class money_get<charT, InputIterator>
+
+// 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 <cassert>
+#include <cstddef>
+#include <ios>
+#include <locale>
+#include <streambuf>
+#include <string>
+
+#include "make_string.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+
+template <class CharT>
+class my_basic_facet : public std::money_get<CharT, cpp17_input_iterator<const CharT*> > {
+private:
+ typedef std::money_get<CharT, cpp17_input_iterator<const CharT*> > Base;
+
+public:
+ explicit my_basic_facet(std::size_t refs = 0) : Base(refs) {}
+};
+
+template <class CharT>
+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<CharT> f(1);
+ for (std::size_t i = 0; i != sizeof(digit_result_cases) / sizeof(digit_result_cases[0]); ++i) {
+ {
+ std::basic_string<CharT> v = MAKE_STRING(CharT, "2");
+ v.append(digit_result_cases[i].digit, static_cast<CharT>('0'));
+
+ typedef cpp17_input_iterator<const CharT*> 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<CharT> v = MAKE_STRING(CharT, "-2");
+ v.append(digit_result_cases[i].digit, static_cast<CharT>('0'));
+
+ typedef cpp17_input_iterator<const CharT*> 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<CharT> v = MAKE_STRING(CharT, "0.");
+ v.append(digit_result_cases[i].digit, static_cast<CharT>('0'));
+ v += MAKE_CSTRING(CharT, "2");
+
+ typedef cpp17_input_iterator<const CharT*> 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<CharT> v = MAKE_STRING(CharT, "-0.");
+ v.append(digit_result_cases[i].digit, static_cast<CharT>('0'));
+ v += MAKE_CSTRING(CharT, "2");
+
+ typedef cpp17_input_iterator<const CharT*> 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<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>();
+#endif
+
+ return 0;
+}
More information about the libcxx-commits
mailing list