mirror of
https://github.com/shadow-maint/shadow.git
synced 2026-01-27 14:24:12 +00:00
These functions are like [v]snprintf(3), but return -1 on truncation, which makes it easier to test. In fact, the API of swprintf(3), which was invented later than snprintf(3), and is the wide-character version of it, is identical to this snprintf_(). snprintf(3) is iseful in two cases: - We don't care if the output is truncated. snprintf(3) is fine for those, and the return value can be ignored. But snprintf_() is also fine for those. - Truncation is bad. In that case, it's as bad as a hard error (-1) from snprintf, so merging both problems into the same error code makes it easier to handle errors. Return the length if no truncation so that we can use it if necessary. Not returning the whole length before truncation makes a better API, which need not read the entire input, so it's less vulnerable to DoS attacks when a malicious user controls the input. Use these functions to implement SNPRINTF(). Cc: Samanta Navarro <ferivoz@riseup.net> Signed-off-by: Alejandro Colomar <alx@kernel.org>
98 lines
1.7 KiB
C
98 lines
1.7 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2023, Alejandro Colomar <alx@kernel.org>
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
|
|
#ifndef SHADOW_INCLUDE_LIB_SPRINTF_H_
|
|
#define SHADOW_INCLUDE_LIB_SPRINTF_H_
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
|
|
#include "attr.h"
|
|
#include "defines.h"
|
|
#include "sizeof.h"
|
|
|
|
|
|
#define SNPRINTF(s, fmt, ...) \
|
|
snprintf_(s, NITEMS(s), fmt __VA_OPT__(,) __VA_ARGS__)
|
|
|
|
|
|
format_attr(printf, 2, 3)
|
|
inline int xasprintf(char **restrict s, const char *restrict fmt, ...);
|
|
format_attr(printf, 2, 0)
|
|
inline int xvasprintf(char **restrict s, const char *restrict fmt, va_list ap);
|
|
|
|
format_attr(printf, 3, 4)
|
|
inline int snprintf_(char *restrict s, size_t size, const char *restrict fmt,
|
|
...);
|
|
format_attr(printf, 3, 0)
|
|
inline int vsnprintf_(char *restrict s, size_t size, const char *restrict fmt,
|
|
va_list ap);
|
|
|
|
|
|
inline int
|
|
xasprintf(char **restrict s, const char *restrict fmt, ...)
|
|
{
|
|
int len;
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
len = xvasprintf(s, fmt, ap);
|
|
va_end(ap);
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
inline int
|
|
xvasprintf(char **restrict s, const char *restrict fmt, va_list ap)
|
|
{
|
|
int len;
|
|
|
|
len = vasprintf(s, fmt, ap);
|
|
if (len == -1) {
|
|
perror("asprintf");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
inline int
|
|
snprintf_(char *restrict s, size_t size, const char *restrict fmt, ...)
|
|
{
|
|
int len;
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
len = vsnprintf_(s, size, fmt, ap);
|
|
va_end(ap);
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
inline int
|
|
vsnprintf_(char *restrict s, size_t size, const char *restrict fmt, va_list ap)
|
|
{
|
|
int len;
|
|
|
|
len = vsnprintf(s, size, fmt, ap);
|
|
if (len == -1)
|
|
return -1;
|
|
if ((size_t) len >= size)
|
|
return -1;
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
#endif // include guard
|