https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68737
--- Comment #22 from dave.anglin at bell dot net --- I prefer the first approach although it might loop if there is an error. Probably, it needs to check if the current __cs_size is less than the new __cs_size before doing a retry. Another option would be to just duplicate the code instead of branching back. It's my understanding that the vsnprintf bug is fixed in 11.31 and some HP-UX patch sets. We win with the first approach when the initial buffer is large enough. It's possible for vsnprintf on linux to return a negative value if an output error occurs. So, there's some justification to check the return on linux. On 2018-09-05 8:07 AM, redi at gcc dot gnu.org wrote: > 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; >