When the session pool is destroyed, so is the beam's pool so we don't
want to run the beam cleanup twice.
ASan is reporting something like this (APR_POOL_DEBUG):
=================================================================
==81201==ERROR: AddressSanitizer: heap-use-after-free on address 0x603000080ce8 at pc 0x7fdc78962cc9 bp 0x7fdc731ff4f0 sp 0x7fdc731ff4e8
READ of size 8 at 0x603000080ce8 thread T11
#0 0x7fdc78962cc8 in recv_buffer_cleanup ~httpd/modules/http2/h2_bucket_beam.c:279
#1 0x7fdc78962fdc in beam_cleanup ~httpd/modules/http2/h2_bucket_beam.c:306
#2 0x7fdc7896300c in beam_pool_cleanup ~httpd/modules/http2/h2_bucket_beam.c:313
#3 0x7fdc7c5a8239 in run_cleanups memory/unix/apr_pools.c:2689
#4 0x7fdc7c5a50f9 in pool_clear_debug memory/unix/apr_pools.c:1867
#5 0x7fdc7c5a562e in pool_destroy_debug memory/unix/apr_pools.c:1965
#6 0x7fdc7c5a5179 in pool_clear_debug memory/unix/apr_pools.c:1880
#7 0x7fdc7c5a562e in pool_destroy_debug memory/unix/apr_pools.c:1965
#8 0x7fdc7c5a5179 in pool_clear_debug memory/unix/apr_pools.c:1880
#9 0x7fdc7c5a562e in pool_destroy_debug memory/unix/apr_pools.c:1965
#10 0x7fdc7c5a5179 in pool_clear_debug memory/unix/apr_pools.c:1880
#11 0x7fdc7c5a562e in pool_destroy_debug memory/unix/apr_pools.c:1965
#12 0x7fdc7c5a5827 in apr_pool_destroy_debug memory/unix/apr_pools.c:2014
#13 0x7fdc789aeaa5 in h2_session_pre_close ~httpd/modules/http2/h2_session.c:1934
#14 0x7fdc7896a20e in h2_c1_pre_close ~httpd/modules/http2/h2_c1.c:188
#15 0x7fdc7896b538 in h2_c1_hook_pre_close ~httpd/modules/http2/h2_c1.c:308
#16 0x5596139aeb28 in ap_run_pre_close_connection ~httpd/server/connection.c:45
#17 0x5596139af353 in ap_prep_lingering_close ~httpd/server/connection.c:128
#18 0x5596139af3f2 in ap_start_lingering_close ~httpd/server/connection.c:154
#19 0x7fdc7835bdf0 in process_lingering_close ~httpd/server/mpm/event/event.c:1999
#20 0x7fdc78359ccb in process_socket ~httpd/server/mpm/event/event.c:1540
#21 0x7fdc783608d7 in worker_thread ~httpd/server/mpm/event/event.c:2756
#22 0x7fdc7c5d3e57 in dummy_worker threadproc/unix/thread.c:153
#23 0x7fdc7c441d7f in start_thread nptl/pthread_create.c:481
#24 0x7fdc7c337bde in clone (/lib/x86_64-linux-gnu/libc.so.6+0xfcbde)
0x603000080ce8 is located 8 bytes inside of 32-byte region [0x603000080ce0,0x603000080d00)
freed by thread T11 here:
#0 0x7fdc7c887f07 in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:122
#1 0x7fdc7c5a5420 in pool_clear_debug memory/unix/apr_pools.c:1906
#2 0x7fdc7c5a562e in pool_destroy_debug memory/unix/apr_pools.c:1965
#3 0x7fdc7c5a5179 in pool_clear_debug memory/unix/apr_pools.c:1880
#4 0x7fdc7c5a562e in pool_destroy_debug memory/unix/apr_pools.c:1965
#5 0x7fdc7c5a5827 in apr_pool_destroy_debug memory/unix/apr_pools.c:2014
#6 0x7fdc789aeaa5 in h2_session_pre_close ~httpd/modules/http2/h2_session.c:1934
#7 0x7fdc7896a20e in h2_c1_pre_close ~httpd/modules/http2/h2_c1.c:188
#8 0x7fdc7896b538 in h2_c1_hook_pre_close ~httpd/modules/http2/h2_c1.c:308
#9 0x5596139aeb28 in ap_run_pre_close_connection ~httpd/server/connection.c:45
#10 0x5596139af353 in ap_prep_lingering_close ~httpd/server/connection.c:128
#11 0x5596139af3f2 in ap_start_lingering_close ~httpd/server/connection.c:154
#12 0x7fdc7835bdf0 in process_lingering_close ~httpd/server/mpm/event/event.c:1999
#13 0x7fdc78359ccb in process_socket ~httpd/server/mpm/event/event.c:1540
#14 0x7fdc783608d7 in worker_thread ~httpd/server/mpm/event/event.c:2756
#15 0x7fdc7c5d3e57 in dummy_worker threadproc/unix/thread.c:153
#16 0x7fdc7c441d7f in start_thread nptl/pthread_create.c:481
previously allocated by thread T11 here:
#0 0x7fdc7c8882b8 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x7fdc7c5a4d00 in pool_alloc memory/unix/apr_pools.c:1787
#2 0x7fdc7c5a507a in apr_palloc_debug memory/unix/apr_pools.c:1828
#3 0x7fdc7c4d8160 in apr_brigade_create buckets/apr_brigade.c:90
#4 0x7fdc7c4d82d8 in apr_brigade_split_ex buckets/apr_brigade.c:107
#5 0x7fdc78967f7c in h2_beam_receive ~httpd/modules/http2/h2_bucket_beam.c:729
#6 0x7fdc789b65f0 in buffer_output_receive ~httpd/modules/http2/h2_stream.c:847
#7 0x7fdc789bb655 in h2_stream_read_output ~httpd/modules/http2/h2_stream.c:1372
#8 0x7fdc789aa155 in on_stream_output ~httpd/modules/http2/h2_session.c:1313
#9 0x7fdc789956ba in mplx_pollset_poll ~httpd/modules/http2/h2_mplx.c:1299
#10 0x7fdc7898deb8 in h2_mplx_c1_poll ~httpd/modules/http2/h2_mplx.c:532
#11 0x7fdc789ae04b in h2_session_process ~httpd/modules/http2/h2_session.c:1863
#12 0x7fdc78969b0f in h2_c1_run ~httpd/modules/http2/h2_c1.c:138
#13 0x7fdc7896b302 in h2_c1_hook_process_connection ~httpd/modules/http2/h2_c1.c:286
#14 0x5596139ae4b6 in ap_run_process_connection ~httpd/server/connection.c:43
#15 0x7fdc78358d67 in process_socket ~httpd/server/mpm/event/event.c:1353
#16 0x7fdc783608d7 in worker_thread ~httpd/server/mpm/event/event.c:2756
#17 0x7fdc7c5d3e57 in dummy_worker threadproc/unix/thread.c:153
#18 0x7fdc7c441d7f in start_thread nptl/pthread_create.c:481
Thread T11 created by T2 here:
#0 0x7fdc7c7baa22 in __interceptor_pthread_create ../../../../src/libsanitizer/asan/asan_interceptors.cc:208
#1 0x7fdc7c5d4534 in apr_thread_create threadproc/unix/thread.c:228
#2 0x7fdc7836273d in start_threads ~httpd/server/mpm/event/event.c:3035
#3 0x7fdc7c5d3e57 in dummy_worker threadproc/unix/thread.c:153
#4 0x7fdc7c441d7f in start_thread nptl/pthread_create.c:481
Thread T2 created by T0 here:
#0 0x7fdc7c7baa22 in __interceptor_pthread_create ../../../../src/libsanitizer/asan/asan_interceptors.cc:208
#1 0x7fdc7c5d4534 in apr_thread_create threadproc/unix/thread.c:228
#2 0x7fdc78363d9f in child_main ~httpd/server/mpm/event/event.c:3262
#3 0x7fdc7836483b in make_child ~httpd/server/mpm/event/event.c:3421
#4 0x7fdc78364b89 in startup_children ~httpd/server/mpm/event/event.c:3444
#5 0x7fdc78368abc in event_run ~httpd/server/mpm/event/event.c:3932
#6 0x5596139b6d18 in ap_run_mpm ~httpd/server/mpm_common.c:101
#7 0x55961399098b in main ~httpd/server/main.c:880
#8 0x7fdc7c2627ec in __libc_start_main ../csu/libc-start.c:332
SUMMARY: AddressSanitizer: heap-use-after-free ~httpd/modules/http2/h2_bucket_beam.c:279 in recv_buffer_cleanup
Shadow bytes around the buggy address:
0x0c0680008140: fa fa 00 00 00 00 fa fa fd fd fd fa fa fa fd fd
0x0c0680008150: fd fd fa fa fd fd fd fd fa fa fd fd fd fd fa fa
0x0c0680008160: fd fd fd fd fa fa fd fd fd fd fa fa fd fd fd fd
0x0c0680008170: fa fa fd fd fd fd fa fa fd fd fd fd fa fa fd fd
0x0c0680008180: fd fd fa fa fd fd fd fd fa fa fd fd fd fa fa fa
=>0x0c0680008190: fd fd fd fa fa fa fd fd fd fa fa fa fd[fd]fd fd
0x0c06800081a0: fa fa fd fd fd fd fa fa fd fd fd fd fa fa fd fd
0x0c06800081b0: fd fd fa fa fd fd fd fd fa fa fd fd fd fd fa fa
0x0c06800081c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c06800081d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c06800081e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==81201==ABORTING
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@
1897868 13f79535-47bb-0310-9956-
ffa450edef68
static void recv_buffer_cleanup(h2_bucket_beam *beam)
{
- if (beam->recv_buffer && !APR_BRIGADE_EMPTY(beam->recv_buffer)) {
- apr_bucket_brigade *bb = beam->recv_buffer;
+ apr_bucket_brigade *bb = beam->recv_buffer;
+
+ beam->recv_buffer = NULL;
+
+ if (bb && !APR_BRIGADE_EMPTY(bb)) {
apr_off_t bblen = 0;
- beam->recv_buffer = NULL;
apr_brigade_length(bb, 0, &bblen);
beam->recv_bytes += bblen;
}
}
-static apr_status_t beam_cleanup(h2_bucket_beam *beam, int from_pool)
+static void beam_shutdown(h2_bucket_beam *beam, apr_shutdown_how_e how)
{
- beam->cons_io_cb = NULL;
- beam->recv_cb = NULL;
+ if (!beam->pool) {
+ /* pool being cleared already */
+ return;
+ }
- h2_blist_cleanup(&beam->buckets_to_send);
- recv_buffer_cleanup(beam);
- purge_consumed_buckets(beam);
- return APR_SUCCESS;
+ /* shutdown both receiver and sender? */
+ if (how == APR_SHUTDOWN_READWRITE) {
+ beam->cons_io_cb = NULL;
+ beam->recv_cb = NULL;
+ }
+
+ /* shutdown receiver (or both)? */
+ if (how != APR_SHUTDOWN_WRITE) {
+ recv_buffer_cleanup(beam);
+ beam->recv_cb = NULL;
+ }
+
+ /* shutdown sender (or both)? */
+ if (how != APR_SHUTDOWN_READ) {
+ h2_blist_cleanup(&beam->buckets_to_send);
+ purge_consumed_buckets(beam);
+ }
}
-static apr_status_t beam_pool_cleanup(void *data)
+static apr_status_t beam_cleanup(void *data)
{
- return beam_cleanup(data, 1);
+ h2_bucket_beam *beam = data;
+ beam_shutdown(beam, APR_SHUTDOWN_READWRITE);
+ beam->pool = NULL; /* the pool is clearing now */
+ return APR_SUCCESS;
}
apr_status_t h2_beam_destroy(h2_bucket_beam *beam, conn_rec *c)
{
- apr_pool_cleanup_kill(beam->pool, beam, beam_pool_cleanup);
- H2_BEAM_LOG(beam, c, APLOG_TRACE2, 0, "destroy", NULL);
- return beam_cleanup(beam, 0);
+ if (beam->pool) {
+ H2_BEAM_LOG(beam, c, APLOG_TRACE2, 0, "destroy", NULL);
+ apr_pool_cleanup_run(beam->pool, beam, beam_cleanup);
+ }
+ H2_BEAM_LOG(beam, c, APLOG_TRACE2, 0, "destroyed", NULL);
+ return APR_SUCCESS;
}
apr_status_t h2_beam_create(h2_bucket_beam **pbeam, conn_rec *from,
if (APR_SUCCESS != rv) goto cleanup;
rv = apr_thread_cond_create(&beam->change, pool);
if (APR_SUCCESS != rv) goto cleanup;
- apr_pool_pre_cleanup_register(pool, beam, beam_pool_cleanup);
+ apr_pool_pre_cleanup_register(pool, beam, beam_cleanup);
cleanup:
H2_BEAM_LOG(beam, from, APLOG_TRACE2, rv, "created", NULL);
beam->was_empty_cb(beam->was_empty_ctx, beam);
}
/* no more consumption reporting to sender */
- beam->cons_io_cb = NULL;
- beam->cons_ctx = NULL;
- purge_consumed_buckets(beam);
- h2_blist_cleanup(&beam->buckets_to_send);
report_consumption(beam, 1);
+ beam->cons_ctx = NULL;
+
+ beam_shutdown(beam, APR_SHUTDOWN_WRITE);
}
else {
/* receiver aborts */
- recv_buffer_cleanup(beam);
+ beam_shutdown(beam, APR_SHUTDOWN_READ);
}
apr_thread_cond_broadcast(beam->change);
apr_thread_mutex_unlock(beam->lock);
goto cleanup;
}
+ ap_assert(beam->pool);
+
b = APR_BRIGADE_FIRST(bb);
if (APR_BUCKET_IS_METADATA(b)) {
APR_BUCKET_REMOVE(b);
apr_size_t space_left = 0;
int was_empty;
+ ap_assert(beam->pool);
+
/* Called from the sender thread to add buckets to the beam */
apr_thread_mutex_lock(beam->lock);
ap_assert(beam->from == from);
transfer:
if (beam->aborted) {
- recv_buffer_cleanup(beam);
+ beam_shutdown(beam, APR_SHUTDOWN_READ);
rv = APR_ECONNABORTED;
goto leave;
}
+ ap_assert(beam->pool);
+
/* transfer enough buckets from our receiver brigade, if we have one */
while (remain >= 0
&& beam->recv_buffer