]> Savannah Git Hosting - gnulib.git/commitdiff
string-buffer: Remove INT_MAX limitation.
authorBruno Haible <bruno@clisp.org>
Tue, 24 Sep 2024 16:31:49 +0000 (18:31 +0200)
committerBruno Haible <bruno@clisp.org>
Tue, 24 Sep 2024 16:47:06 +0000 (18:47 +0200)
* lib/string-buffer.h (sb_appendvf, sb_appendf): Document that errno is
set upon failure.
* lib/string-buffer-printf.c: Include <errno.h>.
(sb_appendvf): Call vsnzprintf instead of vsnprintf. Ensure errno is
set upon failure.
(sb_appendf): Likewise.
* modules/string-buffer (Depends-on): Add vsnzprintf-posix. Remove
vsnprintf-posix.
* tests/test-string-buffer.c (main): Test error code from sb_appendf.

ChangeLog
lib/string-buffer-printf.c
lib/string-buffer.h
modules/string-buffer
tests/test-string-buffer.c

index 8c8fb9227b1fde1f85997883bb38ebfcfe7c6d8c..e6eaf1be5535f18d0c94e701f4b83446b25d0e7d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2024-09-24  Bruno Haible  <bruno@clisp.org>
+
+       string-buffer: Remove INT_MAX limitation.
+       * lib/string-buffer.h (sb_appendvf, sb_appendf): Document that errno is
+       set upon failure.
+       * lib/string-buffer-printf.c: Include <errno.h>.
+       (sb_appendvf): Call vsnzprintf instead of vsnprintf. Ensure errno is
+       set upon failure.
+       (sb_appendf): Likewise.
+       * modules/string-buffer (Depends-on): Add vsnzprintf-posix. Remove
+       vsnprintf-posix.
+       * tests/test-string-buffer.c (main): Test error code from sb_appendf.
+
 2024-09-24  Bruno Haible  <bruno@clisp.org>
 
        string-buffer: Link to vasnprintf implementation only when needed.
index 16ef4e4144f5672eef72305ab9be1888e23277b4..6e5ce78b353b76071bc7424ce36a92f6fe5e008a 100644 (file)
@@ -25,6 +25,7 @@
 extern int sb_ensure_more_bytes (struct string_buffer *buffer,
                                  size_t increment);
 
+#include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -35,14 +36,15 @@ sb_appendvf (struct string_buffer *buffer, const char *formatstring,
 {
   va_list list_copy;
 
-  /* Make a bit of room, so that the probability that the first vsnprintf() call
-     succeeds is high.  */
+  /* Make a bit of room, so that the probability that the first vsnzprintf()
+     call succeeds is high.  */
   size_t room = buffer->allocated - buffer->length;
   if (room < 64)
     {
       if (sb_ensure_more_bytes (buffer, 64) < 0)
         {
           buffer->error = true;
+          errno = ENOMEM;
           return -1;
         }
       room = buffer->allocated - buffer->length;
@@ -50,17 +52,18 @@ sb_appendvf (struct string_buffer *buffer, const char *formatstring,
 
   va_copy (list_copy, list);
 
-  /* First vsnprintf() call.  */
-  int ret = vsnprintf (buffer->data + buffer->length, room, formatstring, list);
+  /* First vsnzprintf() call.  */
+  ptrdiff_t ret = vsnzprintf (buffer->data + buffer->length, room,
+                              formatstring, list);
   if (ret < 0)
     {
-      /* Failed.  */
+      /* Failed.  errno is set.  */
       buffer->error = true;
       ret = -1;
     }
   else
     {
-      if ((size_t) ret <= room)
+      if (ret <= room)
         {
           /* The result has fit into room bytes.  */
           buffer->length += (size_t) ret;
@@ -68,35 +71,36 @@ sb_appendvf (struct string_buffer *buffer, const char *formatstring,
         }
       else
         {
-          /* The result was truncated.  Make more room, for a second vsnprintf()
-             call.  */
+          /* The result was truncated.  Make more room, for a second
+             vsnzprintf() call.  */
           if (sb_ensure_more_bytes (buffer, (size_t) ret) < 0)
             {
               buffer->error = true;
+              errno = ENOMEM;
               ret = -1;
             }
           else
             {
-              /* Second vsnprintf() call.  */
+              /* Second vsnzprintf() call.  */
               room = buffer->allocated - buffer->length;
-              ret = vsnprintf (buffer->data + buffer->length, room,
-                               formatstring, list_copy);
+              ret = vsnzprintf (buffer->data + buffer->length, room,
+                                formatstring, list_copy);
               if (ret < 0)
                 {
-                  /* Failed.  */
+                  /* Failed.  errno is set.  */
                   buffer->error = true;
                   ret = -1;
                 }
               else
                 {
-                  if ((size_t) ret <= room)
+                  if (ret <= room)
                     {
                       /* The result has fit into room bytes.  */
                       buffer->length += (size_t) ret;
                       ret = 0;
                     }
                   else
-                    /* The return values of the vsnprintf() calls are not
+                    /* The return values of the vsnzprintf() calls are not
                        consistent.  */
                     abort ();
                 }
@@ -113,14 +117,15 @@ sb_appendf (struct string_buffer *buffer, const char *formatstring, ...)
 {
   va_list args;
 
-  /* Make a bit of room, so that the probability that the first vsnprintf() call
-     succeeds is high.  */
+  /* Make a bit of room, so that the probability that the first vsnzprintf()
+     call succeeds is high.  */
   size_t room = buffer->allocated - buffer->length;
   if (room < 64)
     {
       if (sb_ensure_more_bytes (buffer, 64) < 0)
         {
           buffer->error = true;
+          errno = ENOMEM;
           return -1;
         }
       room = buffer->allocated - buffer->length;
@@ -128,17 +133,18 @@ sb_appendf (struct string_buffer *buffer, const char *formatstring, ...)
 
   va_start (args, formatstring);
 
-  /* First vsnprintf() call.  */
-  int ret = vsnprintf (buffer->data + buffer->length, room, formatstring, args);
+  /* First vsnzprintf() call.  */
+  ptrdiff_t ret = vsnzprintf (buffer->data + buffer->length, room,
+                              formatstring, args);
   if (ret < 0)
     {
-      /* Failed.  */
+      /* Failed.  errno is set.  */
       buffer->error = true;
       ret = -1;
     }
   else
     {
-      if ((size_t) ret <= room)
+      if (ret <= room)
         {
           /* The result has fit into room bytes.  */
           buffer->length += (size_t) ret;
@@ -146,37 +152,38 @@ sb_appendf (struct string_buffer *buffer, const char *formatstring, ...)
         }
       else
         {
-          /* The result was truncated.  Make more room, for a second vsnprintf()
-             call.  */
+          /* The result was truncated.  Make more room, for a second
+             vsnzprintf() call.  */
           if (sb_ensure_more_bytes (buffer, (size_t) ret) < 0)
             {
               buffer->error = true;
+              errno = ENOMEM;
               ret = -1;
             }
           else
             {
-              /* Second vsnprintf() call.  */
+              /* Second vsnzprintf() call.  */
               room = buffer->allocated - buffer->length;
               va_end (args);
               va_start (args, formatstring);
-              ret = vsnprintf (buffer->data + buffer->length, room,
-                               formatstring, args);
+              ret = vsnzprintf (buffer->data + buffer->length, room,
+                                formatstring, args);
               if (ret < 0)
                 {
-                  /* Failed.  */
+                  /* Failed.  errno is set.  */
                   buffer->error = true;
                   ret = -1;
                 }
               else
                 {
-                  if ((size_t) ret <= room)
+                  if (ret <= room)
                     {
                       /* The result has fit into room bytes.  */
                       buffer->length += (size_t) ret;
                       ret = 0;
                     }
                   else
-                    /* The return values of the vsnprintf() calls are not
+                    /* The return values of the vsnzprintf() calls are not
                        consistent.  */
                     abort ();
                 }
index c854aaa809d3744d8018dbb7cd864c0782396239..9220ab301db6958a3a538ab00fc53feb675d65e5 100644 (file)
@@ -52,7 +52,10 @@ extern int sb_append (struct string_buffer *buffer, const char *str);
 
 /* Appends the result of the printf-compatible FORMATSTRING with the argument
    list LIST to BUFFER.
-   Returns 0, or -1 in case of error.  */
+   Returns 0, or -1 with errno set in case of error.
+   Error code EOVERFLOW can only occur when a width > INT_MAX is used.
+   Therefore, if the format string is valid and does not use %ls/%lc
+   directives nor widths, the only possible error code is ENOMEM.  */
 extern int sb_appendvf (struct string_buffer *buffer,
                         const char *formatstring, va_list list)
   #if (__GNUC__ + (__GNUC_MINOR__ >= 4) > 4) && !defined __clang__
@@ -64,7 +67,10 @@ extern int sb_appendvf (struct string_buffer *buffer,
 
 /* Appends the result of the printf-compatible FORMATSTRING with the following
    arguments to BUFFER.
-   Returns 0, or -1 in case of error.  */
+   Returns 0, or -1 with errno set in case of error.
+   Error code EOVERFLOW can only occur when a width > INT_MAX is used.
+   Therefore, if the format string is valid and does not use %ls/%lc
+   directives nor widths, the only possible error code is ENOMEM.  */
 extern int sb_appendf (struct string_buffer *buffer,
                         const char *formatstring, ...)
   #if (__GNUC__ + (__GNUC_MINOR__ >= 4) > 4) && !defined __clang__
index 76c07d94ac862dbf1e04080d413c938497253953..2010641b2b3d37a7a80c0a22b5f3a44514fe286e 100644 (file)
@@ -10,7 +10,7 @@ Depends-on:
 stdbool
 attribute
 stdarg
-vsnprintf-posix
+vsnzprintf-posix
 
 configure.ac:
 
index 8538ac0cecbf461902c25702c14ce8c2c11866ed..d492837b39a124e3c36bc07fe76c98b81750c281 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "string-buffer.h"
 
+#include <errno.h>
 #include <string.h>
 #include <wchar.h>
 
@@ -94,19 +95,33 @@ main ()
   /* Test printf-like formatting failure.
      On all systems except AIX, trying to convert the wide-character 0x76543210
      to a multibyte string (in the "C" locale) fails.
-     On all systems where REPLACE_VSNPRINTF=1 (this includes AIX), i.e. where
-     the Gnulib implementation of vsnprintf() is used), invalid format
-     directives make the *printf call fail.  */
+     On all systems, invalid format directives make the vsnzprintf() call
+     fail.  */
   {
     struct string_buffer buffer;
+    int ret;
 
     sb_init (&buffer);
     sb_append (&buffer, "<");
-    sb_appendf (&buffer, "%lc", (wint_t) 0x76543210);
+
+    ret = sb_appendf (&buffer, "%lc", (wint_t) 0x76543210);
+    #if !defined _AIX
+    ASSERT (ret < 0);
+    ASSERT (errno == EILSEQ);
+    #endif
+
     sb_append (&buffer, "|");
-    sb_appendf (&buffer, invalid_format_string_1, 1);
+
+    ret = sb_appendf (&buffer, invalid_format_string_1, 1);
+    ASSERT (ret < 0);
+    ASSERT (errno == EINVAL);
+
     sb_append (&buffer, "|");
-    sb_appendf (&buffer, invalid_format_string_2, 2);
+
+    ret = sb_appendf (&buffer, invalid_format_string_2, 2);
+    ASSERT (ret < 0);
+    ASSERT (errno == EINVAL);
+
     sb_append (&buffer, ">");
     char *s = sb_dupfree (&buffer);
     ASSERT (s == NULL);