[Varnish] #1399: Memory get freed while in use by another thread/object
Varnish
varnish-bugs at varnish-cache.org
Fri Dec 27 23:40:45 CET 2013
#1399: Memory get freed while in use by another thread/object
-------------------------------------------------+-------------------------
Reporter: varnish@… | Type: defect
Status: new | Priority: normal
Milestone: Varnish 4.0-TP1 | Component: varnishd
Version: trunk | Severity: major
Keywords: memory get freed MPL_Free |
vbf_stp_fetchhdr |
-------------------------------------------------+-------------------------
Hi,
prerequisites:
- compiled varnishd via "./configure --enable-debugging-symbols
--without-jemalloc"
- start varnishd from commandline
{{{
varnishd -n VARNISH -f default.vcl -n /var/tmp/ -a :8080 -p
default_grace=10 -p default_ttl=5 -p ping_interval=0 -p auto_restart=off
-d
}}}
- start the child process via start
- configure a single backend w/o health probes
- start two consecutive requests to varnish with a pause of
$backend_keepalive_timeout + 1 second
- backend is a apache httpd with 10s keepalive timeout
while debugging issue #1398 I've found another issue, which was a little
bit more complicated to debug.
While a backend request is made, the busyobject bereq structures get
filled by the following functions:
- vbf_stp_mkbereq -> bo->bereq0 get populted from bo->req->http
- vbf_stp_startfetch -> bo->bereq get copied from bo->bereq0
After this was done, the headers will be fetched from backend via
vbf_stp_fetchhdr.
After the first request was made, a new object will saved by varnish. If
you now wait for the keep alive timeout of your backend and then starting
the second request, the object will be gracefully delivered by varnish to
the client, but the ongoing backend request will fail, because another
thread has freed the initial (?) req object from memory.
The result is, that the backend responses with an error or in a
virtualhost environment the first vhost which matches the backend ip. You
can see the bereq structur in ticket #1398, the URL and some headers get
deleted from the bereq structure.
For me it looks like the problem leys in vbf_stp_startfetch(), where the
bo->bereq structure will be copied from the bo->bereq0 object. Either the
header should be duplicated, since the protocol and method get also
duplicated (but this could be for conditional fetches) or the req object
inside the busyobject structure should be protected from improper
invalidation (disclaimer: this opinion could be totally wrong).
I've found this bug with the help of gdb, following my commands which I've
executed:
{{{
(gdb) b vbf_stp_fetchhdr
Breakpoint 1 at 0x422304: file cache/cache_fetch.c, line 148.
(gdb) c
Continuing.
[Switching to Thread 0x7f853931b700 (LWP 11382)]
Breakpoint 1, vbf_stp_fetchhdr (wrk=0x7f853931ac20, bo=0x7f851c090a90) at
cache/cache_fetch.c:148
148 CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
(gdb) c
Continuing.
Breakpoint 1, vbf_stp_fetchhdr (wrk=0x7f853931ac20, bo=0x7f851c090a90) at
cache/cache_fetch.c:148
148 CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
(gdb) p bo->bereq->hd[1]
$3 = {b = 0x7f8510092a6d "/", e = 0x7f8510092a6e ""}
(gdb) p bo->bereq->hd[1].b
$4 = 0x7f8510092a6d "/"
(gdb) watch *0x7f8510092a6d
Hardware watchpoint 2: *0x7f8510092a6d
(gdb) c
Continuing.
[Switching to Thread 0x7f85392f7700 (LWP 11385)]
Hardware watchpoint 2: *0x7f8510092a6d
Old value = 1414004783
New value = 1409286144
__memset_sse2 () at ../sysdeps/x86_64/memset.S:880
880 movdqa %xmm0,0x60(%rdi)
(gdb) bt
#0 __memset_sse2 () at ../sysdeps/x86_64/memset.S:880
#1 0x0000000000435eec in MPL_Free (mpl=0x7f8534000a20,
item=0x7f8510090a90) at cache/cache_mempool.c:322
#2 0x0000000000441ed2 in SES_ReleaseReq (req=0x7f8510090a90) at
cache/cache_session.c:437
#3 0x000000000042ff5f in http1_wait (sp=0x7f8514001540,
wrk=0x7f85392f6c20, req=0x7f8510090a90) at cache/cache_http1_fsm.c:159
#4 0x0000000000431106 in HTTP1_Session (wrk=0x7f85392f6c20,
req=0x7f8510090a90) at cache/cache_http1_fsm.c:437
#5 0x000000000044062e in ses_req_pool_task (wrk=0x7f85392f6c20,
arg=0x7f8510090a90) at cache/cache_session.c:148
#6 0x0000000000440856 in ses_sess_pool_task (wrk=0x7f85392f6c20,
arg=0x7f8514001540) at cache/cache_session.c:173
#7 0x0000000000440d69 in SES_pool_accept_task (wrk=0x7f85392f6c20,
arg=0x7f85340009f0) at cache/cache_session.c:243
#8 0x0000000000439607 in Pool_Work_Thread (priv=0x7f85340008c0,
wrk=0x7f85392f6c20) at cache/cache_pool.c:295
#9 0x00000000004520e4 in wrk_thread_real (priv=0x7f85340008c0,
thread_workspace=2048) at cache/cache_wrk.c:143
#10 0x000000000045220d in WRK_thread (priv=0x7f85340008c0) at
cache/cache_wrk.c:161
#11 0x00007f854d8349d1 in start_thread (arg=0x7f85392f7700) at
pthread_create.c:301
#12 0x00007f854d581b6d in clone () at
../sysdeps/unix/sysv/linux/x86_64/clone.S:115
(gdb) q
}}}
1. attach to the child
2. set a breakpoint to vbf_stp_fetchhdr()
3. start the first request in another terminal
4. continue this execution of vbf_stp_fetchhdr() - it's the first request
which works
5. start the second request in another terminal
6. print the memory address of the header we want to watch
7. set the wwatchpoint for the memory address which holds our important
value
8. continue execution
9. watchpoint will be trapped by another thread which deallocates the req
structures
Please let me know if you need more information.
Best regards,
Martin
--
Ticket URL: <https://www.varnish-cache.org/trac/ticket/1399>
Varnish <https://varnish-cache.org/>
The Varnish HTTP Accelerator
More information about the varnish-bugs
mailing list