aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2023-03-04 02:06:19 +0100
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2023-07-20 23:52:51 +0200
commit67ffb772b7488b84e37e6880290820fc54434b33 (patch)
tree574f95ad5834282261846daede1f653b1d1d0666
parent37fd5c92aebd87af14a1f73f8e567b8b74f6bd36 (diff)
Fix memory leak on failed realloc(3)
According to C99 ยง7.20.3.4: If memory for the new object cannot be allocated, the old object is not deallocated and its value is unchanged. Therefore, a temporary pointer must be used to ensure the original object can still be deallocated should realloc(3) return a null pointer.
-rw-r--r--handler.c26
-rw-r--r--html.c13
-rw-r--r--http.c49
-rw-r--r--server.c24
4 files changed, 79 insertions, 33 deletions
diff --git a/handler.c b/handler.c
index b152cf1..1d378a9 100644
--- a/handler.c
+++ b/handler.c
@@ -310,27 +310,33 @@ struct handler *handler_alloc(const char *const tmpdir)
int handler_add(struct handler *const h, const char *url,
const enum http_op op, const handler_fn f, void *const user)
{
- if (!h || !(h->cfg = realloc(h->cfg, (h->n_cfg + 1) * sizeof *h->cfg)))
+ const size_t n = h->n_cfg + 1;
+ struct handler_cfg *const cfgs = realloc(h->cfg, n * sizeof *h->cfg),
+ *c = NULL;
+
+ if (!cfgs)
{
fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno));
return -1;
}
- char *const new = strdup(url);
-
- if (!new)
- {
- fprintf(stderr, "%s: malloc(3): %s\n", __func__, strerror(errno));
- return -1;
- }
+ c = &cfgs[h->n_cfg];
- h->cfg[h->n_cfg++] = (const struct handler_cfg)
+ *c = (const struct handler_cfg)
{
- .url = new,
+ .url = strdup(url),
.op = op,
.f = f,
.user = user
};
+ if (!c->url)
+ {
+ fprintf(stderr, "%s: strdup(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ h->cfg = cfgs;
+ h->n_cfg = n;
return 0;
}
diff --git a/html.c b/html.c
index f5ea336..95d26b9 100644
--- a/html.c
+++ b/html.c
@@ -101,25 +101,30 @@ int html_node_set_value_unescaped(struct html_node *const n,
int html_node_add_attr(struct html_node *const n, const char *const attr,
const char *const val)
{
- if (!(n->attrs = realloc(n->attrs, (n->n + 1) * sizeof *n->attrs)))
+ const size_t el = n->n + 1;
+ struct html_attribute *const attrs = realloc(n->attrs,
+ el * sizeof *n->attrs), *a = NULL;
+
+ if (!attrs)
{
fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno));
return -1;
}
- struct html_attribute *const a = &n->attrs[n->n++];
-
+ a = &attrs[n->n];
*a = (const struct html_attribute){0};
if (!(a->attr = strdup(attr))
|| (val && !(a->value = strdup(val))))
{
- fprintf(stderr, "%s: malloc(3): %s\n", __func__, strerror(errno));
+ fprintf(stderr, "%s: strdup(3): %s\n", __func__, strerror(errno));
free(a->attr);
free(a->value);
return -1;
}
+ n->attrs = attrs;
+ n->n = el;
return 0;
}
diff --git a/http.c b/http.c
index 629f356..448de24 100644
--- a/http.c
+++ b/http.c
@@ -470,14 +470,17 @@ static int http_write(struct http_ctx *const h, bool *const close)
int http_response_add_header(struct http_response *const r,
const char *const header, const char *const value)
{
- if (!(r->headers = realloc(r->headers,
- sizeof (r->n_headers + 1) *sizeof *r->headers)))
+ const size_t n = r->n_headers + 1;
+ struct http_header *const headers = realloc(r->headers,
+ n * sizeof *r->headers), *h = NULL;
+
+ if (!headers)
{
fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno));
return -1;
}
- struct http_header *const h = &r->headers[r->n_headers++];
+ h = &headers[r->n_headers];
*h = (const struct http_header)
{
@@ -487,13 +490,14 @@ int http_response_add_header(struct http_response *const r,
if (!h->header || !h->value)
{
- fprintf(stderr, "%s: malloc(3): %s\n", __func__, strerror(errno));
+ fprintf(stderr, "%s: strdup(3): %s\n", __func__, strerror(errno));
free(h->header);
free(h->value);
- free(h);
return -1;
}
+ r->headers = headers;
+ r->n_headers = n;
return 0;
}
@@ -984,16 +988,21 @@ static int set_content_disposition(struct http_ctx *const h,
__func__, (int)(sep - c), c);
return 1;
}
- else if (!(m->forms = realloc(m->forms,
- (m->nforms + 1) * sizeof *m->forms)))
+
+ const size_t n = m->nforms + 1;
+ struct form *const forms = realloc(m->forms, n * sizeof *m->forms);
+
+ if (!forms)
{
fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno));
return -1;
}
- struct form *const f = &m->forms[m->nforms++];
+ struct form *const f = &forms[m->nforms];
*f = (const struct form){0};
+ m->nforms = n;
+ m->forms = forms;
return cd_fields(h, f, sep);
}
@@ -1193,13 +1202,17 @@ static int apply_from_file(struct http_ctx *const h, struct form *const f)
m->fd = -1;
- if (!(m->files = realloc(m->files, (m->nfiles + 1) * sizeof *m->files)))
+ const size_t n = m->nfiles + 1;
+ struct http_post_file *const files = realloc(m->files,
+ n * sizeof *m->files);
+
+ if (!files)
{
fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno));
return -1;
}
- struct http_post_file *const pf = &m->files[m->nfiles++];
+ struct http_post_file *const pf = &files[m->nfiles];
*pf = (const struct http_post_file)
{
@@ -1207,6 +1220,8 @@ static int apply_from_file(struct http_ctx *const h, struct form *const f)
.filename = f->filename
};
+ m->files = files;
+ m->nfiles = n;
return 0;
}
@@ -1575,13 +1590,18 @@ char *http_decode_url(const char *url)
while (*url)
{
- if (!(ret = realloc(ret, n + 1)))
+ char *const r = realloc(ret, n + 1);
+
+ if (!r)
{
fprintf(stderr, "%s: realloc(3) loop: %s\n",
__func__, strerror(errno));
goto failure;
}
- else if (*url != '%')
+
+ ret = r;
+
+ if (*url != '%')
ret[n++] = *url++;
else if (*(url + 1) && *(url + 2))
{
@@ -1597,12 +1617,15 @@ char *http_decode_url(const char *url)
}
}
- if (!(ret = realloc(ret, n + 1)))
+ char *const r = realloc(ret, n + 1);
+
+ if (!r)
{
fprintf(stderr, "%s: realloc(3) end: %s\n", __func__, strerror(errno));
goto failure;
}
+ ret = r;
ret[n] = '\0';
return ret;
diff --git a/server.c b/server.c
index d867b59..f00a37c 100644
--- a/server.c
+++ b/server.c
@@ -58,12 +58,17 @@ int server_client_close(struct server *const s, struct server_client *const c)
{
memcpy(ref, ref + 1, s->n - i);
- if (!(s->c = realloc(s->c, (s->n - 1) * sizeof *s->c)))
+ const size_t n = s->n - 1;
+ struct server_client *const c = realloc(s->c, n * sizeof *s->c);
+
+ if (!c)
{
fprintf(stderr, "%s: realloc(3): %s\n",
__func__, strerror(errno));
return -1;
}
+
+ s->c = c;
}
else
{
@@ -127,19 +132,26 @@ static struct server_client *alloc_client(struct server *const s)
__func__, strerror(errno));
return NULL;
}
- else if (!(s->c = realloc(s->c, (s->n + 1) * sizeof *s->c)))
+
+ const size_t n = s->n + 1;
+ struct server_client *const clients = realloc(s->c, n * sizeof *s->c);
+
+ if (!clients)
{
- fprintf(stderr, "%s: realloc(3): %s\n",
- __func__, strerror(errno));
+ fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno));
return NULL;
}
- s->c[s->n] = (const struct server_client)
+ struct server_client *const c = &clients[s->n];
+
+ *c = (const struct server_client)
{
.fd = fd
};
- return &s->c[s->n++];
+ s->c = clients;
+ s->n = n;
+ return c;
}
void server_client_write_pending(struct server_client *const c,