mirror of
https://github.com/morgan9e/systemd
synced 2026-04-15 08:56:15 +09:00
as per docs snprintf() can fail in which case it returns -1. The snprintf_ok() macro so far unconditionally cast the return value of snprintf() to size_t, which would turn -1 to (size_t) INT_MAX, presumably, at least on 2 complements system. Let's be more careful with types here, and first check if return value is positive, before casting to size_t. Also, while we are at it, let's return the input buffer as return value or NULL instead of 1 or 0. It's marginally more useful, but more importantly, is more inline with most of our other codebase that typically doesn't use booleans to signal success. All uses of snprintf_ok() don't care for the type of the return, hence this change does not propagate anywhere else.
70 lines
4.1 KiB
C
70 lines
4.1 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
#pragma once
|
|
|
|
#include <printf.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
|
|
#include "macro.h"
|
|
#include "memory-util.h"
|
|
|
|
#define snprintf_ok(buf, len, fmt, ...) \
|
|
({ \
|
|
char *_buf = (buf); \
|
|
size_t _len = (len); \
|
|
int _snpf = snprintf(_buf, _len, (fmt), __VA_ARGS__); \
|
|
_snpf >= 0 && (size_t) _snpf < _len ? _buf : NULL; \
|
|
})
|
|
|
|
#define xsprintf(buf, fmt, ...) \
|
|
assert_message_se(snprintf_ok(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__), "xsprintf: " #buf "[] must be big enough")
|
|
|
|
#define VA_FORMAT_ADVANCE(format, ap) \
|
|
do { \
|
|
int _argtypes[128]; \
|
|
size_t _i, _k; \
|
|
/* See https://github.com/google/sanitizers/issues/992 */ \
|
|
if (HAS_FEATURE_MEMORY_SANITIZER) \
|
|
zero(_argtypes); \
|
|
_k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \
|
|
assert(_k < ELEMENTSOF(_argtypes)); \
|
|
for (_i = 0; _i < _k; _i++) { \
|
|
if (_argtypes[_i] & PA_FLAG_PTR) { \
|
|
(void) va_arg(ap, void*); \
|
|
continue; \
|
|
} \
|
|
\
|
|
switch (_argtypes[_i]) { \
|
|
case PA_INT: \
|
|
case PA_INT|PA_FLAG_SHORT: \
|
|
case PA_CHAR: \
|
|
(void) va_arg(ap, int); \
|
|
break; \
|
|
case PA_INT|PA_FLAG_LONG: \
|
|
(void) va_arg(ap, long int); \
|
|
break; \
|
|
case PA_INT|PA_FLAG_LONG_LONG: \
|
|
(void) va_arg(ap, long long int); \
|
|
break; \
|
|
case PA_WCHAR: \
|
|
(void) va_arg(ap, wchar_t); \
|
|
break; \
|
|
case PA_WSTRING: \
|
|
case PA_STRING: \
|
|
case PA_POINTER: \
|
|
(void) va_arg(ap, void*); \
|
|
break; \
|
|
case PA_FLOAT: \
|
|
case PA_DOUBLE: \
|
|
(void) va_arg(ap, double); \
|
|
break; \
|
|
case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \
|
|
(void) va_arg(ap, long double); \
|
|
break; \
|
|
default: \
|
|
assert_not_reached(); \
|
|
} \
|
|
} \
|
|
} while (false)
|