diff options
author | Anna Henningsen <anna@addaleax.net> | 2020-05-07 02:30:36 +0300 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2020-05-15 20:36:48 +0300 |
commit | e9f293750760d59243020d0376edf242c9a26b67 (patch) | |
tree | bfa905e137940a3d530b1008b5b0327f0bd22f7a /src/node_file.h | |
parent | 441e703b2851be4c0f924907ff3c20cc4bab8588 (diff) |
fs: clean up Dir.read() uv_fs_t data before calling into JS
A call into JS can schedule another operation on the same `uv_dir_t`.
In particular, when the handle is closed from the callback for a
directory read operation, there previously was a race condition window:
1. A `dir.read()` operation is submitted to libuv
2. The read operation is finished by libuv, calling `AfterDirRead()`
3. We call into JS
4. JS calls dir.close()
5. libuv posts the close request to a thread in the pool
6. The close request runs, destroying the directory handle
7. `AfterDirRead()` is being exited.
Exiting the `FSReqAfterScope` in step 7 attempts to destroy the original
uv_fs_t` from step 1, which now points to an `uv_dir_t` that has
already been destroyed in step 5.
By forcing the `FSReqAfterScope` to clean up before we call into JS,
we can be sure that no other operations on the same `uv_dir_t` are
submitted concurrently.
This addresses issues observed when running with ASAN/valgrind.
PR-URL: https://github.com/nodejs/node/pull/33274
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Diffstat (limited to 'src/node_file.h')
-rw-r--r-- | src/node_file.h | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/src/node_file.h b/src/node_file.h index 7690f272848..39c9034f669 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -184,6 +184,7 @@ class FSReqAfterScope final { public: FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req); ~FSReqAfterScope(); + void Clear(); bool Proceed(); @@ -195,7 +196,7 @@ class FSReqAfterScope final { FSReqAfterScope& operator=(const FSReqAfterScope&&) = delete; private: - FSReqBase* wrap_ = nullptr; + BaseObjectPtr<FSReqBase> wrap_; uv_fs_t* req_ = nullptr; v8::HandleScope handle_scope_; v8::Context::Scope context_scope_; |