-
-
Notifications
You must be signed in to change notification settings - Fork 6.3k
channels: fix use after free #7813
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
src/nvim/channel.c
Outdated
|
||
if ((--chan->refcount != 0)) { | ||
abort(); | ||
} | ||
|
||
free_channel_event((void **)&chan); | ||
// uv will still keep a reference to our memory until next event loop tick, so delay free | ||
multiqueue_put(main_loop.fast_events, free_channel_event, 1, chan); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
libuv resources should be freed in their respective "on close" handlers. Is that the problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it can be assumed that libuv frees handles at latest during the next loop iteration (but not in the middle of a still ongoing tick). Otherwise we will need to keep a second refcount on the channel struct just for "number of not yet closed libuv handles"
Actually closing pipes was not problematic, only the process handle itself ( What I think we really need is to defer freeing the channel struct until after a uv loop iteration. I get one remaining failure in
|
Also deps caching or something prevents libuv from being built with ASAN on travis. Though the current implementation is a hard-coded hack, I might need help from someone more familiar with our ci code. Modulo fixing the remaining luajit related error, I think we would want it to make incorrect libuv use fail quicker. |
That luaeval ASAN failure looks like #6774, which is an upstream problem. |
Unusual output from log_uv_handles(): https://gist.github.com/justinmk/802fc6f6343658358a3d623b626d46dc
|
I was just testing if |
Hmm, the scrollbind test doesn't fail if I run it (still on ASAN travis) in isolation. The failure is weird anyway as scrollbind doesn't use any channels or any other IO except ordinary buffer load/save... |
ffaf71e
to
0e95b22
Compare
@bfredl is this ready? LGTM |
@justinmk Let me squash it and cycle travis a few times... |
add test for a crash this caused
This comment was marked as outdated.
This comment was marked as outdated.
closes neovim#8813 ref neovim#7813 (comment) ref neovim#8088 (comment) Sometimes ASan fails like this: = ==16820==ERROR: AddressSanitizer: SEGV on unknown address 0x000001baab50 (pc 0x00000044f3a1 bp 0x000000000001 sp 0x7fff7ddb6a60 T0) ... = 4 0xfbfae4 in xfree /home/travis/build/neovim/neovim/build/../src/nvim/memory.c:134:3 = 5 0x120e948 in free_string_option /home/travis/build/neovim/neovim/build/../src/nvim/option.c:2207:5 = 6 0x120de3d in free_all_options /home/travis/build/neovim/neovim/build/../src/nvim/option.c:923:9 = 7 0xfc2441 in free_all_mem /home/travis/build/neovim/neovim/build/../src/nvim/memory.c:622:3 = 8 0x12bbe6c in mch_exit /home/travis/build/neovim/neovim/build/../src/nvim/os_unix.c:153:3 = 9 0x1092cc3 in exit_event /home/travis/build/neovim/neovim/build/../src/nvim/msgpack_rpc/channel.c:542:5 = 10 0xa6b2d3 in multiqueue_process_events /home/travis/build/neovim/neovim/build/../src/nvim/event/multiqueue.c:150:7 = 11 0xa64e2f in loop_poll_events /home/travis/build/neovim/neovim/build/../src/nvim/event/loop.c:65:3 = 12 0x12a4ec0 in os_breakcheck /home/travis/build/neovim/neovim/build/../src/nvim/os/input.c:162:5 = 13 0x1035f07 in line_breakcheck /home/travis/build/neovim/neovim/build/../src/nvim/misc1.c:2692:5 ... = 19 0x137ac07 in vim_regexec_nl /home/travis/build/neovim/neovim/build/../src/nvim/regexp.c:7302:10 = 20 0x910f2b in f_split /home/travis/build/neovim/neovim/build/../src/nvim/eval.c:15673:17 ... = 43 0x11667d5 in normal_check /home/travis/build/neovim/neovim/build/../src/nvim/normal.c:1325:5 = 44 0x17774c1 in state_enter /home/travis/build/neovim/neovim/build/../src/nvim/state.c:28:35 = 45 0x10c0bf4 in normal_enter /home/travis/build/neovim/neovim/build/../src/nvim/normal.c:467:3 = 46 0xea98a2 in main /home/travis/build/neovim/neovim/build/../src/nvim/main.c:566:3 = 47 0x7fbb0a667f44 in __libc_start_main /build/eglibc-ripdx6/eglibc-2.19/csu/libc-start.c:287 = 48 0x44e39b in _start (/home/travis/build/neovim/neovim/build/bin/nvim+0x44e39b) ===================================================================================================== test/helpers.lua:149: assertion failed! Discussion: - `free_all_options` is free'ing something before it was alloc'd. - ~~Options init isn't complete?~~ (No: init completed, `main.c` reached `normal_enter()`) - stdio RPC channel was closed (so `rpc_close` schedules `exit_event`) - was this because the client died from a invalid message? - `exit_event` is scheduled on `main_loop.fast_events`. - would `main_loop.events` defer it? Or do we need something like `stuffReadbuff(":qall!\n")`?
closes neovim#8813 ref neovim#7813 (comment) ref neovim#8088 (comment) Sometimes ASan fails like this: = ==16820==ERROR: AddressSanitizer: SEGV on unknown address 0x000001baab50 (pc 0x00000044f3a1 bp 0x000000000001 sp 0x7fff7ddb6a60 T0) ... 4 0xfbfae4 in xfree /home/travis/build/neovim/neovim/build/../src/nvim/memory.c:134:3 5 0x120e948 in free_string_option /home/travis/build/neovim/neovim/build/../src/nvim/option.c:2207:5 6 0x120de3d in free_all_options /home/travis/build/neovim/neovim/build/../src/nvim/option.c:923:9 7 0xfc2441 in free_all_mem /home/travis/build/neovim/neovim/build/../src/nvim/memory.c:622:3 8 0x12bbe6c in mch_exit /home/travis/build/neovim/neovim/build/../src/nvim/os_unix.c:153:3 9 0x1092cc3 in exit_event /home/travis/build/neovim/neovim/build/../src/nvim/msgpack_rpc/channel.c:542:5 10 0xa6b2d3 in multiqueue_process_events /home/travis/build/neovim/neovim/build/../src/nvim/event/multiqueue.c:150:7 11 0xa64e2f in loop_poll_events /home/travis/build/neovim/neovim/build/../src/nvim/event/loop.c:65:3 12 0x12a4ec0 in os_breakcheck /home/travis/build/neovim/neovim/build/../src/nvim/os/input.c:162:5 13 0x1035f07 in line_breakcheck /home/travis/build/neovim/neovim/build/../src/nvim/misc1.c:2692:5 ... 19 0x137ac07 in vim_regexec_nl /home/travis/build/neovim/neovim/build/../src/nvim/regexp.c:7302:10 20 0x910f2b in f_split /home/travis/build/neovim/neovim/build/../src/nvim/eval.c:15673:17 ... 43 0x11667d5 in normal_check /home/travis/build/neovim/neovim/build/../src/nvim/normal.c:1325:5 44 0x17774c1 in state_enter /home/travis/build/neovim/neovim/build/../src/nvim/state.c:28:35 45 0x10c0bf4 in normal_enter /home/travis/build/neovim/neovim/build/../src/nvim/normal.c:467:3 46 0xea98a2 in main /home/travis/build/neovim/neovim/build/../src/nvim/main.c:566:3 47 0x7fbb0a667f44 in __libc_start_main /build/eglibc-ripdx6/eglibc-2.19/csu/libc-start.c:287 48 0x44e39b in _start (/home/travis/build/neovim/neovim/build/bin/nvim+0x44e39b) Discussion: - `free_all_options` is free'ing something before it was alloc'd. - ~~Options init isn't complete?~~ (No: init completed, `main.c` reached `normal_enter()`) - stdio RPC channel was closed (so `rpc_close` schedules `exit_event`) - was this because the client died from a invalid message? - `exit_event` is scheduled on `main_loop.fast_events`. - would `main_loop.events` defer it? Or do we need something like `stuffReadbuff(":qall!\n")`? Deferring the event: diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 3244d83..62c7717 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -532,7 +532,7 @@ void rpc_close(Channel *channel) channel_decref(channel); if (channel->streamtype == kChannelStreamStdio) { - multiqueue_put(main_loop.fast_events, exit_event, 0); + multiqueue_put(main_loop.events, exit_event, 0); } } ...leads to hangs (waiting for input): [5/7] Building C object test/functiona...s/CMakeFiles/tty-test.dir/tty-test.c.o�[K [6/7] Linking C executable bin/tty-test�[K [6/7] Linking C executable bin/tty-test�[K [7/7] cd /home/travis/build/neovim/neo...ild/neovim/neovim/cmake/RunTests.cmake�[K No output has been received in the last 10m0s, this potentially indicates a stalled build or something wrong with the build itself. Check the details on how to adjust your build configuration on: https://docs.travis-ci.com/user/common-build-problems/#Build-times-out-because-no-output-was-received The build has been terminated
closes neovim#8813 ref neovim#7813 (comment) ref neovim#8088 (comment) Sometimes ASan fails like this: = ==16820==ERROR: AddressSanitizer: SEGV on unknown address 0x000001baab50 (pc 0x00000044f3a1 bp 0x000000000001 sp 0x7fff7ddb6a60 T0) ... 4 0xfbfae4 in xfree /home/travis/build/neovim/neovim/build/../src/nvim/memory.c:134:3 5 0x120e948 in free_string_option /home/travis/build/neovim/neovim/build/../src/nvim/option.c:2207:5 6 0x120de3d in free_all_options /home/travis/build/neovim/neovim/build/../src/nvim/option.c:923:9 7 0xfc2441 in free_all_mem /home/travis/build/neovim/neovim/build/../src/nvim/memory.c:622:3 8 0x12bbe6c in mch_exit /home/travis/build/neovim/neovim/build/../src/nvim/os_unix.c:153:3 9 0x1092cc3 in exit_event /home/travis/build/neovim/neovim/build/../src/nvim/msgpack_rpc/channel.c:542:5 10 0xa6b2d3 in multiqueue_process_events /home/travis/build/neovim/neovim/build/../src/nvim/event/multiqueue.c:150:7 11 0xa64e2f in loop_poll_events /home/travis/build/neovim/neovim/build/../src/nvim/event/loop.c:65:3 12 0x12a4ec0 in os_breakcheck /home/travis/build/neovim/neovim/build/../src/nvim/os/input.c:162:5 13 0x1035f07 in line_breakcheck /home/travis/build/neovim/neovim/build/../src/nvim/misc1.c:2692:5 ... 19 0x137ac07 in vim_regexec_nl /home/travis/build/neovim/neovim/build/../src/nvim/regexp.c:7302:10 20 0x910f2b in f_split /home/travis/build/neovim/neovim/build/../src/nvim/eval.c:15673:17 ... 43 0x11667d5 in normal_check /home/travis/build/neovim/neovim/build/../src/nvim/normal.c:1325:5 44 0x17774c1 in state_enter /home/travis/build/neovim/neovim/build/../src/nvim/state.c:28:35 45 0x10c0bf4 in normal_enter /home/travis/build/neovim/neovim/build/../src/nvim/normal.c:467:3 46 0xea98a2 in main /home/travis/build/neovim/neovim/build/../src/nvim/main.c:566:3 47 0x7fbb0a667f44 in __libc_start_main /build/eglibc-ripdx6/eglibc-2.19/csu/libc-start.c:287 48 0x44e39b in _start (/home/travis/build/neovim/neovim/build/bin/nvim+0x44e39b) Discussion: - `free_all_options` is free'ing something before it was alloc'd. - ~~Options init isn't complete?~~ (No: init completed, `main.c` reached `normal_enter()`) - stdio RPC channel was closed (so `rpc_close` schedules `exit_event`) - was this because the client died from a invalid message? - `exit_event` is scheduled on `main_loop.fast_events`. - would `main_loop.events` defer it? Or do we need something like `stuffReadbuff(":qall!\n")`? Deferring the event: diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 3244d83..62c7717 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -532,7 +532,7 @@ void rpc_close(Channel *channel) channel_decref(channel); if (channel->streamtype == kChannelStreamStdio) { - multiqueue_put(main_loop.fast_events, exit_event, 0); + multiqueue_put(main_loop.events, exit_event, 0); } } ...leads to hangs (waiting for input): [5/7] Building C object test/functiona...s/CMakeFiles/tty-test.dir/tty-test.c.o�[K [6/7] Linking C executable bin/tty-test�[K [6/7] Linking C executable bin/tty-test�[K [7/7] cd /home/travis/build/neovim/neo...ild/neovim/neovim/cmake/RunTests.cmake�[K No output has been received in the last 10m0s, this potentially indicates a stalled build or something wrong with the build itself. Check the details on how to adjust your build configuration on: https://docs.travis-ci.com/user/common-build-problems/#Build-times-out-because-no-output-was-received The build has been terminated
closes neovim#8813 ref neovim#7813 (comment) ref neovim#8088 (comment) Sometimes ASan fails like this: = ==16820==ERROR: AddressSanitizer: SEGV on unknown address 0x000001baab50 (pc 0x00000044f3a1 bp 0x000000000001 sp 0x7fff7ddb6a60 T0) ... 4 0xfbfae4 in xfree /home/travis/build/neovim/neovim/build/../src/nvim/memory.c:134:3 5 0x120e948 in free_string_option /home/travis/build/neovim/neovim/build/../src/nvim/option.c:2207:5 6 0x120de3d in free_all_options /home/travis/build/neovim/neovim/build/../src/nvim/option.c:923:9 7 0xfc2441 in free_all_mem /home/travis/build/neovim/neovim/build/../src/nvim/memory.c:622:3 8 0x12bbe6c in mch_exit /home/travis/build/neovim/neovim/build/../src/nvim/os_unix.c:153:3 9 0x1092cc3 in exit_event /home/travis/build/neovim/neovim/build/../src/nvim/msgpack_rpc/channel.c:542:5 10 0xa6b2d3 in multiqueue_process_events /home/travis/build/neovim/neovim/build/../src/nvim/event/multiqueue.c:150:7 11 0xa64e2f in loop_poll_events /home/travis/build/neovim/neovim/build/../src/nvim/event/loop.c:65:3 12 0x12a4ec0 in os_breakcheck /home/travis/build/neovim/neovim/build/../src/nvim/os/input.c:162:5 13 0x1035f07 in line_breakcheck /home/travis/build/neovim/neovim/build/../src/nvim/misc1.c:2692:5 ... 19 0x137ac07 in vim_regexec_nl /home/travis/build/neovim/neovim/build/../src/nvim/regexp.c:7302:10 20 0x910f2b in f_split /home/travis/build/neovim/neovim/build/../src/nvim/eval.c:15673:17 ... 43 0x11667d5 in normal_check /home/travis/build/neovim/neovim/build/../src/nvim/normal.c:1325:5 44 0x17774c1 in state_enter /home/travis/build/neovim/neovim/build/../src/nvim/state.c:28:35 45 0x10c0bf4 in normal_enter /home/travis/build/neovim/neovim/build/../src/nvim/normal.c:467:3 46 0xea98a2 in main /home/travis/build/neovim/neovim/build/../src/nvim/main.c:566:3 47 0x7fbb0a667f44 in __libc_start_main /build/eglibc-ripdx6/eglibc-2.19/csu/libc-start.c:287 48 0x44e39b in _start (/home/travis/build/neovim/neovim/build/bin/nvim+0x44e39b) Discussion: - `free_all_options` is free'ing something before it was alloc'd. - ~~Options init isn't complete?~~ (No: init completed, `main.c` reached `normal_enter()`) - stdio RPC channel was closed (so `rpc_close` schedules `exit_event`) - was this because the client died from a invalid message? - `exit_event` is scheduled on `main_loop.fast_events`. - would `main_loop.events` defer it? Or do we need something like `stuffReadbuff(":qall!\n")`? Deferring the event: diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 3244d83..62c7717 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -532,7 +532,7 @@ void rpc_close(Channel *channel) channel_decref(channel); if (channel->streamtype == kChannelStreamStdio) { - multiqueue_put(main_loop.fast_events, exit_event, 0); + multiqueue_put(main_loop.events, exit_event, 0); } } ...leads to hangs (waiting for input): [5/7] Building C object test/functiona...s/CMakeFiles/tty-test.dir/tty-test.c.o�[K [6/7] Linking C executable bin/tty-test�[K [6/7] Linking C executable bin/tty-test�[K [7/7] cd /home/travis/build/neovim/neo...ild/neovim/neovim/cmake/RunTests.cmake�[K No output has been received in the last 10m0s, this potentially indicates a stalled build or something wrong with the build itself. Check the details on how to adjust your build configuration on: https://docs.travis-ci.com/user/common-build-problems/#Build-times-out-because-no-output-was-received The build has been terminated
closes neovim#8813 ref neovim#7813 (comment) ref neovim#8088 (comment) Sometimes ASan fails like this: = ==16820==ERROR: AddressSanitizer: SEGV on unknown address 0x000001baab50 (pc 0x00000044f3a1 bp 0x000000000001 sp 0x7fff7ddb6a60 T0) ... 4 0xfbfae4 in xfree /home/travis/build/neovim/neovim/build/../src/nvim/memory.c:134:3 5 0x120e948 in free_string_option /home/travis/build/neovim/neovim/build/../src/nvim/option.c:2207:5 6 0x120de3d in free_all_options /home/travis/build/neovim/neovim/build/../src/nvim/option.c:923:9 7 0xfc2441 in free_all_mem /home/travis/build/neovim/neovim/build/../src/nvim/memory.c:622:3 8 0x12bbe6c in mch_exit /home/travis/build/neovim/neovim/build/../src/nvim/os_unix.c:153:3 9 0x1092cc3 in exit_event /home/travis/build/neovim/neovim/build/../src/nvim/msgpack_rpc/channel.c:542:5 10 0xa6b2d3 in multiqueue_process_events /home/travis/build/neovim/neovim/build/../src/nvim/event/multiqueue.c:150:7 11 0xa64e2f in loop_poll_events /home/travis/build/neovim/neovim/build/../src/nvim/event/loop.c:65:3 12 0x12a4ec0 in os_breakcheck /home/travis/build/neovim/neovim/build/../src/nvim/os/input.c:162:5 13 0x1035f07 in line_breakcheck /home/travis/build/neovim/neovim/build/../src/nvim/misc1.c:2692:5 ... 19 0x137ac07 in vim_regexec_nl /home/travis/build/neovim/neovim/build/../src/nvim/regexp.c:7302:10 20 0x910f2b in f_split /home/travis/build/neovim/neovim/build/../src/nvim/eval.c:15673:17 ... 43 0x11667d5 in normal_check /home/travis/build/neovim/neovim/build/../src/nvim/normal.c:1325:5 44 0x17774c1 in state_enter /home/travis/build/neovim/neovim/build/../src/nvim/state.c:28:35 45 0x10c0bf4 in normal_enter /home/travis/build/neovim/neovim/build/../src/nvim/normal.c:467:3 46 0xea98a2 in main /home/travis/build/neovim/neovim/build/../src/nvim/main.c:566:3 47 0x7fbb0a667f44 in __libc_start_main /build/eglibc-ripdx6/eglibc-2.19/csu/libc-start.c:287 48 0x44e39b in _start (/home/travis/build/neovim/neovim/build/bin/nvim+0x44e39b) Discussion: - `free_all_options` is free'ing something before it was alloc'd. - ~~Options init isn't complete?~~ (No: init completed, `main.c` reached `normal_enter()`) - stdio RPC channel was closed (so `rpc_close` schedules `exit_event`) - was this because the client died from a invalid message? - `exit_event` is scheduled on `main_loop.fast_events`. - would `main_loop.events` defer it? Or do we need something like `stuffReadbuff(":qall!\n")`?
Ref #7699 (comment). I will add test tomorrow.