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;