https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68737

--- Comment #21 from Jonathan Wakely <redi at gcc dot gnu.org> ---
This should never fail:

--- a/libstdc++-v3/include/bits/locale_facets.tcc
+++ b/libstdc++-v3/include/bits/locale_facets.tcc
@@ -1000,7 +1000,11 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
        // First try a buffer perhaps big enough (most probably sufficient
        // for non-ios_base::fixed outputs)
        int __cs_size = __max_digits * 3;
-       char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
+       char* __cs;
+
+__retry_convert_from_v:
+
+       __cs = static_cast<char*>(__builtin_alloca(__cs_size));
        if (__use_prec)
          __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
                                        __fbuf, __prec, __v);
@@ -1020,6 +1024,15 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
              __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
                                            __fbuf, __v);
          }
+       else if (__builtin_expect(__len == -1, false))
+         {
+           const bool __fixed = __io.flags() & ios_base::fixed;
+           const int __max_exp =
+             __gnu_cxx::__numeric_traits<_ValueT>::__max_exponent10;
+           __cs_size = __fixed ? __max_exp + __prec + 4
+                               : __max_digits * 2 + __prec;
+           goto __retry_convert_from_v;
+         }
 #else
        // Consider the possibility of long ios_base::fixed outputs
        const bool __fixed = __io.flags() & ios_base::fixed;



Another option is to simply define _GLIBCXX_BROKEN_VSNPRINTF in
config/os/hpux/os_defines.h and then force the use of vsprintf, which is always
called with a large enough buffer:

diff --git a/libstdc++-v3/config/locale/generic/c_locale.h
b/libstdc++-v3/config/locale/generic/c_locale.h
index 0d208166063..3045931c840 100644
--- a/libstdc++-v3/config/locale/generic/c_locale.h
+++ b/libstdc++-v3/config/locale/generic/c_locale.h
@@ -70,7 +70,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __builtin_va_list __args;
     __builtin_va_start(__args, __fmt);

-#if _GLIBCXX_USE_C99_STDIO
+#if _GLIBCXX_USE_C99_STDIO && !_GLIBCXX_HAVE_BROKEN_VSNPRINTF
     const int __ret = __builtin_vsnprintf(__out, __size, __fmt, __args);
 #else
     const int __ret = __builtin_vsprintf(__out, __fmt, __args);
diff --git a/libstdc++-v3/config/os/hpux/os_defines.h
b/libstdc++-v3/config/os/hpux/os_defines.h
index 1003477fe35..5a9c4faf75d 100644
--- a/libstdc++-v3/config/os/hpux/os_defines.h
+++ b/libstdc++-v3/config/os/hpux/os_defines.h
@@ -109,4 +109,9 @@ typedef long int __padding_type;
 #if defined (__hppa__)
 #define _GLIBCXX_HAVE_BROKEN_STRTOLD 1
 #endif
+
+// The vnsprintf function returns -1 when the buffer is too small.
+// See PR libstdc++/68737.
+#define _GLIBCXX_HAVE_BROKEN_VSNPRINTF 1
+
 #endif
diff --git a/libstdc++-v3/include/bits/locale_facets.tcc
b/libstdc++-v3/include/bits/locale_facets.tcc
index 39da5766075..d5fa91e97d6 100644
--- a/libstdc++-v3/include/bits/locale_facets.tcc
+++ b/libstdc++-v3/include/bits/locale_facets.tcc
@@ -992,7 +992,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
        char __fbuf[16];
        __num_base::_S_format_float(__io, __fbuf, __mod);

-#if _GLIBCXX_USE_C99_STDIO
+#if _GLIBCXX_USE_C99_STDIO && !_GLIBCXX_HAVE_BROKEN_VSNPRINTF
        // Precision is always used except for hexfloat format.
        const bool __use_prec =
          (__io.flags() & ios_base::floatfield) != ios_base::floatfield;

Reply via email to