Fix various memory management issues
authorMatthias Schiffer <mschiffer@universe-factory.net>
Tue, 21 Jun 2016 15:19:10 +0000 (17:19 +0200)
committerFelix Fietkau <nbd@nbd.name>
Sun, 26 Jun 2016 10:53:51 +0000 (12:53 +0200)
Consistently handle allocation failures. Some functions are changed to
return bool or int instead of void to allow returning an error.

Also fix a buffer size miscalculation in lua/uloop and use _exit() instead
of exit() on errors after forking.

Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
blobmsg.c
blobmsg.h
blobmsg_json.c
jshn.c
json_script.c
kvlist.c
kvlist.h
lua/uloop.c
ustream.c
utils.c

index 80b984a133cd52f0d3a5fefe33de4e9739d99e71..1e93376a27b65cf816f94f87738b98e8bb497ef6 100644 (file)
--- a/blobmsg.c
+++ b/blobmsg.c
@@ -227,29 +227,38 @@ blobmsg_open_nested(struct blob_buf *buf, const char *name, bool array)
        return (void *)offset;
 }
 
-void
+int
 blobmsg_vprintf(struct blob_buf *buf, const char *name, const char *format, va_list arg)
 {
        va_list arg2;
        char cbuf;
-       int len;
+       char *sbuf;
+       int len, ret;
 
        va_copy(arg2, arg);
        len = vsnprintf(&cbuf, sizeof(cbuf), format, arg2);
        va_end(arg2);
 
-       vsprintf(blobmsg_alloc_string_buffer(buf, name, len + 1), format, arg);
+       sbuf = blobmsg_alloc_string_buffer(buf, name, len + 1);
+       if (!sbuf)
+               return -1;
+       ret = vsprintf(sbuf, format, arg);
        blobmsg_add_string_buffer(buf);
+
+       return ret;
 }
 
-void
+int
 blobmsg_printf(struct blob_buf *buf, const char *name, const char *format, ...)
 {
        va_list ap;
+       int ret;
 
        va_start(ap, format);
-       blobmsg_vprintf(buf, name, format, ap);
+       ret = blobmsg_vprintf(buf, name, format, ap);
        va_end(ap);
+
+       return ret;
 }
 
 void *
@@ -278,7 +287,8 @@ blobmsg_realloc_string_buffer(struct blob_buf *buf, unsigned int maxlen)
        if (required <= 0)
                goto out;
 
-       blob_buf_grow(buf, required);
+       if (!blob_buf_grow(buf, required))
+               return NULL;
        attr = blob_next(buf->head);
 
 out:
index e58f95deb6be700c501fdfb2b8b604df459db47b..84997a67ab5bc347dab0bd0a741bd0fd98ecddb5 100644 (file)
--- a/blobmsg.h
+++ b/blobmsg.h
@@ -224,8 +224,8 @@ void *blobmsg_alloc_string_buffer(struct blob_buf *buf, const char *name, unsign
 void *blobmsg_realloc_string_buffer(struct blob_buf *buf, unsigned int maxlen);
 void blobmsg_add_string_buffer(struct blob_buf *buf);
 
-void blobmsg_vprintf(struct blob_buf *buf, const char *name, const char *format, va_list arg);
-void blobmsg_printf(struct blob_buf *buf, const char *name, const char *format, ...)
+int blobmsg_vprintf(struct blob_buf *buf, const char *name, const char *format, va_list arg);
+int blobmsg_printf(struct blob_buf *buf, const char *name, const char *format, ...)
      __attribute__((format(printf, 3, 4)));
 
 
index 571394840181e1453deb67aa5e9045c0f868f61a..2e318b2fcc96619cf0b5c032fcb460a97c5dfb6c 100644 (file)
@@ -119,15 +119,22 @@ struct strbuf {
 
 static bool blobmsg_puts(struct strbuf *s, const char *c, int len)
 {
+       size_t new_len;
+       char *new_buf;
+
        if (len <= 0)
                return true;
 
        if (s->pos + len >= s->len) {
-               s->len += 16 + len;
-               s->buf = realloc(s->buf, s->len);
-               if (!s->buf)
+               new_len = s->len + 16 + len;
+               new_buf = realloc(s->buf, new_len);
+               if (!new_buf)
                        return false;
+
+               s->len = new_len;
+               s->buf = new_buf;
        }
+
        memcpy(s->buf + s->pos, c, len);
        s->pos += len;
        return true;
@@ -290,14 +297,18 @@ char *blobmsg_format_json_with_cb(struct blob_attr *attr, bool list, blobmsg_jso
 {
        struct strbuf s;
        bool array;
+       char *ret;
 
        s.len = blob_len(attr);
-       s.buf = malloc(s.len);
        s.pos = 0;
        s.custom_format = cb;
        s.priv = priv;
        s.indent = false;
 
+       s.buf = malloc(s.len);
+       if (!s.buf)
+               return NULL;
+
        if (indent >= 0) {
                s.indent = true;
                s.indent_level = indent;
@@ -316,8 +327,13 @@ char *blobmsg_format_json_with_cb(struct blob_attr *attr, bool list, blobmsg_jso
                return NULL;
        }
 
-       s.buf = realloc(s.buf, s.pos + 1);
-       s.buf[s.pos] = 0;
+       ret = realloc(s.buf, s.pos + 1);
+       if (!ret) {
+               free(s.buf);
+               return NULL;
+       }
+
+       ret[s.pos] = 0;
 
-       return s.buf;
+       return ret;
 }
diff --git a/jshn.c b/jshn.c
index e2d90220335c6bbc505dd4de4bd26477abb0e752..4989099484be94b8205612a3bbb70983f87c0528 100644 (file)
--- a/jshn.c
+++ b/jshn.c
@@ -338,6 +338,10 @@ int main(int argc, char **argv)
        for (i = 0; environ[i]; i++);
 
        vars = calloc(i, sizeof(*vars));
+       if (!vars) {
+               fprintf(stderr, "%m\n");
+               return -1;
+       }
        for (i = 0; environ[i]; i++) {
                char *c;
 
index b5d414d7e83c2f7a6b39b377558dca69a9599841..463aac88dee42cef14e848f878a0548c96c0134d 100644 (file)
@@ -45,6 +45,9 @@ json_script_file_from_blobmsg(const char *name, void *data, int len)
                name_len = strlen(name) + 1;
 
        f = calloc_a(sizeof(*f) + len, &new_name, name_len);
+       if (!f)
+               return NULL;
+
        memcpy(f->data, data, len);
        if (name)
                f->avl.key = strcpy(new_name, name);
@@ -426,12 +429,15 @@ static int eval_string(struct json_call *call, struct blob_buf *buf, const char
        char c = '%';
 
        dest = blobmsg_alloc_string_buffer(buf, name, 1);
+       if (!dest)
+               return -1;
+
        next = alloca(strlen(pattern) + 1);
        strcpy(next, pattern);
 
        for (str = next; str; str = next) {
                const char *cur;
-               char *end;
+               char *end, *new_buf;
                int cur_len = 0;
                bool cur_var = var;
 
@@ -464,7 +470,14 @@ static int eval_string(struct json_call *call, struct blob_buf *buf, const char
                        cur_len = end - str;
                }
 
-               dest = blobmsg_realloc_string_buffer(buf, len + cur_len + 1);
+               new_buf = blobmsg_realloc_string_buffer(buf, len + cur_len + 1);
+               if (!new_buf) {
+                       /* Make eval_string return -1 */
+                       var = true;
+                       break;
+               }
+
+               dest = new_buf;
                memcpy(dest + len, cur, cur_len);
                len += cur_len;
        }
index e0a8acb0025e77ce56338648dbd2ece5f0e906b2..a7b6ea07240eed51769d79d1a59c8b424ec65eea 100644 (file)
--- a/kvlist.c
+++ b/kvlist.c
@@ -71,20 +71,25 @@ bool kvlist_delete(struct kvlist *kv, const char *name)
        return !!node;
 }
 
-void kvlist_set(struct kvlist *kv, const char *name, const void *data)
+bool kvlist_set(struct kvlist *kv, const char *name, const void *data)
 {
        struct kvlist_node *node;
        char *name_buf;
        int len = kv->get_len(kv, data);
 
-       kvlist_delete(kv, name);
-
        node = calloc_a(sizeof(struct kvlist_node) + len,
                &name_buf, strlen(name) + 1);
+       if (!node)
+               return false;
+
+       kvlist_delete(kv, name);
+
        memcpy(node->data, data, len);
 
        node->avl.key = strcpy(name_buf, name);
        avl_insert(&kv->avl, &node->avl);
+
+       return true;
 }
 
 void kvlist_free(struct kvlist *kv)
index 0d35b46a5f695cf629a9296f399e6fcd97b5639b..d59ff9e07227d58c4125e46b661e80c827b6b0c2 100644 (file)
--- a/kvlist.h
+++ b/kvlist.h
@@ -45,7 +45,7 @@ struct kvlist_node {
 void kvlist_init(struct kvlist *kv, int (*get_len)(struct kvlist *kv, const void *data));
 void kvlist_free(struct kvlist *kv);
 void *kvlist_get(struct kvlist *kv, const char *name);
-void kvlist_set(struct kvlist *kv, const char *name, const void *data);
+bool kvlist_set(struct kvlist *kv, const char *name, const void *data);
 bool kvlist_delete(struct kvlist *kv, const char *name);
 
 int kvlist_strlen(struct kvlist *kv, const void *data);
index 782b5a51b5fbc5a583c63d8193f8a1725738221c..c5dd12f027c9b008619f46a2fd52ce7c9d13bbb4 100644 (file)
@@ -325,9 +325,12 @@ static int ul_process(lua_State *L)
                int argn = lua_objlen(L, -3);
                int envn = lua_objlen(L, -2);
                char** argp = malloc(sizeof(char*) * (argn + 2));
-               char** envp = malloc(sizeof(char*) * envn + 1);
+               char** envp = malloc(sizeof(char*) * (envn + 1));
                int i = 1;
 
+               if (!argp || !envp)
+                       _exit(-1);
+
                argp[0] = (char*) lua_tostring(L, -4);
                for (i = 1; i <= argn; i++) {
                        lua_rawgeti(L, -3, i);
@@ -344,7 +347,7 @@ static int ul_process(lua_State *L)
                envp[i - 1] = NULL;
 
                execve(*argp, argp, envp);
-               exit(-1);
+               _exit(-1);
        }
 
        lua_getglobal(L, "__uloop_cb");
index e7ee9f07c5952057bb2bc558ae9330af180bc753..d36ce080ec10067cd8f25d52d0da72285e1048eb 100644 (file)
--- a/ustream.c
+++ b/ustream.c
@@ -65,6 +65,9 @@ static int ustream_alloc_default(struct ustream *s, struct ustream_buf_list *l)
                return -1;
 
        buf = malloc(sizeof(*buf) + l->buffer_len + s->string_data);
+       if (!buf)
+               return -1;
+
        ustream_init_buf(buf, l->buffer_len);
        ustream_add_buf(l, buf);
 
@@ -490,6 +493,8 @@ int ustream_vprintf(struct ustream *s, const char *format, va_list arg)
                        return ustream_write_buffered(s, buf, maxlen, wr);
                } else {
                        buf = malloc(maxlen + 1);
+                       if (!buf)
+                               return 0;
                        wr = vsnprintf(buf, maxlen + 1, format, arg);
                        wr = ustream_write(s, buf, wr, false);
                        free(buf);
@@ -517,6 +522,8 @@ int ustream_vprintf(struct ustream *s, const char *format, va_list arg)
                return wr;
 
        buf = malloc(maxlen + 1);
+       if (!buf)
+               return wr;
        maxlen = vsnprintf(buf, maxlen + 1, format, arg);
        wr = ustream_write_buffered(s, buf + wr, maxlen - wr, wr);
        free(buf);
diff --git a/utils.c b/utils.c
index 8fd19f47b01898227b08b00ec66efadb40f9ea92..91dd71e6c18dd67dcb5b24a6a93ab88dfa9d887d 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -43,6 +43,8 @@ void *__calloc_a(size_t len, ...)
        va_end(ap1);
 
        ptr = calloc(1, alloc_len);
+       if (!ptr)
+               return NULL;
        alloc_len = 0;
        foreach_arg(ap, cur_addr, cur_len, &ret, len) {
                *cur_addr = &ptr[alloc_len];