Hi guys,

On Tue, Dec 31, 2013 at 10:17:30AM -0600, Kevin wrote:
> I think that is the same bug I ran into.
> 
> I was unable to get the debug tools working sufficiently to track it down
> myself, and Willy was unable to use my debug file to find it either.
> 
> He did point me toward a clever workaround of changing the header instead of
> deleting it and that seems to work. In my case changing Content-Length to
> Xontent-Length.
> 
> >> rsprep ^Content-Length:(.*) Xontent-Length:\1 if is_304
> 
> 
> The other thing that worked for me was using the built in regular expressions 
> library instead of PCRE.

I'm really starting to think this could be a PCRE bug on OSX. The
only two reports of this crash are users of PCRE on OSX, and looking
at the code, I can't imagine any reason for this to happen. The same
code is executed for header renaming and removal. The only difference
is that when the header is removed, regexec() is called again with a
pointer to the same location (but different content). So maybe there
is an improperly initialized pointer somewhere in PCRE which randomly
makes it fail when multiple contents are passed in turn ? I don't really
know.

Another strange point is that if a memory corruption happened because
of the header removal (eg: wrong length calculation), it should be
independant on the regex lib used (since it does not use anything
returned by regexec). And the fact that changing to the builtin regex
fixes the issue tends to fuel the theory of a PCRE bug.

If you can easily reproduce it without too much traffic, you can
apply the attached patch and report the output.

Thanks,
Willy

diff --git a/src/proto_http.c b/src/proto_http.c
index 7a9eaa0..bd4c3ac 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -7129,6 +7129,10 @@ int apply_filter_to_resp_headers(struct session *t, 
struct channel *rtr, struct
        cur_next = rtr->buf->p + hdr_idx_first_pos(&txn->hdr_idx);
        old_idx = 0;
 
+       printf("0: cur_next=+%d used=%d buf.p=%p buf.size=%d buf.p=+%d buf.o=%d 
buf.i=%d\n",
+              (int)(cur_next - rtr->buf->p), txn->hdr_idx.used, 
rtr->buf->data, rtr->buf->size, (int)(rtr->buf->p-rtr->buf->data),
+              rtr->buf->o, rtr->buf->i);
+
        while (!last_hdr) {
                if (unlikely(txn->flags & TX_SVDENY))
                        return 1;
@@ -7146,6 +7150,9 @@ int apply_filter_to_resp_headers(struct session *t, 
struct channel *rtr, struct
                cur_end  = cur_ptr + cur_hdr->len;
                cur_next = cur_end + cur_hdr->cr + 1;
 
+               printf("1: old_idx=%d cur_idx=%d ptr=%p end=+%d next=+%d 
buf_end=%+d\n",
+                      old_idx, cur_idx, cur_ptr, (int)(cur_end-cur_ptr), 
(int)(cur_next-cur_ptr), (int)(bi_end(rtr->buf)-cur_ptr));
+
                /* Now we have one header between cur_ptr and cur_end,
                 * and the next header starts at cur_next.
                 */
@@ -7187,6 +7194,7 @@ int apply_filter_to_resp_headers(struct session *t, 
struct channel *rtr, struct
                        case ACT_REMOVE:
                                delta = buffer_replace2(rtr->buf, cur_ptr, 
cur_next, NULL, 0);
                                cur_next += delta;
+                               printf("2: old_idx=%d cur_idx=%d next_idx=%d 
used=%d delta=%d ptr=%p next=+%d buf_end=+%d\n", old_idx, cur_idx, 
cur_hdr->next, txn->hdr_idx.used, delta, cur_ptr, (int)(cur_next-cur_ptr), 
(int)(bi_end(rtr->buf)-cur_ptr));
 
                                http_msg_move_end(&txn->rsp, delta);
                                txn->hdr_idx.v[old_idx].next = cur_hdr->next;

Reply via email to