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;
>

Reply via email to