From a39009a5a9252a566ca0704d02df8dabc4ce328f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 8 Sep 2021 17:30:02 +0200 Subject: [PATCH] win,fsevent: fix uv_fs_event_stop() assert Fix a logic error where calling uv_fs_event_stop() from the event callback tripped on a `handle->dir_handle != INVALID_HANDLE_VALUE` assert in uv_fs_event_queue_readdirchanges(). Fixes: https://github.com/libuv/libuv/issues/3258 PR-URL: https://github.com/libuv/libuv/pull/3259 Reviewed-By: Jameson Nash Reviewed-By: Santiago Gimeno --- src/win/fs-event.c | 6 +++--- test/test-fs-event.c | 49 +++++++++++++++++++++++++++++++++++++++++++- test/test-list.h | 2 ++ 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 0126c5ededf..76da077551d 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -574,10 +574,10 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, handle->cb(handle, NULL, 0, uv_translate_sys_error(err)); } - if (!(handle->flags & UV_HANDLE_CLOSING)) { - uv_fs_event_queue_readdirchanges(loop, handle); - } else { + if (handle->flags & UV_HANDLE_CLOSING) { uv_want_endgame(loop, (uv_handle_t*)handle); + } else if (uv__is_active(handle)) { + uv_fs_event_queue_readdirchanges(loop, handle); } } diff --git a/test/test-fs-event.c b/test/test-fs-event.c index ec163868f49..b04809db333 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -380,7 +380,7 @@ static void timer_cb_file(uv_timer_t* handle) { static void timer_cb_touch(uv_timer_t* timer) { uv_close((uv_handle_t*)timer, NULL); - touch_file("watch_file"); + touch_file((char*) timer->data); timer_cb_touch_called++; } @@ -730,6 +730,7 @@ TEST_IMPL(fs_event_watch_file_current_dir) { r = uv_timer_init(loop, &timer); ASSERT(r == 0); + timer.data = "watch_file"; r = uv_timer_start(&timer, timer_cb_touch, 1100, 0); ASSERT(r == 0); @@ -1174,3 +1175,49 @@ TEST_IMPL(fs_event_watch_invalid_path) { MAKE_VALGRIND_HAPPY(); return 0; } + +static int fs_event_cb_stop_calls; + +static void fs_event_cb_stop(uv_fs_event_t* handle, const char* path, + int events, int status) { + uv_fs_event_stop(handle); + fs_event_cb_stop_calls++; +} + +TEST_IMPL(fs_event_stop_in_cb) { + uv_fs_event_t fs; + uv_timer_t timer; + char path[] = "fs_event_stop_in_cb.txt"; + +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + + remove(path); + create_file(path); + + ASSERT_EQ(0, uv_fs_event_init(uv_default_loop(), &fs)); + ASSERT_EQ(0, uv_fs_event_start(&fs, fs_event_cb_stop, path, 0)); + + /* Note: timer_cb_touch() closes the handle. */ + timer.data = path; + ASSERT_EQ(0, uv_timer_init(uv_default_loop(), &timer)); + ASSERT_EQ(0, uv_timer_start(&timer, timer_cb_touch, 100, 0)); + + ASSERT_EQ(0, fs_event_cb_stop_calls); + ASSERT_EQ(0, timer_cb_touch_called); + + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT_EQ(1, fs_event_cb_stop_calls); + ASSERT_EQ(1, timer_cb_touch_called); + + uv_close((uv_handle_t*) &fs, NULL); + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, fs_event_cb_stop_calls); + + remove(path); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index f8ed94bce21..69a63ac5bdb 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -391,6 +391,7 @@ TEST_DECLARE (fs_event_close_in_callback) TEST_DECLARE (fs_event_start_and_close) TEST_DECLARE (fs_event_error_reporting) TEST_DECLARE (fs_event_getpath) +TEST_DECLARE (fs_event_stop_in_cb) TEST_DECLARE (fs_scandir_empty_dir) TEST_DECLARE (fs_scandir_non_existent_dir) TEST_DECLARE (fs_scandir_file) @@ -1052,6 +1053,7 @@ TASK_LIST_START TEST_ENTRY (fs_event_start_and_close) TEST_ENTRY_CUSTOM (fs_event_error_reporting, 0, 0, 60000) TEST_ENTRY (fs_event_getpath) + TEST_ENTRY (fs_event_stop_in_cb) TEST_ENTRY (fs_scandir_empty_dir) TEST_ENTRY (fs_scandir_non_existent_dir) TEST_ENTRY (fs_scandir_file)