summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorGergely Nagy <algernon@balabit.hu>2012-04-08 11:04:59 +0200
committerGergely Nagy <algernon@balabit.hu>2012-04-08 11:04:59 +0200
commit5de1bdf4c0b6f8f5d064c27ba8298019b295e970 (patch)
tree9af764fda9e59862bb178bce2aeae40aacee5e17 /lib
parentbe6c6fb1b7e169f8e643e45409efbee1241954c0 (diff)
downloadlibumberlog-5de1bdf4c0b6f8f5d064c27ba8298019b295e970.tar.gz
libumberlog-5de1bdf4c0b6f8f5d064c27ba8298019b295e970.tar.xz
libumberlog-5de1bdf4c0b6f8f5d064c27ba8298019b295e970.zip
Properly handle va_lists, by copying.
Up until now, the library abused that passing va_list around without copying works on various architectures. On others, that does not. To remedy the issue, the library now parses format strings itself, and copies va_list. This makes it work on all architectures, independent on the internal implementation of va_list, and preserves both API and ABI. Signed-off-by: Gergely Nagy <algernon@balabit.hu>
Diffstat (limited to 'lib')
-rw-r--r--lib/umberlog.c101
1 files changed, 97 insertions, 4 deletions
diff --git a/lib/umberlog.c b/lib/umberlog.c
index ac810f8..78697c6 100644
--- a/lib/umberlog.c
+++ b/lib/umberlog.c
@@ -40,6 +40,7 @@
#include <limits.h>
#include <time.h>
#include <errno.h>
+#include <wchar.h>
#include "config.h"
#include "umberlog.h"
@@ -156,6 +157,80 @@ _get_hostname (void)
return ul_sys_settings.hostname;
}
+#define _ul_va_spin(fmt,ap) \
+ { \
+ size_t i; \
+ \
+ for (i = 0; i < strlen (fmt); i++) \
+ { \
+ int eof = 0; \
+ \
+ if (fmt[i] != '%') \
+ continue; \
+ i++; \
+ while (eof != 1) \
+ { \
+ switch (fmt[i]) \
+ { \
+ case 'd': \
+ case 'i': \
+ case 'o': \
+ case 'u': \
+ case 'x': \
+ case 'X': \
+ if (fmt[i - 1] == 'l') \
+ { \
+ if (i - 2 > 0 && fmt[i - 2] == 'l') \
+ (void)va_arg (ap, long long int); \
+ else \
+ (void)va_arg (ap, long int); \
+ } \
+ else \
+ (void)va_arg (ap, int); \
+ eof = 1; \
+ break; \
+ case 'e': \
+ case 'E': \
+ case 'f': \
+ case 'F': \
+ case 'g': \
+ case 'G': \
+ case 'a': \
+ case 'A': \
+ if (fmt[i - 1] == 'L') \
+ (void)va_arg (ap, long double); \
+ else \
+ (void)va_arg (ap, double); \
+ eof = 1; \
+ break; \
+ case 'c': \
+ if (fmt [i - 1] == 'l') \
+ (void)va_arg (ap, wint_t); \
+ else \
+ (void)va_arg (ap, int); \
+ eof = 1; \
+ break; \
+ case 's': \
+ if (fmt [i - 1] == 'l') \
+ (void)va_arg (ap, wchar_t *); \
+ else \
+ (void)va_arg (ap, char *); \
+ eof = 1; \
+ break; \
+ case 'p': \
+ (void)va_arg (ap, void *); \
+ eof = 1; \
+ break; \
+ case '%': \
+ eof = 1; \
+ break; \
+ default: \
+ i++; \
+ } \
+ } \
+ } \
+ }
+
static inline struct json_object *
_ul_json_vappend (struct json_object *json, va_list ap)
{
@@ -166,9 +241,16 @@ _ul_json_vappend (struct json_object *json, va_list ap)
char *fmt = (char *)va_arg (ap, char *);
char *value = NULL;
struct json_object *jstr;
+ va_list aq;
+
+ va_copy (aq, ap);
+ if (vasprintf (&value, fmt, aq) == -1)
+ {
+ va_end (aq);
+ return NULL;
+ }
+ va_end (aq);
- if (vasprintf (&value, fmt, ap) == -1)
- return NULL;
if (!value)
return NULL;
@@ -181,7 +263,10 @@ _ul_json_vappend (struct json_object *json, va_list ap)
json_object_object_add (json, key, jstr);
free (value);
+
+ _ul_va_spin (fmt, ap);
}
+
return json;
}
@@ -245,9 +330,15 @@ _ul_vformat (struct json_object *jo, int format_version,
{
char *value;
struct json_object *jstr;
+ va_list aq;
- if (vasprintf (&value, msg_format, ap) == -1)
- return NULL;
+ va_copy (aq, ap);
+ if (vasprintf (&value, msg_format, aq) == -1)
+ {
+ va_end (aq);
+ return NULL;
+ }
+ va_end (aq);
if (!value)
return NULL;
@@ -261,6 +352,8 @@ _ul_vformat (struct json_object *jo, int format_version,
json_object_object_add (jo, "msg", jstr);
free (value);
+ _ul_va_spin (msg_format, ap);
+
if (format_version > 0)
jo = _ul_json_vappend (jo, ap);