]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
Fix abuse of realloc() causing memory leaks
authorDavid Woodhouse <David.Woodhouse@intel.com>
Mon, 18 Feb 2013 00:31:57 +0000 (00:31 +0000)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Mon, 18 Feb 2013 00:32:00 +0000 (00:32 +0000)
Implement a helper which actually *does* free the original pointer on
allocation failure, as I evidently always expected it to.

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=700805

Reported by: Niels Thykier <niels@thykier.net>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
auth.c
compat.c
http.c
openconnect-internal.h

diff --git a/auth.c b/auth.c
index da0c029402209208f84744f39110a96d0362619b..361f656ce8e90cd13b76bd1430aa2e63c5f0d8e7 100644 (file)
--- a/auth.c
+++ b/auth.c
@@ -150,8 +150,8 @@ static int parse_auth_choice(struct openconnect_info *vpninfo, struct oc_auth_fo
                        continue;
 
                opt->nr_choices++;
-               opt = realloc(opt, sizeof(*opt) +
-                                  opt->nr_choices * sizeof(*choice));
+               realloc_inplace(opt, sizeof(*opt) +
+                               opt->nr_choices * sizeof(*choice));
                if (!opt)
                        return -ENOMEM;
 
index da59d3592cc907be286b2ac0ec98ee20327dad49..d728c94c582f7a9209215becbfba24517764f028 100644 (file)
--- a/compat.c
+++ b/compat.c
@@ -131,7 +131,7 @@ ssize_t openconnect__getline(char **lineptr, size_t *n, FILE *stream)
                        break;
 
                *n *= 2;
-               *lineptr = realloc(*lineptr, *n);
+               realloc_inplace(*lineptr, *n);
                if (!*lineptr)
                        return -1;
        }
diff --git a/http.c b/http.c
index d6a3636cf8cbd1bf08120855744e3f56a89d018a..9b77be58b330d8986e9d597ae1c949d280b7f227 100644 (file)
--- a/http.c
+++ b/http.c
@@ -96,7 +96,7 @@ static void buf_append(struct oc_text_buf *buf, const char *fmt, ...)
                                break;
                        }
 
-                       buf->data = realloc(buf->data, new_buf_len);
+                       realloc_inplace(buf->data, new_buf_len);
                        if (!buf->data) {
                                buf->error = -ENOMEM;
                                break;
@@ -353,7 +353,7 @@ static int process_http_response(struct openconnect_info *vpninfo, int *result,
                                lastchunk = 1;
                                goto skip;
                        }
-                       body = realloc(body, done + chunklen + 1);
+                       realloc_inplace(body, done + chunklen + 1);
                        if (!body)
                                return -ENOMEM;
                        while (chunklen) {
@@ -394,7 +394,7 @@ static int process_http_response(struct openconnect_info *vpninfo, int *result,
 
                /* HTTP 1.0 response. Just eat all we can in 16KiB chunks */
                while (1) {
-                       body = realloc(body, done + 16384);
+                       realloc_inplace(body, done + 16384);
                        if (!body)
                                return -ENOMEM;
                        i = openconnect_SSL_read(vpninfo, body + done, 16384);
@@ -407,7 +407,7 @@ static int process_http_response(struct openconnect_info *vpninfo, int *result,
                                return i;
                        } else {
                                /* Connection closed. Reduce allocation to just what we need */
-                               body = realloc(body, done + 1);
+                               realloc_inplace(body, done + 1);
                                if (!body)
                                        return -ENOMEM;
                                break;
index 4b4c4550b1704217f54d518dd15f349e37e3bf01..ff1b80bfedbcea99ca6b3d638274c1bc5f2e0509 100644 (file)
@@ -347,6 +347,14 @@ ssize_t openconnect__getline(char **lineptr, size_t *n, FILE *stream);
 char *openconnect__strcasestr(const char *haystack, const char *needle);
 #endif
 
+/* I always coded as if it worked like this. Now it does. */
+#define realloc_inplace(p, size) do {                  \
+       void *__realloc_old = p;                        \
+       p = realloc(p, size);                           \
+       if (size && !p)                                 \
+               free(__realloc_old);                    \
+    } while (0)
+
 /****************************************************************************/
 
 /* tun.c */