]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[BUG] http: fix for capture memory leak was incorrect
authorWilly Tarreau <w@1wt.eu>
Thu, 7 Jan 2010 21:51:47 +0000 (22:51 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 7 Jan 2010 21:51:47 +0000 (22:51 +0100)
That patch was incorrect because under some circumstances, the
capture memory could be freed by session_free() and then again
by http_end_txn(), causing a double free and an eventual segfault.
The pool use count was also reported wrong due to this bug.

The cleanup code was removed from session_free() to remain only
in http_end_txn().

src/proto_http.c
src/session.c

index 9b9176caeac65f8720da690467e51dde8c281eec..a3354207acad904490a6ab26ce26142b1b376086 100644 (file)
@@ -6310,19 +6310,11 @@ void http_init_txn(struct session *s)
        if (fe->options2 & PR_O2_REQBUG_OK)
                txn->req.err_pos = -1;            /* let buggy requests pass */
 
-       if (txn->req.cap) {
-               struct cap_hdr *h;
-               for (h = fe->req_cap; h; h = h->next)
-                       pool_free2(h->pool, txn->req.cap[h->index]);
+       if (txn->req.cap)
                memset(txn->req.cap, 0, fe->nb_req_cap * sizeof(void *));
-       }
 
-       if (txn->rsp.cap) {
-               struct cap_hdr *h;
-               for (h = fe->rsp_cap; h; h = h->next)
-                       pool_free2(h->pool, txn->rsp.cap[h->index]);
+       if (txn->rsp.cap)
                memset(txn->rsp.cap, 0, fe->nb_rsp_cap * sizeof(void *));
-       }
 
        if (txn->hdr_idx.v)
                hdr_idx_init(&txn->hdr_idx);
@@ -6340,6 +6332,21 @@ void http_end_txn(struct session *s)
        txn->uri = NULL;
        txn->srv_cookie = NULL;
        txn->cli_cookie = NULL;
+
+       if (txn->req.cap) {
+               struct cap_hdr *h;
+               for (h = s->fe->req_cap; h; h = h->next)
+                       pool_free2(h->pool, txn->req.cap[h->index]);
+               memset(txn->req.cap, 0, s->fe->nb_req_cap * sizeof(void *));
+       }
+
+       if (txn->rsp.cap) {
+               struct cap_hdr *h;
+               for (h = s->fe->rsp_cap; h; h = h->next)
+                       pool_free2(h->pool, txn->rsp.cap[h->index]);
+               memset(txn->rsp.cap, 0, s->fe->nb_rsp_cap * sizeof(void *));
+       }
+
 }
 
 /* to be used at the end of a transaction to prepare a new one */
index 406d2c0bdd22e8c93b9a8e65b5ea0df17e1b9e6b..48c8ce9c978528cf693abee160d1b9d7feedeadd 100644 (file)
@@ -81,25 +81,14 @@ void session_free(struct session *s)
        if (s->sessid)
                pool_free2(apools.sessid, s->sessid);
 
+       http_end_txn(s);
+
        if (fe) {
                pool_free2(fe->hdr_idx_pool, txn->hdr_idx.v);
-
-               if (txn->rsp.cap != NULL) {
-                       struct cap_hdr *h;
-                       for (h = fe->rsp_cap; h; h = h->next)
-                               pool_free2(h->pool, txn->rsp.cap[h->index]);
-                       pool_free2(fe->rsp_cap_pool, txn->rsp.cap);
-               }
-               if (txn->req.cap != NULL) {
-                       struct cap_hdr *h;
-                       for (h = fe->req_cap; h; h = h->next)
-                               pool_free2(h->pool, txn->req.cap[h->index]);
-                       pool_free2(fe->req_cap_pool, txn->req.cap);
-               }
+               pool_free2(fe->rsp_cap_pool, txn->rsp.cap);
+               pool_free2(fe->req_cap_pool, txn->req.cap);
        }
 
-       http_end_txn(s);
-
        list_for_each_entry_safe(bref, back, &s->back_refs, users) {
                /* we have to unlink all watchers. We must not relink them if
                 * this session was the last one in the list.