basic/stdio-util: introduce asprintf_safe
asprintf is nice to use, but the _documented_ error return convention is unclear: > If memory allocation wasn't possible, or some other error occurs, > these functions will return -1, and the contents of strp are undefined. What exactly "undefined" means is up for debate: if it was really undefined, the caller wouldn't be able to meaningfully clean up, because they wouldn't know if strp is a valid pointer. So far we interpreted "undefined" — in some parts of the code base — as "either NULL or a valid pointer that needs to be freed", and — in other parts of the codebase — as "always NULL". I checked glibc and musl, and they both uncoditionally set the output pointer to NULL on failure. There is also no information _why_ asprintf failed. It could be an allocation error or format string error. But we just don't have this information. Let's add a wrapper that either returns a good string or a NULL pointer. Since there's just one failure result, we don't need a separate return value and an output argument and can simplify callers.
This commit is contained in:
@@ -754,9 +754,9 @@ SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
section of the `alloca(3)` man page.
|
||||
|
||||
- If you want to concatenate two or more strings, consider using `strjoina()`
|
||||
or `strjoin()` rather than `asprintf()`, as the latter is a lot slower. This
|
||||
matters particularly in inner loops (but note that `strjoina()` cannot be
|
||||
used there).
|
||||
or `strjoin()` rather than `asprintf()` or `asprintf_safe`, as the latter is
|
||||
a lot slower. This matters particularly in inner loops (but note that
|
||||
`strjoina()` cannot be used there).
|
||||
|
||||
## Runtime Behaviour
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ basic_sources = files(
|
||||
'sort-util.c',
|
||||
'stat-util.c',
|
||||
'static-destruct.c',
|
||||
'stdio-util.c',
|
||||
'strbuf.c',
|
||||
'string-table.c',
|
||||
'string-util.c',
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "stdio-util.h"
|
||||
|
||||
char* asprintf_safe(const char *restrict fmt, ...) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
va_start(ap, fmt);
|
||||
r = vasprintf(&buf, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
return TAKE_PTR(buf);
|
||||
}
|
||||
@@ -21,6 +21,8 @@ static inline char* snprintf_ok(char *buf, size_t len, const char *format, ...)
|
||||
#define xsprintf(buf, fmt, ...) \
|
||||
assert_message_se(snprintf_ok(buf, ELEMENTSOF(buf), fmt, ##__VA_ARGS__), "xsprintf: buffer too small")
|
||||
|
||||
char* asprintf_safe(const char *restrict fmt, ...) _printf_(1, 2);
|
||||
|
||||
#define VA_FORMAT_ADVANCE(format, ap) \
|
||||
do { \
|
||||
int _argtypes[128]; \
|
||||
|
||||
Reference in New Issue
Block a user