diff options
author | Florian Weimer <fweimer@redhat.com> | 2023-01-25 08:01:00 +0100 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2023-01-25 08:01:00 +0100 |
commit | 0d50f477f47ba637b54fb03ac48d769ec4543e8d (patch) | |
tree | 598fbe050d8441a6152237d5442d2506ed846bf0 /libio | |
parent | 0674613e6652a46063756f162bdef88622b3bdbd (diff) | |
download | glibc-0d50f477f47ba637b54fb03ac48d769ec4543e8d.zip glibc-0d50f477f47ba637b54fb03ac48d769ec4543e8d.tar.gz glibc-0d50f477f47ba637b54fb03ac48d769ec4543e8d.tar.bz2 |
stdio-common: Handle -1 buffer size in __sprintf_chk & co (bug 30039)
This shows up as an assertion failure when sprintf is called with
a specifier like "%.8g" and libquadmath is linked in:
Fatal glibc error: printf_buffer_as_file.c:31
(__printf_buffer_as_file_commit): assertion failed:
file->stream._IO_write_ptr <= file->next->write_end
Fix this by detecting pointer wraparound in __vsprintf_internal
and saturate the addition to the end of the address space instead.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Diffstat (limited to 'libio')
-rw-r--r-- | libio/iovsprintf.c | 15 |
1 files changed, 10 insertions, 5 deletions
diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c index 8d53e40..9a4f59a 100644 --- a/libio/iovsprintf.c +++ b/libio/iovsprintf.c @@ -45,14 +45,19 @@ __vsprintf_internal (char *string, size_t maxlen, if ((mode_flags & PRINTF_CHK) != 0) { string[0] = '\0'; - __printf_buffer_init (&buf, string, maxlen, + /* In some cases, __sprintf_chk is called with an unknown buffer + size (the special value -1). Prevent pointer wraparound in + this case and saturate to the end of the address space. */ + uintptr_t end; + if (__builtin_add_overflow ((uintptr_t) string, maxlen, &end)) + end = -1; + __printf_buffer_init_end (&buf, string, (char *) end, __printf_buffer_mode_sprintf_chk); } else - { - __printf_buffer_init (&buf, string, 0, __printf_buffer_mode_sprintf); - buf.write_end = (char *) ~(uintptr_t) 0; /* End of address space. */ - } + /* Use end of address space. */ + __printf_buffer_init_end (&buf, string, (char *) ~(uintptr_t) 0, + __printf_buffer_mode_sprintf); __printf_buffer (&buf, format, args, mode_flags); |