fsevents: fix race on simultaneous init+close
When `uv_fsevents_t` handle is closed immediately after initializing, there is a possibility that the `CFRunLoop`'s thread will process both of these events at the same time. `uv__is_active(handle)` will return `0`, and the `uv_close()` semaphore will be unblocked, leading to the use after free in node.js. See: https://github.com/nodejs/node/issues/4091 PR-URL: https://github.com/libuv/libuv/pull/637 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
This commit is contained in:
parent
43994b4e3c
commit
0761bfe6a3
@ -73,9 +73,16 @@ typedef struct uv__fsevents_event_s uv__fsevents_event_t;
|
||||
typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
|
||||
typedef struct uv__cf_loop_state_s uv__cf_loop_state_t;
|
||||
|
||||
enum uv__cf_loop_signal_type_e {
|
||||
kUVCFLoopSignalRegular,
|
||||
kUVCFLoopSignalClosing
|
||||
};
|
||||
typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t;
|
||||
|
||||
struct uv__cf_loop_signal_s {
|
||||
QUEUE member;
|
||||
uv_fs_event_t* handle;
|
||||
uv__cf_loop_signal_type_t type;
|
||||
};
|
||||
|
||||
struct uv__fsevents_event_s {
|
||||
@ -98,7 +105,9 @@ struct uv__cf_loop_state_s {
|
||||
/* Forward declarations */
|
||||
static void uv__cf_loop_cb(void* arg);
|
||||
static void* uv__cf_loop_runner(void* arg);
|
||||
static int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle);
|
||||
static int uv__cf_loop_signal(uv_loop_t* loop,
|
||||
uv_fs_event_t* handle,
|
||||
uv__cf_loop_signal_type_t type);
|
||||
|
||||
/* Lazy-loaded by uv__fsevents_global_init(). */
|
||||
static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef,
|
||||
@ -383,7 +392,8 @@ static void uv__fsevents_destroy_stream(uv_loop_t* loop) {
|
||||
|
||||
|
||||
/* Runs in CF thread, when there're new fsevent handles to add to stream */
|
||||
static void uv__fsevents_reschedule(uv_fs_event_t* handle) {
|
||||
static void uv__fsevents_reschedule(uv_fs_event_t* handle,
|
||||
uv__cf_loop_signal_type_t type) {
|
||||
uv__cf_loop_state_t* state;
|
||||
QUEUE* q;
|
||||
uv_fs_event_t* curr;
|
||||
@ -482,7 +492,7 @@ final:
|
||||
*
|
||||
* NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close`
|
||||
*/
|
||||
if (!uv__is_active(handle))
|
||||
if (type == kUVCFLoopSignalClosing)
|
||||
uv_sem_post(&state->fsevent_sem);
|
||||
}
|
||||
|
||||
@ -672,7 +682,7 @@ void uv__fsevents_loop_delete(uv_loop_t* loop) {
|
||||
if (loop->cf_state == NULL)
|
||||
return;
|
||||
|
||||
if (uv__cf_loop_signal(loop, NULL) != 0)
|
||||
if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0)
|
||||
abort();
|
||||
|
||||
uv_thread_join(&loop->cf_thread);
|
||||
@ -746,7 +756,7 @@ static void uv__cf_loop_cb(void* arg) {
|
||||
if (s->handle == NULL)
|
||||
pCFRunLoopStop(state->loop);
|
||||
else
|
||||
uv__fsevents_reschedule(s->handle);
|
||||
uv__fsevents_reschedule(s->handle, s->type);
|
||||
|
||||
uv__free(s);
|
||||
}
|
||||
@ -754,7 +764,9 @@ static void uv__cf_loop_cb(void* arg) {
|
||||
|
||||
|
||||
/* Runs in UV loop to notify CF thread */
|
||||
int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
int uv__cf_loop_signal(uv_loop_t* loop,
|
||||
uv_fs_event_t* handle,
|
||||
uv__cf_loop_signal_type_t type) {
|
||||
uv__cf_loop_signal_t* item;
|
||||
uv__cf_loop_state_t* state;
|
||||
|
||||
@ -763,6 +775,7 @@ int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
return -ENOMEM;
|
||||
|
||||
item->handle = handle;
|
||||
item->type = type;
|
||||
|
||||
uv_mutex_lock(&loop->cf_mutex);
|
||||
QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
|
||||
@ -825,7 +838,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
|
||||
|
||||
/* Reschedule FSEventStream */
|
||||
assert(handle != NULL);
|
||||
err = uv__cf_loop_signal(handle->loop, handle);
|
||||
err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular);
|
||||
if (err)
|
||||
goto fail_loop_signal;
|
||||
|
||||
@ -865,7 +878,7 @@ int uv__fsevents_close(uv_fs_event_t* handle) {
|
||||
|
||||
/* Reschedule FSEventStream */
|
||||
assert(handle != NULL);
|
||||
err = uv__cf_loop_signal(handle->loop, handle);
|
||||
err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing);
|
||||
if (err)
|
||||
return -err;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user