log: fix repeated invocation of vsnprintf()/vaprintf() in log_struct()
https://bugs.freedesktop.org/show_bug.cgi?id=55213
This commit is contained in:
+20
-2
@@ -27,6 +27,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <stddef.h>
|
||||
#include <printf.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
@@ -705,11 +706,23 @@ int log_struct_internal(
|
||||
va_start(ap, format);
|
||||
while (format && n + 1 < ELEMENTSOF(iovec)) {
|
||||
char *buf;
|
||||
va_list aq;
|
||||
|
||||
if (vasprintf(&buf, format, ap) < 0) {
|
||||
/* We need to copy the va_list structure,
|
||||
* since vasprintf() leaves it afterwards at
|
||||
* an undefined location */
|
||||
|
||||
va_copy(aq, ap);
|
||||
if (vasprintf(&buf, format, aq) < 0) {
|
||||
va_end(aq);
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
va_end(aq);
|
||||
|
||||
/* Now, jump enough ahead, so that we point to
|
||||
* the next format string */
|
||||
VA_FORMAT_ADVANCE(format, ap);
|
||||
|
||||
IOVEC_SET_STRING(iovec[n++], buf);
|
||||
|
||||
@@ -742,8 +755,11 @@ int log_struct_internal(
|
||||
|
||||
va_start(ap, format);
|
||||
while (format) {
|
||||
va_list aq;
|
||||
|
||||
vsnprintf(buf, sizeof(buf), format, ap);
|
||||
va_copy(aq, ap);
|
||||
vsnprintf(buf, sizeof(buf), format, aq);
|
||||
va_end(aq);
|
||||
char_array_0(buf);
|
||||
|
||||
if (startswith(buf, "MESSAGE=")) {
|
||||
@@ -751,6 +767,8 @@ int log_struct_internal(
|
||||
break;
|
||||
}
|
||||
|
||||
VA_FORMAT_ADVANCE(format, ap);
|
||||
|
||||
format = va_arg(ap, char *);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
@@ -193,4 +193,47 @@ static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) {
|
||||
#define _cleanup_closedir_ __attribute__((cleanup(closedirp)))
|
||||
#define _cleanup_umask_ __attribute__((cleanup(umaskp)))
|
||||
|
||||
#define VA_FORMAT_ADVANCE(format, ap) do { \
|
||||
int _argtypes[64]; \
|
||||
size_t _i, _k; \
|
||||
_k = parse_printf_format((format), ELEMENTSOF(_argtypes), _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("Unknown format string argument."); \
|
||||
} \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
#include "log.h"
|
||||
|
||||
Reference in New Issue
Block a user