about summary refs log tree commit diff
path: root/libio
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2023-01-25 08:01:00 +0100
committerFlorian Weimer <fweimer@redhat.com>2023-01-25 08:01:00 +0100
commit0d50f477f47ba637b54fb03ac48d769ec4543e8d (patch)
tree598fbe050d8441a6152237d5442d2506ed846bf0 /libio
parent0674613e6652a46063756f162bdef88622b3bdbd (diff)
downloadglibc-0d50f477f47ba637b54fb03ac48d769ec4543e8d.tar.gz
glibc-0d50f477f47ba637b54fb03ac48d769ec4543e8d.tar.xz
glibc-0d50f477f47ba637b54fb03ac48d769ec4543e8d.zip
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.c15
1 files changed, 10 insertions, 5 deletions
diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
index 8d53e401cc..9a4f59a06e 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);