Bug 68737 - FAIL: 22_locale/num_put/put/char/14220.cc execution test
Summary: FAIL: 22_locale/num_put/put/char/14220.cc execution test
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 6.0
: P3 normal
Target Milestone: 8.5
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-12-06 18:37 UTC by John David Anglin
Modified: 2020-07-21 15:09 UTC (History)
1 user (show)

See Also:
Host: hppa64-hp-hpux11.11
Target: hppa64-hp-hpux11.11
Build: hppa64-hp-hpux11.11
Known to work:
Known to fail:
Last reconfirmed: 2018-09-03 00:00:00


Attachments
locale_facets.tcc.d (480 bytes, text/plain)
2018-09-04 16:13 UTC, dave.anglin
Details

Note You need to log in before you can comment on or make changes to this bug.
Description John David Anglin 2015-12-06 18:37:22 UTC
Executing on host: /test/gnu/gcc/objdir/./gcc/xg++ -shared-libgcc -B/test/gnu/gc
c/objdir/./gcc -nostdinc++ -L/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-
v3/src -L/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/src/.libs -L/test
/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/libsupc++/.libs -B/opt/gnu64/gcc/gcc-6/hppa64-hp-hpux11.11/bin/ -B/opt/gnu64/gcc/gcc-6/hppa64-hp-hpux11.11/lib/ -isystem /opt/gnu64/gcc/gcc-6/hppa64-hp-hpux11.11/include -isystem /opt/gnu64/gcc/gcc-6/hppa64-hp-hpux11.11/sys-include -B/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/./libstdc++-v3/src/.libs -D_GLIBCXX_ASSERT -fmessage-length=0 -ffunction-sections -fdata-sections -g -O2 -DLOCALEDIR="." -nostdinc++ -I/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/include/hppa64-hp-hpux11.11 -I/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/include -I/test/gnu/gcc/gcc/libstdc++-v3/libsupc++ -I/test/gnu/gcc/gcc/libstdc++-v3/include/backward -I/test/gnu/gcc/gcc/libstdc++-v3/testsuite/util /test/gnu/gcc/gcc/libstdc++-v3/testsuite/22_locale/num_put/put/char/14220.cc    -include bits/stdc++.h -fno-diagnostics-show-caret -fdiagnostics-color=never ./libtestc++.a -L/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/src/filesystem/.libs  -lm   -o ./14220.exe    (timeout = 600)spawn /test/gnu/gcc/objdir/./gcc/xg++ -shared-libgcc -B/test/gnu/gcc/objdir/./gcc -nostdinc++ -L/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/src -L/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/src/.libs -L/test/gnu/gcc/objd
ir/hppa64-hp-hpux11.11/libstdc++-v3/libsupc++/.libs -B/opt/gnu64/gcc/gcc-6/hppa64-hp-hpux11.11/bin/ -B/opt/gnu64/gcc/gcc-6/hppa64-hp-hpux11.11/lib/ -isystem /opt/gnu64/gcc/gcc-6/hppa64-hp-hpux11.11/include -isystem /opt/gnu64/gcc/gcc-6/hppa64-hp-hpux11.11/sys-include -B/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/./libstdc++-v3/src/.libs -D_GLIBCXX_ASSERT -fmessage-length=0 -ffunction-sections -fdata-sections -g -O2 -DLOCALEDIR="." -nostdinc++ -I/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/include/hppa64-hp-hpux11.11 -I/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/include -I/test/gnu/gcc/gcc/libstdc++-v3/libsupc++ -I/test/gnu/gcc/gcc/libstdc++-v3/include/backward -I/test/gnu/gcc/gcc/libstdc++-v3/testsuite/util /test/gnu/gcc/gcc/libstdc++-v3/testsuite/22_locale/num_put/put/char/14220.cc -include bits/stdc++.h -fno-diagnostics-show-caret -fdiagnostics-color=never ./libtestc++.a -L/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/src/filesystem/.libs -lm -o ./14220.exe
PASS: 22_locale/num_put/put/char/14220.cc (test for excess errors)
Setting LD_LIBRARY_PATH to :/test/gnu/gcc/objdir/gcc:/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/./libstdc++-v3/../libgomp/.libs:/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/./libstdc++-v3/src/.libs::/test/gnu/gcc/objdir/gcc:/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/./libstdc++-v3/../libgomp/.libs:/test/gnu/gcc/objdir/hppa64-hp-hpux11.11/./libstdc++-v3/src/.libs
spawn [open ...]
FAIL: 22_locale/num_put/put/char/14220.cc execution test
extra_tool_flags are:
  -include bits/stdc++.h

Similar fails:

FAIL: 22_locale/num_put/put/wchar_t/14220.cc execution test
FAIL: 27_io/basic_ostream/inserters_arithmetic/char/4402.cc execution test
FAIL: 27_io/basic_ostream/inserters_arithmetic/wchar_t/4402.cc execution test
Comment 1 John David Anglin 2016-04-16 16:36:02 UTC
14220.cc fails due stack growth:

-bash-4.3$ ./14220.exe

Pid 28500 received a SIGSEGV for stack growth failure.
Possible causes: insufficient memory or swap space,
or stack size exceeded maxssiz. 
Segmentation fault

-bash-4.3$ ulimit -s 
16384

Increasing requires kernel rebuild...
Comment 2 John David Anglin 2018-09-03 12:52:52 UTC
Still present in gcc 9.
Comment 3 Jonathan Wakely 2018-09-03 14:57:56 UTC
Could this be due to using alloca? The tests should not require a huge stack, so either alloca isn't usable or maybe there's a bug causing an infinite recursion.
Comment 4 dave.anglin 2018-09-03 16:03:18 UTC
On 2018-09-03 10:57 AM, redi at gcc dot gnu.org wrote:
> Could this be due to using alloca? The tests should not require a huge stack,
> so either alloca isn't usable or maybe there's a bug causing an infinite
> recursion.
(gdb) r
Starting program: 
/mnt/gnu/gcc/objdir-test/hppa64-hp-hpux11.11/libstdc++-v3/testsuite/14220.exe
warning: Private mapping of shared library text was not specified
by the executable; setting a breakpoint in a shared library which
is not privately mapped will not work.  See the HP-UX 11i v3 chatr
manpage for methods to privately map shared library text.

Pid 2143 received a SIGSEGV for stack growth failure.
Possible causes: insufficient memory or swap space,
or stack size exceeded maxssiz.

Program received signal SIGSEGV, Segmentation fault.
0xc000000000270de8 in memmove () from /lib/pa20_64/libc.2
(gdb) bt
#0  0xc000000000270de8 in memmove () from /lib/pa20_64/libc.2
#1  0xc0000000005bba38 in std::ctype<char>::do_widen (
     __to=0x800003fffdff0dd0 <crc_table+120> "1.", '0' <repeats 42 times>,
     __hi=0x800003fffdff0d9f <crc_table+71> "",
     __lo=0x800003fffdff0da0 <crc_table+72> "1.", '0' <repeats 42 times>,
     this=<optimized out>)
     at 
/mnt/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/include/bits/locale_facets.h:1107
#2  std::ctype<char>::widen (
     __to=0x800003fffdff0dd0 <crc_table+120> "1.", '0' <repeats 42 times>,
     __hi=0x800003fffdff0d9f <crc_table+71> "",
     __lo=0x800003fffdff0da0 <crc_table+72> "1.", '0' <repeats 42 times>,
     this=<optimized out>)
     at 
/mnt/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/include/bits/locale_facets.h:908
#3  std::num_put<char, std::ostreambuf_iterator<char, 
std::char_traits<char> > >::_M_insert_float<double> 
(this=0x800003fffdfe57a0, __s=..., __io=...,
     __fill=43 '+', __mod=<optimized out>, __v=1)
     at 
/mnt/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/include/bits/locale_facets.tcc:1048
#4  0xc0000000005bbe68 in std::num_put<char, 
std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put 
(this=<optimized out>,
     __s=<error reading variable: Cannot access memory at address 0x10>,
---Type <return> to continue, or q <return> to quit---
     __io=..., __fill=<optimized out>, __v=<optimized out>)
     at 
/mnt/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/include/bits/locale_facets.tcc:1157
#5  0x4000000000003794 in std::num_put<char, 
std::ostreambuf_iterator<char, std::char_traits<char> > >::put (__v=1, 
__fill=43 '+', __io=..., __s=...,
     this=0x800003fffdfe57a0)
     at 
/mnt/gnu/gcc/gcc/libstdc++-v3/testsuite/22_locale/num_put/put/char/14220.cc:38
#6  test01 ()
     at 
/mnt/gnu/gcc/gcc/libstdc++-v3/testsuite/22_locale/num_put/put/char/14220.cc:38
#7  0x4000000000003a74 in main ()
     at 
/mnt/gnu/gcc/gcc/libstdc++-v3/testsuite/22_locale/num_put/put/char/14220.cc:45

On the failing call to memmove, we have the following arguments:

(gdb) p/x $r26
$1 = 0x800003fffdff0dd0
(gdb) p/x $r25
$2 = 0x800003fffdff0da0
(gdb) p/x $r24
$3 = 0xffffffffffffffff

(gdb) frame 1
#1  0x800003fffdfa0a38 in std::ctype<char>::do_widen (
     __to=0x800003fffdff0dd0 <crc_table+120> "\200",
     __hi=0x800003fffdff0d9f <crc_table+71> "",
     __lo=0x800003fffdff0da0 <crc_table+72> "1.", '0' <repeats 42 times>,
     this=<optimized out>)
     at 
/mnt/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/include/bits/locale_facets.h:1107
1107            __builtin_memcpy(__to, __lo, __hi - __lo);
(gdb) p __hi
$4 = 0x800003fffdff0d9f <crc_table+71> ""
(gdb) p __lo
$5 = 0x800003fffdff0da0 <crc_table+72> "1.", '0' <repeats 42 times>
(gdb) p/x __hi - __lo
$6 = 0xffffffffffffffff
Comment 5 dave.anglin 2018-09-03 16:26:29 UTC
On 2018-09-03 12:03 PM, dave.anglin at bell dot net wrote:
> (gdb) p/x __hi - __lo
> $6 = 0xffffffffffffffff
(gdb) frame 3
#3  std::num_put<char, std::ostreambuf_iterator<char, 
std::char_traits<char> > >::_M_insert_float<double> 
(this=0x800003fffdde37a0, __s=..., __io=...,
     __fill=43 '+', __mod=<optimized out>, __v=1)
     at 
/mnt/gnu/gcc/objdir/hppa64-hp-hpux11.11/libstdc++-v3/include/bits/locale_facets.tcc:1048
1048            __ctype.widen(__cs, __cs + __len, __ws);
(gdb) p __len
$9 = -1
Comment 6 Jonathan Wakely 2018-09-04 08:51:05 UTC
And the previous line an alloca call using __len:

	_CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
							     * __len));
	__ctype.widen(__cs, __cs + __len, __ws);


The code assumes __convert_from_v always returns a valid length, but it seems to be failing and returning -1.
Comment 7 Jonathan Wakely 2018-09-04 09:04:12 UTC
I assume the implementation in libstdc++-v3/config/locale/generic/c_locale.h is used for HPUX, so one of these is returning an error, which we then use as __len:

#if _GLIBCXX_USE_C99_STDIO
    const int __ret = __builtin_vsnprintf(__out, __size, __fmt, __args);
#else
    const int __ret = __builtin_vsprintf(__out, __fmt, __args);
#endif
Comment 8 Jonathan Wakely 2018-09-04 10:38:54 UTC
Could you see what this prints on the target please?

#include <cerrno>

int
getlen(char* __out, int __size __attribute__((unused)), const char* __fmt, ...)
{
  __builtin_va_list __args;
  __builtin_va_start(__args, __fmt);

#if _GLIBCXX_USE_C99_STDIO
  __builtin_puts("using vsnprintf");
  const int __ret = __builtin_vsnprintf(__out, __size, __fmt, __args);
#else
  __builtin_puts("using vsprintf");
  const int __ret = __builtin_vsprintf(__out, __fmt, __args);
#endif
  return __ret;
}

int main()
{
  char out[64];
  errno = 0;
  int len = getlen(out, 0, "%.*g", 6, 1.99);
  __builtin_printf("returned %d, errno = %d\n", len, errno);
}
Comment 9 dave.anglin 2018-09-04 11:42:55 UTC
On 2018-09-04 6:38 AM, redi at gcc dot gnu.org wrote:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68737
>
> --- Comment #8 from Jonathan Wakely <redi at gcc dot gnu.org> ---
> Could you see what this prints on the target please?
# ./test
using vsnprintf
returned 4, errno = 0

>
> #include <cerrno>
>
> int
> getlen(char* __out, int __size __attribute__((unused)), const char* __fmt, ...)
> {
>    __builtin_va_list __args;
>    __builtin_va_start(__args, __fmt);
>
> #if _GLIBCXX_USE_C99_STDIO
>    __builtin_puts("using vsnprintf");
>    const int __ret = __builtin_vsnprintf(__out, __size, __fmt, __args);
> #else
>    __builtin_puts("using vsprintf");
>    const int __ret = __builtin_vsprintf(__out, __fmt, __args);
> #endif
>    return __ret;
> }
>
> int main()
> {
>    char out[64];
>    errno = 0;
>    int len = getlen(out, 0, "%.*g", 6, 1.99);
>    __builtin_printf("returned %d, errno = %d\n", len, errno);
> }
>
Comment 10 dave.anglin 2018-09-04 11:58:30 UTC
On 2018-09-04 4:51 AM, redi at gcc dot gnu.org wrote:
> The code assumes __convert_from_v always returns a valid length, but it seems
> to be failing and returning -1.
vsnprintf/snprintf can return a negative value if an error occurs.
Comment 11 dave.anglin 2018-09-04 12:20:11 UTC
On 2018-09-04 7:58 AM, dave.anglin at bell dot net wrote:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68737
>
> --- Comment #10 from dave.anglin at bell dot net ---
> On 2018-09-04 4:51 AM, redi at gcc dot gnu.org wrote:
>> The code assumes __convert_from_v always returns a valid length, but it seems
>> to be failing and returning -1.
> vsnprintf/snprintf can return a negative value if an error occurs.
I think we are hitting one of these problems:

JAGaf80770: vsnprintf and snprintf return doesn't conform to C99
JAGaf47646: with small buffer vsnprintf always returns -1

Probably, we should use libiberty version unless we can work around the 
buffer size issue.
Comment 12 Jonathan Wakely 2018-09-04 13:48:40 UTC
(In reply to dave.anglin from comment #11)
> JAGaf47646: with small buffer vsnprintf always returns -1

Aha, that is probably it. We pass 0 as the size, which is supposed to make vsnprintf tell you how many bytes it would have written (as that's how we find out the required length).

It's curious that it printed "returned 4, errno = 0" when you tested it though. Maybe GCC optimized the call and didn't use the OS function.

Does it return -1 if you use -fno-builtin-vsnprintf ?
Comment 13 dave.anglin 2018-09-04 14:16:16 UTC
On 2018-09-04 9:48 AM, redi at gcc dot gnu.org wrote:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68737
>
> --- Comment #12 from Jonathan Wakely <redi at gcc dot gnu.org> ---
> (In reply to dave.anglin from comment #11)
>> JAGaf47646: with small buffer vsnprintf always returns -1
> Aha, that is probably it. We pass 0 as the size, which is supposed to make
> vsnprintf tell you how many bytes it would have written (as that's how we find
> out the required length).
>
> It's curious that it printed "returned 4, errno = 0" when you tested it though.
> Maybe GCC optimized the call and didn't use the OS function.
>
> Does it return -1 if you use -fno-builtin-vsnprintf ?
No.  I checked .s file and GCC isn't optimizing the call.  It returns -1 
when passed a nonzero size
that is too small.

Passing 4 causes it to return -1:
using vsnprintf
returned -1, errno = 0

Passing 5 is okay:
using vsnprintf
returned 4, errno = 0

Maybe it's returning an incorrect length when passed 0 in some locales?

Dave
Comment 14 dave.anglin 2018-09-04 14:34:28 UTC
On 2018-09-04 10:16 AM, dave.anglin at bell dot net wrote:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68737
>
> --- Comment #13 from dave.anglin at bell dot net ---
> On 2018-09-04 9:48 AM, redi at gcc dot gnu.org wrote:
>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68737
>>
>> --- Comment #12 from Jonathan Wakely <redi at gcc dot gnu.org> ---
>> (In reply to dave.anglin from comment #11)
>>> JAGaf47646: with small buffer vsnprintf always returns -1
>> Aha, that is probably it. We pass 0 as the size, which is supposed to make
>> vsnprintf tell you how many bytes it would have written (as that's how we find
>> out the required length).
>>
>> It's curious that it printed "returned 4, errno = 0" when you tested it though.
>> Maybe GCC optimized the call and didn't use the OS function.
>>
>> Does it return -1 if you use -fno-builtin-vsnprintf ?
> No.  I checked .s file and GCC isn't optimizing the call.  It returns -1
> when passed a nonzero size
> that is too small.
>
> Passing 4 causes it to return -1:
> using vsnprintf
> returned -1, errno = 0
>
> Passing 5 is okay:
> using vsnprintf
> returned 4, errno = 0
>
> Maybe it's returning an incorrect length when passed 0 in some locales?
No, it uses the buffer when passed a a size of 0:
https://stackoverflow.com/questions/619497/heap-corruption-in-hp-ux
Comment 15 dave.anglin 2018-09-04 15:12:28 UTC
On 2018-09-04 4:51 AM, redi at gcc dot gnu.org wrote:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68737
>
> --- Comment #6 from Jonathan Wakely <redi at gcc dot gnu.org> ---
> And the previous line an alloca call using __len:
>
>          _CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
>                                                               * __len));
>          __ctype.widen(__cs, __cs + __len, __ws);
>
>
> The code assumes __convert_from_v always returns a valid length, but it seems
> to be failing and returning -1.
It appears to me we are using the first hunk of the #if:

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

         // 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));
         if (__use_prec)
           __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
                                         __fbuf, __prec, __v);
         else
           __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
                                         __fbuf, __v);

         // If the buffer was not large enough, try again with the 
correct size.
         if (__len >= __cs_size)
           {
             __cs_size = __len + 1;
             __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);
             else
               __len = std::__convert_from_v(_S_get_c_locale(), __cs, 
__cs_size,
                                             __fbuf, __v);
           }
#else
         // Consider the possibility of long ios_base::fixed outputs
         const bool __fixed = __io.flags() & ios_base::fixed;
         const int __max_exp =
__gnu_cxx::__numeric_traits<_ValueT>::__max_exponent10;

         // The size of the output string is computed as follows.
         // ios_base::fixed outputs may need up to __max_exp + 1 chars
         // for the integer part + __prec chars for the fractional part
         // + 3 chars for sign, decimal point, '\0'. On the other hand,
         // for non-fixed outputs __max_digits * 2 + __prec chars are
         // largely sufficient.
         const int __cs_size = __fixed ? __max_exp + __prec + 4
                                       : __max_digits * 2 + __prec;
         char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
         __len = std::__convert_from_v(_S_get_c_locale(), __cs, 0, __fbuf,
                                       __prec, __v);
#endif

In the first hunk, __cs_size is not zero but __max_digits * 3.  If the 
buffer is too small,
__len will be -1.  We need to check for -1 in second if.  Is 
incrementing __cs_size by
1 enough?
Comment 16 Jonathan Wakely 2018-09-04 15:20:55 UTC
Yes I've just realised that passing 0 was a red herring, because we take the 
#if _GLIBCXX_USE_C99_STDIO branch. Sorry.

I don't think __cs_size + 1 will be enough in general. There's no reason to think it's only 1 byte too small.

Maybe we need a kluge like:

--- a/libstdc++-v3/include/bits/locale_facets.tcc
+++ b/libstdc++-v3/include/bits/locale_facets.tcc
@@ -1008,6 +1008,20 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
          __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
                                        __fbuf, __v);
 
+#ifdef __hpux
+       while (__len == -1 && __cs_size < 1024)
+         {
+           __cs_size *= 2;
+           char* __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);
+           else
+             __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
+                 __fbuf, __v);
+         }
+#endif
+
        // If the buffer was not large enough, try again with the correct size.
        if (__len >= __cs_size)
          {
Comment 17 dave.anglin 2018-09-04 16:13:47 UTC
Created attachment 44659 [details]
locale_facets.tcc.d

On 2018-09-04 11:20 AM, redi at gcc dot gnu.org wrote:
> I don't think __cs_size + 1 will be enough in general. There's no reason to
> think it's only 1 byte too small.
>
> Maybe we need a kluge like:
Maybe.  I read in manpage that old glibc versions also return -1 when 
the output is truncated.

I was about to try the attached change.  Was hoping that a slightly 
larger __cs_size would work.
Comment 18 Jonathan Wakely 2018-09-04 16:35:34 UTC
I don't think we care about glibc < 2.0.6 though.

__max_digits * 4 is not enough for:

  std::cout << std::fixed << std::numeric_limits<long double>::max();

That needs 4940 bytes, but we don't want to unconditionally alloca that amount.

Maybe:

--- a/libstdc++-v3/include/bits/locale_facets.tcc
+++ b/libstdc++-v3/include/bits/locale_facets.tcc
@@ -1008,6 +1008,11 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
          __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
                                        __fbuf, __v);
 
+#ifdef __hpux
+       if (__len == -1)
+         __len = __cs_size = 5000;
+#endif
+
        // If the buffer was not large enough, try again with the correct size.
        if (__len >= __cs_size)
          {
@@ -1020,6 +1025,11 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
              __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
                                            __fbuf, __v);
          }
+
+#ifdef __hpux
+       if (__len == -1)
+         return __s;
+#endif
 #else
        // Consider the possibility of long ios_base::fixed outputs
        const bool __fixed = __io.flags() & ios_base::fixed;
Comment 19 dave.anglin 2018-09-04 17:00:50 UTC
On 2018-09-04 12:35 PM, redi at gcc dot gnu.org wrote:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68737
>
> --- Comment #18 from Jonathan Wakely <redi at gcc dot gnu.org> ---
> I don't think we care about glibc < 2.0.6 though.
>
> __max_digits * 4 is not enough for:
>
>    std::cout << std::fixed << std::numeric_limits<long double>::max();
>
> That needs 4940 bytes, but we don't want to unconditionally alloca that amount.
>
> Maybe:
>
> --- a/libstdc++-v3/include/bits/locale_facets.tcc
> +++ b/libstdc++-v3/include/bits/locale_facets.tcc
> @@ -1008,6 +1008,11 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
>            __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
>                                          __fbuf, __v);
>
> +#ifdef __hpux
> +       if (__len == -1)
> +         __len = __cs_size = 5000;
> +#endif
> +
>          // If the buffer was not large enough, try again with the correct size.
>          if (__len >= __cs_size)
>            {
> @@ -1020,6 +1025,11 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
>                __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
>                                              __fbuf, __v);
>            }
> +
> +#ifdef __hpux
> +       if (__len == -1)
> +         return __s;
> +#endif
>   #else
>          // Consider the possibility of long ios_base::fixed outputs
>          const bool __fixed = __io.flags() & ios_base::fixed;
>
Testing.
Comment 20 Jonathan Wakely 2018-09-05 10:34:00 UTC
(In reply to Jonathan Wakely from comment #18)
> +#ifdef __hpux
> +       if (__len == -1)
> +         return __s;
> +#endif

N.B. I really don't want to just abort here, nor assume that __len is valid, and then continue onwards with undefined behaviour. But I don't think this function has any way to report an error. Maybe it should throw an exception instead.

It also occurs to me that in some cases we could reuse the original alloca result for the final output string instead of doing yet another alloca, e.g. if we alloca(5000) and find __len is less than (5000 / sizeof(wchar_t)) then we could reuse it. Or maybe beyond a certain size we should switch to the heap.
Comment 21 Jonathan Wakely 2018-09-05 12:07:51 UTC
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;
Comment 22 dave.anglin 2018-09-05 15:02:49 UTC
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;
>
Comment 23 Jonathan Wakely 2018-09-05 15:53:38 UTC
I prefer just forcing the use of vsprintf with a larger buffer, it avoids adding more complexity to the code.

(In reply to dave.anglin from comment #22)
> 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.

Yes, it needs to avoid looping forever.

> Another option would be to just duplicate the code instead of branching 
> back.

Yes, but it's already duplicated and I didn't want to add another one.

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

I'm not sure if an output error is ever possible when writing to a buffer (rather than to a file) when we control the format specification.

I'll return to this another time.
Comment 24 dave.anglin 2018-09-05 22:45:00 UTC
On 2018-09-05 11:53 AM, redi at gcc dot gnu.org wrote:
> I prefer just forcing the use of vsprintf with a larger buffer, it avoids
> adding more complexity to the code.
Will test in next build.
Comment 25 dave.anglin 2019-01-28 01:42:18 UTC
On 2018-09-05 8:07 a.m., redi at gcc dot gnu.org wrote:
> 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;
The above fix is okay for now.

Dave
Comment 26 Jonathan Wakely 2019-01-28 23:59:29 UTC
Author: redi
Date: Mon Jan 28 23:58:57 2019
New Revision: 268350

URL: https://gcc.gnu.org/viewcvs?rev=268350&root=gcc&view=rev
Log:
PR libstdc++/68737 Do not use vsnprintf on HPUX

It doesn't conform to the spec, so use vsprintf with a large buffer
instead.

	PR libstdc++/68737
	* config/locale/generic/c_locale.h (__convert_from_v)
	[_GLIBCXX_USE_C99_STDIO]: Also check _GLIBCXX_HAVE_BROKEN_VSNPRINTF.
	* config/os/hpux/os_defines.h: Define _GLIBCXX_HAVE_BROKEN_VSNPRINTF.
	* include/bits/locale_facets.tcc (num_put::_M_insert_float)
	[_GLIBCXX_USE_C99_STDIO]: Also check _GLIBCXX_HAVE_BROKEN_VSNPRINTF.

Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/config/locale/generic/c_locale.h
    trunk/libstdc++-v3/config/os/hpux/os_defines.h
    trunk/libstdc++-v3/include/bits/locale_facets.tcc
Comment 27 Jonathan Wakely 2019-01-29 09:53:54 UTC
Done - do you want to keep this open?
Comment 28 dave.anglin 2019-01-29 15:06:20 UTC
On 2019-01-29 4:53 a.m., redi at gcc dot gnu.org wrote:
> Done - do you want to keep this open?
Could the change be backported?  I will test in coming days.
Comment 29 Jonathan Wakely 2020-07-13 11:20:53 UTC
Dave, did you test this for the gcc-8 branch? Do you still want it backported to that branch?

It's fixed in 9.1.0 and later.
Comment 30 dave.anglin 2020-07-15 17:07:53 UTC
I'll test when I get a chance.
Comment 31 dave.anglin 2020-07-21 13:23:35 UTC
On 2020-07-13 7:20 a.m., redi at gcc dot gnu.org wrote:
> Dave, did you test this for the gcc-8 branch? Do you still want it backported
> to that branch?
Yes please.  The patch applies cleanly on the gcc-8 branch.  Then, we can close this PR.

Thanks,
Dave
Comment 32 GCC Commits 2020-07-21 14:25:01 UTC
The releases/gcc-8 branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:

https://gcc.gnu.org/g:c54d4e218f18c66ce1ad9d7e7762357fd7edacb7

commit r8-10367-gc54d4e218f18c66ce1ad9d7e7762357fd7edacb7
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Jan 28 23:58:57 2019 +0000

    PR libstdc++/68737 Do not use vsnprintf on HPUX
    
    It doesn't conform to the spec, so use vsprintf with a large buffer
    instead.
    
            PR libstdc++/68737
            * config/locale/generic/c_locale.h (__convert_from_v)
            [_GLIBCXX_USE_C99_STDIO]: Also check _GLIBCXX_HAVE_BROKEN_VSNPRINTF.
            * config/os/hpux/os_defines.h: Define _GLIBCXX_HAVE_BROKEN_VSNPRINTF.
            * include/bits/locale_facets.tcc (num_put::_M_insert_float)
            [_GLIBCXX_USE_C99_STDIO]: Also check _GLIBCXX_HAVE_BROKEN_VSNPRINTF.
    
    (cherry picked from commit c98f255154798847bdd1fc6ce33266c1a1ddc13a)
Comment 33 Jonathan Wakely 2020-07-21 15:09:55 UTC
Also fixed for 8.5.0 now.