]> Savannah Git Hosting - gnulib.git/commitdiff
xvasprintf: Guarantee a non-NULL result.
authorBruno Haible <bruno@clisp.org>
Sat, 22 Jun 2024 10:17:51 +0000 (12:17 +0200)
committerBruno Haible <bruno@clisp.org>
Sat, 22 Jun 2024 10:17:51 +0000 (12:17 +0200)
* lib/xvasprintf.h: Clarify the programmer's responsibilities.
(xasprintf, xvasprintf): Declare as returning non-NULL.
* lib/xvasprintf.c: Include <stdlib.h>.
(xstrcat): Allow results longer than INT_MAX characters. Upon size
overflow, invoke xalloc_die.
(xvasprintf): Call vazsprintf instead of vasprintf. When some other
error occurs, emit an error message and abort.
* m4/strerrorname_np.m4 (gl_CHECK_STRERRORNAME_NP): New macro, extracted
from gl_FUNC_STRERRORNAME_NP.
(gl_FUNC_STRERRORNAME_NP): Invoke it.
(gl_OPTIONAL_STRERRORNAME_NP): New macro.
* m4/xvasprintf.m4 (gl_XVASPRINTF): Invoke gl_OPTIONAL_STRERRORNAME_NP.
* modules/xvasprintf (Files): Add m4/strerrorname_np.m4.
(Depends-on): Add extensions, vazsprintf. Remove vasprintf.
* NEWS: Mention the change.

ChangeLog
NEWS
lib/xvasprintf.c
lib/xvasprintf.h
m4/strerrorname_np.m4
m4/xvasprintf.m4
modules/xvasprintf

index 7c720ba88590ec00713346be4b4f848f54d0cc3e..ef21dcc22270bc544fc074a4c0be14f9158d3beb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2024-06-22  Bruno Haible  <bruno@clisp.org>
+
+       xvasprintf: Guarantee a non-NULL result.
+       * lib/xvasprintf.h: Clarify the programmer's responsibilities.
+       (xasprintf, xvasprintf): Declare as returning non-NULL.
+       * lib/xvasprintf.c: Include <stdlib.h>.
+       (xstrcat): Allow results longer than INT_MAX characters. Upon size
+       overflow, invoke xalloc_die.
+       (xvasprintf): Call vazsprintf instead of vasprintf. When some other
+       error occurs, emit an error message and abort.
+       * m4/strerrorname_np.m4 (gl_CHECK_STRERRORNAME_NP): New macro, extracted
+       from gl_FUNC_STRERRORNAME_NP.
+       (gl_FUNC_STRERRORNAME_NP): Invoke it.
+       (gl_OPTIONAL_STRERRORNAME_NP): New macro.
+       * m4/xvasprintf.m4 (gl_XVASPRINTF): Invoke gl_OPTIONAL_STRERRORNAME_NP.
+       * modules/xvasprintf (Files): Add m4/strerrorname_np.m4.
+       (Depends-on): Add extensions, vazsprintf. Remove vasprintf.
+       * NEWS: Mention the change.
+
 2024-06-22  Bruno Haible  <bruno@clisp.org>
 
        vasprintf: Make return convention consistent with other modules.
diff --git a/NEWS b/NEWS
index 57540c8375d9ebd925308fca1f9ffb5528f4fd09..36ffbb64f8cd10d60549457e041d9bca113fefad 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -74,6 +74,10 @@ User visible incompatible changes
 
 Date        Modules         Changes
 
+2024-06-22  xvasprintf      It is now the programmer's responsibility to pass
+                            a valid format string without %ls, %lc directives
+                            and that all widths are >= -INT_MAX and <= INT_MAX.
+
 2024-05-16  putenv          This module is renamed to 'putenv-gnu'.
 
 2024-02-21  *printf-posix   These modules no longer support the 'n' directive
index 6cf6d36a58d89e9b78be75dd5ab15157077a824a..97f24eb297294d327af625fe272257e7c09584bc 100644 (file)
@@ -21,8 +21,9 @@
 
 #include <errno.h>
 #include <limits.h>
-#include <string.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include "xalloc.h"
 
@@ -48,14 +49,10 @@ xstrcat (size_t argcount, va_list args)
     }
   va_end (ap);
 
-  /* Test for overflow in the summing pass above or in (totalsize + 1) below.
-     Also, don't return a string longer than INT_MAX, for consistency with
-     vasprintf().  */
-  if (totalsize == SIZE_MAX || totalsize > INT_MAX)
-    {
-      errno = EOVERFLOW;
-      return NULL;
-    }
+  /* Test for overflow in the summing pass above or in (totalsize + 1)
+     below.  */
+  if (totalsize == SIZE_MAX)
+    xalloc_die ();
 
   /* Allocate and fill the result string.  */
   result = XNMALLOC (totalsize + 1, char);
@@ -99,11 +96,38 @@ xvasprintf (const char *format, va_list args)
       }
   }
 
-  if (vasprintf (&result, format, args) < 0)
+  if (vazsprintf (&result, format, args) < 0)
     {
       if (errno == ENOMEM)
         xalloc_die ();
-      return NULL;
+      else
+        {
+          /* The programmer ought to have ensured that none of the other errors
+             can occur.  */
+          int err = errno;
+          char errbuf[20];
+          const char *errname;
+#if HAVE_WORKING_STRERRORNAME_NP
+          errname = strerrorname_np (err);
+          if (errname == NULL)
+#else
+          if (err == EINVAL)
+            errname = "EINVAL";
+          else if (err == EILSEQ)
+            errname = "EILSEQ";
+          else if (err == EOVERFLOW)
+            errname = "EOVERFLOW";
+          else
+#endif
+            {
+              sprintf (errbuf, "%d", err);
+              errname = errbuf;
+            }
+          fprintf (stderr, "vasprintf failed! format=\"%s\", errno=%s\n",
+                   format, errname);
+          fflush (stderr);
+          abort ();
+        }
     }
 
   return result;
index 937f97ba4bcc5d2c7392a73e0828fbbf754a6bf3..fac633c5494bc7e46728bdd12ddf6663c0466614 100644 (file)
@@ -17,7 +17,8 @@
 #ifndef _XVASPRINTF_H
 #define _XVASPRINTF_H
 
-/* This file uses _GL_ATTRIBUTE_FORMAT, _GL_ATTRIBUTE_MALLOC.  */
+/* This file uses _GL_ATTRIBUTE_FORMAT, _GL_ATTRIBUTE_MALLOC,
+   _GL_ATTRIBUTE_RETURNS_NONNULL.  */
 #if !_GL_CONFIG_H_INCLUDED
  #error "Please include config.h first."
 #endif
 extern "C" {
 #endif
 
-/* Write formatted output to a string dynamically allocated with malloc(),
-   and return it.  Upon [ENOMEM] memory allocation error, call xalloc_die.
-   On some other error
-     - [EOVERFLOW] resulting string length is > INT_MAX,
+/* Prints formatted output to a string dynamically allocated with malloc(),
+   and returns it.  Upon [ENOMEM] memory allocation error, it calls xalloc_die.
+
+   It is the responsibility of the programmer to ensure that
+     - the format string is valid,
+     - the format string does not use %ls or %lc directives, and
+     - all widths in the format string and passed as arguments are >= -INT_MAX
+       and <= INT_MAX,
+   so that other errors
      - [EINVAL] invalid format string,
      - [EILSEQ] error during conversion between wide and multibyte characters,
-   return NULL.  */
+     - [EOVERFLOW] some specified width is > INT_MAX,
+   cannot occur.  */
 extern char *xasprintf (const char *format, ...)
        _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
-       _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 1, 2));
+       _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 1, 2))
+       _GL_ATTRIBUTE_RETURNS_NONNULL;
 extern char *xvasprintf (const char *format, va_list args)
        _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
-       _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 1, 0));
+       _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 1, 0))
+       _GL_ATTRIBUTE_RETURNS_NONNULL;
 
 #ifdef __cplusplus
 }
index 9725155baea4f80dd9e50a8408ab5c4f275648ae..ac0211715ac8196d45c0d9115aa12f4c11990d7e 100644 (file)
@@ -1,5 +1,5 @@
 # strerrorname_np.m4
-# serial 5
+# serial 6
 dnl Copyright (C) 2020-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -9,6 +9,21 @@ AC_DEFUN([gl_FUNC_STRERRORNAME_NP],
 [
   AC_REQUIRE([gl_STRING_H_DEFAULTS])
 
+  AC_REQUIRE([gl_CHECK_STRERRORNAME_NP])
+  if test $ac_cv_func_strerrorname_np = yes; then
+    case "$gl_cv_func_strerrorname_np_works" in
+      *yes) ;;
+      *) REPLACE_STRERRORNAME_NP=1 ;;
+    esac
+  else
+    HAVE_STRERRORNAME_NP=0
+  fi
+])
+
+# Check for a working strerrorname_np function.
+# Sets ac_cv_func_strerrorname_np, gl_cv_func_strerrorname_np_works.
+AC_DEFUN([gl_CHECK_STRERRORNAME_NP],
+[
   dnl Persuade glibc <string.h> to declare strerrorname_np().
   AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
 
@@ -54,11 +69,19 @@ AC_DEFUN([gl_FUNC_STRERRORNAME_NP],
           esac
          ])
       ])
+  fi
+])
+
+# Prerequisite for using strerrorname_np when available.
+AC_DEFUN_ONCE([gl_OPTIONAL_STRERRORNAME_NP],
+[
+  AC_REQUIRE([gl_CHECK_STRERRORNAME_NP])
+  if test $ac_cv_func_strerrorname_np = yes; then
     case "$gl_cv_func_strerrorname_np_works" in
-      *yes) ;;
-      *) REPLACE_STRERRORNAME_NP=1 ;;
+      *yes)
+        AC_DEFINE([HAVE_WORKING_STRERRORNAME_NP], [1],
+          [Define to 1 if the function strerrorname_np exists and works.])
+        ;;
     esac
-  else
-    HAVE_STRERRORNAME_NP=0
   fi
 ])
index f492e990cbe12f3ea1b1a6073041578d3de456d5..a3c15966d959fa32f961a574bc39ddb139402e45 100644 (file)
@@ -1,9 +1,11 @@
 # xvasprintf.m4
-# serial 2
+# serial 3
 dnl Copyright (C) 2006, 2009-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
 dnl Prerequisites of lib/xvasprintf.c.
-AC_DEFUN([gl_XVASPRINTF], [:])
+AC_DEFUN([gl_XVASPRINTF], [
+  gl_OPTIONAL_STRERRORNAME_NP
+])
index b3228908761a930768b6f09efabccb2a3d275ebe..bb537ce3eeb457ba21734de8916a1689eb4ae525 100644 (file)
@@ -7,10 +7,12 @@ lib/xvasprintf.c
 lib/xasprintf.c
 lib/xalloc.h
 m4/xvasprintf.m4
+m4/strerrorname_np.m4
 
 Depends-on:
+extensions
 stdio
-vasprintf
+vazsprintf
 xalloc
 xalloc-die
 extern-inline