[systemd-devel] [PATCH] journal: get rid of LINE_MAX in sd_journal_printv*()

harald at redhat.com harald at redhat.com
Mon Apr 15 07:12:51 PDT 2013


From: Harald Hoyer <harald at redhat.com>

use stack_size_guess() to get rid of LINE_MAX
---
 src/journal/journal-send.c      | 99 +++++++++++++++++++++++++++++++----------
 src/journal/test-journal-send.c | 92 +++++++++++++++++++++++++++++++++-----
 2 files changed, 156 insertions(+), 35 deletions(-)

diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c
index 4b9109a..2ff04b4 100644
--- a/src/journal/journal-send.c
+++ b/src/journal/journal-send.c
@@ -26,6 +26,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <printf.h>
+#include <sys/resource.h>
 
 #define SD_JOURNAL_SUPPRESS_LOCATION
 
@@ -35,15 +36,17 @@
 
 #define SNDBUF_SIZE (8*1024*1024)
 
-#define ALLOCA_CODE_FUNC(f, func)                 \
-        do {                                      \
-                size_t _fl;                       \
-                const char *_func = (func);       \
-                char **_f = &(f);                 \
-                _fl = strlen(_func) + 1;          \
-                *_f = alloca(_fl + 10);           \
-                memcpy(*_f, "CODE_FUNC=", 10);    \
-                memcpy(*_f + 10, _func, _fl);     \
+#define ALLOCA_CODE_FUNC(f, func)                    \
+        do {                                         \
+                size_t _fl;                          \
+                const char *_func = (func);          \
+                char **_f = &(f);                    \
+                _fl = strlen(_func) + 1;             \
+                if (stack_size_guess() < (_fl + 10)) \
+                        return -ENOMEM;              \
+                *_f = alloca(_fl + 10);              \
+                memcpy(*_f, "CODE_FUNC=", 10);       \
+                memcpy(*_f + 10, _func, _fl);        \
         } while(false)
 
 /* We open a single fd, and we'll share it with the current process,
@@ -85,11 +88,9 @@ _public_ int sd_journal_print(int priority, const char *format, ...) {
 }
 
 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
-
-        /* FIXME: Instead of limiting things to LINE_MAX we could do a
-           C99 variable-length array on the stack here in a loop. */
-
-        char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2];
+        char p[11], *buffer; struct iovec iov[2];
+        int len = 0;
+        rlim_t sts = RLIM_INFINITY;
 
         if (priority < 0 || priority > 7)
                 return -EINVAL;
@@ -97,12 +98,37 @@ _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
         if (!format)
                 return -EINVAL;
 
-        snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
-        char_array_0(p);
+        {
+                va_list aq;
+                va_copy(aq, ap);
+                len = vsnprintf(NULL, 0, format, aq);
+                va_end(aq);
+        }
+        if (len <= 0)
+                return -EINVAL;
+
+        sts = stack_size_guess();
+
+        /* Limit the maximum size to the send buffer minus some
+           bytes for the rest
+        */
+        if (sts == RLIM_INFINITY)
+                sts = SNDBUF_SIZE - 1024;
+
+        /* Spare at least one page_size of stack */
+        if (sts < (unsigned)(len + page_size()))
+                len = sts - page_size();
+
+        if (len < 0)
+                return -ENOMEM;
+
+        buffer = alloca(len + 9);
 
         memcpy(buffer, "MESSAGE=", 8);
-        vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
-        char_array_0(buffer);
+        vsnprintf(buffer+8, len+1, format, ap);
+
+        snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
+        char_array_0(p);
 
         zero(iov);
         IOVEC_SET_STRING(iov[0], buffer);
@@ -478,9 +504,11 @@ _public_ int sd_journal_print_with_location(int priority, const char *file, cons
 }
 
 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
-        char buffer[8 + LINE_MAX], p[11];
+        char p[11], *buffer = NULL;
         struct iovec iov[5];
         char *f;
+        int len = 0;
+        rlim_t sts = RLIM_INFINITY;
 
         if (priority < 0 || priority > 7)
                 return -EINVAL;
@@ -488,12 +516,37 @@ _public_ int sd_journal_printv_with_location(int priority, const char *file, con
         if (_unlikely_(!format))
                 return -EINVAL;
 
-        snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
-        char_array_0(p);
+        {
+                va_list aq;
+                va_copy(aq, ap);
+                len = vsnprintf(NULL, 0, format, aq);
+                va_end(aq);
+        }
+        if (len <= 0)
+                return -EINVAL;
+
+        sts = stack_size_guess();
+
+        /* Limit the maximum size to the send buffer minus some
+           bytes for the rest
+        */
+        if (sts == RLIM_INFINITY)
+                sts = SNDBUF_SIZE - 1024;
+
+        /* Spare at least one page_size of stack */
+        if (sts < (unsigned)(len + page_size()))
+                len = sts - page_size();
+
+        if (len < 0)
+                return -ENOMEM;
+
+        buffer = alloca(len + 9);
 
         memcpy(buffer, "MESSAGE=", 8);
-        vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
-        char_array_0(buffer);
+        vsnprintf(buffer+8, len+1, format, ap);
+
+        snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
+        char_array_0(p);
 
         /* func is initialized from __func__ which is not a macro, but
          * a static const char[], hence cannot easily be prefixed with
diff --git a/src/journal/test-journal-send.c b/src/journal/test-journal-send.c
index 3e986ed..b2ff422 100644
--- a/src/journal/test-journal-send.c
+++ b/src/journal/test-journal-send.c
@@ -22,34 +22,66 @@
 #include <systemd/sd-journal.h>
 #include <stdlib.h>
 #include <unistd.h>
-
+#include <stdio.h>
+#include <sys/resource.h>
 #include "log.h"
 
+#define HUGE_SIZE (4096*1024)
+
+static int huge_message_send(void)
+{
+        char *huge;
+        int r;
+        int asz = random() % (long int)sysconf(_SC_PAGESIZE);
+        huge = alloca(asz);
+        memset(huge, 'x', asz-1);
+        huge[asz-1] = 0;
+        r = sd_journal_print(LOG_NOTICE, "huge_message_send: %s", huge);
+        if (r)
+                return r;
+
+        r = huge_message_send();
+        return r;
+}
+
+
 int main(int argc, char *argv[]) {
-        char huge[4096*1024];
+        int r;
+        char huge[HUGE_SIZE];
+        struct rlimit rlim;
 
         log_set_max_level(LOG_DEBUG);
 
-        sd_journal_print(LOG_INFO, "piepapo");
+        r = sd_journal_print(LOG_INFO, "piepapo");
+        if (r != 0)
+                return 1;
 
-        sd_journal_send("MESSAGE=foobar",
+        r = sd_journal_send("MESSAGE=foobar",
                         "VALUE=%i", 7,
                         NULL);
+        if (r != 0)
+                return 1;
 
         errno = ENOENT;
-        sd_journal_perror("Foobar");
+        r = sd_journal_perror("Foobar");
+        if (r != 0)
+                return 1;
 
-        sd_journal_perror("");
+        r = sd_journal_perror("");
+        if (r != 0)
+                return 1;
 
         memset(huge, 'x', sizeof(huge));
         memcpy(huge, "HUGE=", 5);
         char_array_0(huge);
 
-        sd_journal_send("MESSAGE=Huge field attached",
+        r = sd_journal_send("MESSAGE=Huge field attached",
                         huge,
                         NULL);
+        if (r != 0)
+                return 1;
 
-        sd_journal_send("MESSAGE=uiui",
+        r = sd_journal_send("MESSAGE=uiui",
                         "VALUE=A",
                         "VALUE=B",
                         "VALUE=C",
@@ -58,12 +90,16 @@ int main(int argc, char *argv[]) {
                         "OTHERVALUE=Y",
                         "WITH_BINARY=this is a binary value \a",
                         NULL);
+        if (r != 0)
+                return 1;
 
         syslog(LOG_NOTICE, "Hello World!");
 
-        sd_journal_print(LOG_NOTICE, "Hello World");
+        r = sd_journal_print(LOG_NOTICE, "Hello World!");
+        if (r != 0)
+                return 1;
 
-        sd_journal_send("MESSAGE=Hello World!",
+        r = sd_journal_send("MESSAGE=Hello World!",
                         "MESSAGE_ID=52fb62f99e2c49d89cfbf9d6de5e3555",
                         "PRIORITY=5",
                         "HOME=%s", getenv("HOME"),
@@ -71,8 +107,40 @@ int main(int argc, char *argv[]) {
                         "PAGE_SIZE=%li", sysconf(_SC_PAGESIZE),
                         "N_CPUS=%li", sysconf(_SC_NPROCESSORS_ONLN),
                         NULL);
-
-        sleep(10);
+        if (r != 0)
+                return 1;
+
+        r = sd_journal_print(LOG_NOTICE, "huge string: %s", huge);
+        if (r != 0)
+                return 1;
+
+        r = getrlimit(RLIMIT_STACK, &rlim);
+        if (r) {
+                perror("getrlimit");
+                return 1;
+        }
+
+        rlim.rlim_cur = (rlim_t)sysconf(_SC_PAGESIZE) * 100;
+        r = setrlimit(RLIMIT_STACK, &rlim);
+        if (r) {
+                perror("setrlimit");
+                return 1;
+        }
+
+        r = sd_journal_print(LOG_NOTICE, "huge string: %s", huge);
+        if (r != -ENOMEM)
+                return 1;
+
+        rlim.rlim_cur = (rlim_t)sysconf(_SC_PAGESIZE) * 100 + HUGE_SIZE;
+        r = setrlimit(RLIMIT_STACK, &rlim);
+        if (r) {
+                perror("setrlimit");
+                return 1;
+        }
+
+        r = huge_message_send();
+        if (r != -ENOMEM)
+                return 1;
 
         return 0;
 }
-- 
1.8.2



More information about the systemd-devel mailing list