Raft-drive-async's reconnect-offload burst (Task 2.1/2.2) exposed a latent race in io_worker's epoll dispatch loop: ha.c's on_standby_connected() evicts a stale duplicate peer channel via iomgr_unmonitor()+endpoint_unref(), but epoll_ctl(DEL) only stops FUTURE epoll_wait() calls -- it does not invalidate an event for that same endpoint already sitting in the CURRENT batch's events[] array. A later event in the same batch then dereferences the freed endpoint_t/SSL*, producing the ASAN SEGV observed deep inside OpenSSL's ssl3_read_bytes during raft-drive-async's round-9 soak. The original "concurrent SSL_do_handshake from two io_worker threads" hypothesis was wrong and is retracted -- iomgr_start() creates exactly one io_worker thread per iomgr_t. Fix: extract io_worker_dispatch_batch(), which takes endpoint_ref() on every endpoint in the batch before dispatching any of them and endpoint_unref()s each only after the whole batch completes -- the same lock-free ref/unref bracket already used for bug-1298 and INVOKE_MSG_HANDLER, just never applied to io_worker's own loop. Pure atomics, no locks, no blocking added to the hot path. Adds test_netio_batch_dispatch_uaf.c, which drives the real dispatch loop with a synthetic epoll_event[] batch (TDD RED confirmed via ASAN heap-use-after-free before the fix, GREEN after). Verified further with two independent clean 10-round live sequential HA soaks (33 and 36 jobs, zero loss) and full ASAN suite runs (xcelib_test 294/0, controller_unit_test 972/0). raft-drive-async's kiro-validate-impl re-run flips NO-GO to GO.
200 lines
6.2 KiB
Meson
200 lines
6.2 KiB
Meson
capnp = find_program('capnp')
|
|
packcc = find_program('packcc')
|
|
|
|
schema_dir = meson.current_source_dir() / '..' / 'schema'
|
|
|
|
gen_srcs = custom_target(
|
|
'controllercapnp.[ch]',
|
|
output:['controller.capnp.c', 'controller.capnp.h'],
|
|
input: '../schema/controller.capnp',
|
|
command: [capnp, 'compile','-o' ,'c:lib', '-I', schema_dir, '--src-prefix', schema_dir, '@INPUT@']
|
|
)
|
|
|
|
section_parser = custom_target(
|
|
'xce resreq section parser',
|
|
output: ['section.c', 'section.h'],
|
|
input: ['section.peg'],
|
|
command: [
|
|
packcc,
|
|
'-l',
|
|
'-o',
|
|
'lib/section',
|
|
'@INPUT@'
|
|
],
|
|
build_by_default: true)
|
|
|
|
rusage_parser = custom_target(
|
|
'xce resreq rusage parser',
|
|
output: ['rusage.c', 'rusage.h'],
|
|
input: ['rusage.peg'],
|
|
command: [
|
|
packcc,
|
|
'-l',
|
|
'-o',
|
|
'lib/rusage',
|
|
'@INPUT@'
|
|
],
|
|
build_by_default: true)
|
|
|
|
xce_resreq_parser = custom_target(
|
|
'xce resreq xce_resreq parser',
|
|
output: ['xce_resreq.c', 'xce_resreq.h'],
|
|
input: ['xce_resreq.peg'],
|
|
command: [
|
|
packcc,
|
|
'-l',
|
|
'-o',
|
|
'lib/xce_resreq',
|
|
'@INPUT@'
|
|
],
|
|
build_by_default: true)
|
|
|
|
xce_select_parser = custom_target(
|
|
'xce select expression parser',
|
|
output: ['xce_select_peg.c', 'xce_select_peg.h'],
|
|
input: ['xce_select.peg'],
|
|
command: [
|
|
packcc,
|
|
'-l',
|
|
'-o',
|
|
'lib/xce_select_peg',
|
|
'@INPUT@'
|
|
],
|
|
build_by_default: true)
|
|
|
|
libxce_src = [ gen_srcs[0],
|
|
section_parser[0],
|
|
rusage_parser[0],
|
|
xce_resreq_parser[0],
|
|
xce_select_parser[0],
|
|
'client.c',
|
|
'client_failover.c',
|
|
'dataq.c',
|
|
'hook.c',
|
|
'htab.c',
|
|
'kvmgr.c',
|
|
'mylock.c',
|
|
'netio.c',
|
|
'request.c',
|
|
'threshold.c',
|
|
'utils.c',
|
|
'vtaskmgr.c',
|
|
'window.c',
|
|
'xceapi.c',
|
|
'xcectx.c',
|
|
'xlist.c',
|
|
'xstring.c',
|
|
'zarray.c',
|
|
'wrap.c',
|
|
'idgen.c',
|
|
'delay.c',
|
|
'ordq.c',
|
|
'preason.c',
|
|
'xcealloc.c',
|
|
'misc.c',
|
|
'group.c',
|
|
'xcelimit.c',
|
|
'xvec.c',
|
|
'helper.c',
|
|
'resreq.c',
|
|
'xce_select.c',
|
|
'bitset.c',
|
|
'kv.c',
|
|
'jobj.c',
|
|
'qobj.c',
|
|
'resobj.c',
|
|
'wobj.c',
|
|
'configobj.c',
|
|
'cluster.c',
|
|
'raft/raft.c',
|
|
]
|
|
|
|
incdir = include_directories('../include')
|
|
build_inc = include_directories('.')
|
|
|
|
capnpc_c_prog = find_program('capnpc-c')
|
|
|
|
# debug('capnpc_c_prog %s\n', capnpc_c_prog)
|
|
|
|
thread_dep = dependency('threads')
|
|
c_capnproto_dep = dependency('c-capnproto')
|
|
tinylog_dep = dependency('tinylog')
|
|
unity_dep = dependency('unity')
|
|
ssl_dep = dependency('openssl')
|
|
|
|
libxce_deps = [c_capnproto_dep, ssl_dep, tinylog_dep, thread_dep]
|
|
|
|
#libxce_shared = shared_library('xce',
|
|
# libxce_src,
|
|
# include_directories: [incdir, build_inc],
|
|
# dependencies: libxce_deps,
|
|
# install: true)
|
|
|
|
libxce = static_library('xce',
|
|
libxce_src,
|
|
include_directories: [incdir, build_inc],
|
|
dependencies: libxce_deps,
|
|
install: true)
|
|
|
|
|
|
libxce_dep = declare_dependency(link_with: libxce)
|
|
# libxce_shared_dep = declare_dependency(link_with: libxce_shared)
|
|
|
|
libxce_test_src = ['testsuite/test.c',
|
|
'testsuite/test_error.c',
|
|
'testsuite/test_htab.c',
|
|
'testsuite/test_htab_int.c',
|
|
'testsuite/test_utils.c',
|
|
'testsuite/test_xstring.c',
|
|
'testsuite/test_zarray.c',
|
|
'testsuite/test_config.c',
|
|
'testsuite/test_idgen.c',
|
|
'testsuite/test_delay.c',
|
|
'testsuite/test_ordq.c',
|
|
'testsuite/test_preason.c',
|
|
'testsuite/test_kvmgr.c',
|
|
'testsuite/test_group.c',
|
|
'testsuite/test_xlist.c',
|
|
'testsuite/test_limit.c',
|
|
'testsuite/test_xvec.c',
|
|
'testsuite/test_resreq.c',
|
|
'testsuite/test_resmgr_fixture.c',
|
|
'testsuite/test_select.c',
|
|
'testsuite/test_bitset.c',
|
|
'testsuite/test_kv.c',
|
|
'testsuite/test_jobj.c',
|
|
'testsuite/test_jobj_hardening.c',
|
|
'testsuite/test_wobj.c',
|
|
'testsuite/test_qobj.c',
|
|
'testsuite/test_request.c',
|
|
'testsuite/test_zarray_cow.c',
|
|
'testsuite/test_kvmgr_capture.c',
|
|
'testsuite/test_zarray_reserve.c',
|
|
'testsuite/test_kvmgr_reserve.c',
|
|
'testsuite/test_hooks.c',
|
|
'testsuite/test_cluster.c',
|
|
'testsuite/test_cluster_parse.c',
|
|
'testsuite/test_libxce_retry.c',
|
|
'testsuite/test_netio_on_connected.c',
|
|
'testsuite/test_netio_on_fini.c',
|
|
'testsuite/test_netio_arm_failure.c',
|
|
'testsuite/test_netio_close_propagation.c',
|
|
'testsuite/test_netio_bounded_connect.c',
|
|
'testsuite/test_netio_batch_dispatch_uaf.c',
|
|
'testsuite/test_request_send_propagation.c',
|
|
'testsuite/test_raft.c',
|
|
'testsuite/test_wal_wire.c',
|
|
'testsuite/test_ctrlstatus.c',
|
|
'testsuite/test_vtask_admission.c',
|
|
'raft/raft_sim.c',
|
|
]
|
|
|
|
libxce_test_deps = [libxce_deps, librtti_dep, unity_dep, libxce_dep]
|
|
libxce_test = executable('xcelib_test',
|
|
libxce_test_src,
|
|
include_directories: [incdir, build_inc],
|
|
dependencies: libxce_test_deps,
|
|
c_args: ['-DXCE_TESTING'],
|
|
install: true)
|
|
|
|
test('libxce test', libxce_test, timeout: 120)
|