+2024-06-22 Bruno Haible <bruno@clisp.org>
+
+ c-xvasprintf: Guarantee a non-NULL result.
+ * lib/c-xvasprintf.h: Clarify the programmer's responsibilities.
+ (c_xasprintf, c_xvasprintf): Declare as returning non-NULL.
+ * lib/c-xvasprintf.c: Include <stdlib.h>, <string.h>.
+ (c_xvasprintf): Call c_vazsprintf instead of c_vasprintf. When some
+ other error occurs, emit an error message and abort.
+ * modules/c-xvasprintf (Files): Add m4/strerrorname_np.m4.
+ (Depends-on): Add extensions, c-vazsprintf. Remove c-vasprintf.
+ (configure.ac): Invoke gl_OPTIONAL_STRERRORNAME_NP.
+ * NEWS: Mention the change.
+
2024-06-22 Bruno Haible <bruno@clisp.org>
c-vasprintf: Make return convention consistent with other modules.
#include <errno.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include "c-vasprintf.h"
#include "xalloc.h"
{
char *result;
- if (c_vasprintf (&result, format, args) < 0)
+ if (c_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, "c_vasprintf failed! format=\"%s\", errno=%s\n",
+ format, errname);
+ fflush (stderr);
+ abort ();
+ }
}
return result;
#ifndef _C_XVASPRINTF_H
#define _C_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.
Formatting takes place in the C locale, that is, the decimal point
used in floating-point formatting directives is always '.'. */
extern char *c_xasprintf (const char *format, ...)
_GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 1, 2))
- _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE;
+ _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
+ _GL_ATTRIBUTE_RETURNS_NONNULL;
extern char *c_xvasprintf (const char *format, va_list args)
_GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 1, 0))
- _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE;
+ _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
+ _GL_ATTRIBUTE_RETURNS_NONNULL;
#ifdef __cplusplus
}