-
-
Notifications
You must be signed in to change notification settings - Fork 33.9k
fs: fix potential segfault in async calls #18811
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -518,6 +518,7 @@ class fs_req_wrap { | |
| DISALLOW_COPY_AND_ASSIGN(fs_req_wrap); | ||
| }; | ||
|
|
||
| // Returns nullptr if the operation fails from the start. | ||
| template <typename Func, typename... Args> | ||
| inline FSReqBase* AsyncDestCall(Environment* env, | ||
| FSReqBase* req_wrap, | ||
|
|
@@ -532,16 +533,17 @@ inline FSReqBase* AsyncDestCall(Environment* env, | |
| uv_fs_t* uv_req = req_wrap->req(); | ||
| uv_req->result = err; | ||
| uv_req->path = nullptr; | ||
| after(uv_req); | ||
| after(uv_req); // after may delete req_wrap if there is an error | ||
| req_wrap = nullptr; | ||
| } | ||
|
|
||
| if (req_wrap != nullptr) { | ||
| args.GetReturnValue().Set(req_wrap->persistent()); | ||
| req_wrap->SetReturnValue(args); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: it is possible for
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The after callback should always run on the main thread; only the work callback runs in a different thread.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @bnoordhuis Just to make sure I am understanding correctly here..can I assume the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's right.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @bnoordhuis Thanks, I think I understand what's going on with diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c
index e0969a4c2f..f0446110f2 100644
--- a/deps/uv/src/unix/fs.c
+++ b/deps/uv/src/unix/fs.c
@@ -1513,8 +1513,11 @@ int uv_fs_copyfile(uv_loop_t* loop,
uv_fs_cb cb) {
INIT(COPYFILE);
- if (flags & ~UV_FS_COPYFILE_EXCL)
+ if (flags & ~UV_FS_COPYFILE_EXCL) {
+ if (cb != NULL)
+ uv__req_unregister(loop, req);
return -EINVAL;
+ }
PATH2;
req->flags = flags;
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, the bug is obvious in hindsight... the flags check should be done before
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @bnoordhuis Yes, checking the flags before INIT seems more reasonable...would love to try to open a PR to libuv since I have not done that before. I will do that once I get to somewhere I can open my laptop. |
||
| } | ||
| return req_wrap; | ||
| } | ||
|
|
||
| // Returns nullptr if the operation fails from the start. | ||
| template <typename Func, typename... Args> | ||
| inline FSReqBase* AsyncCall(Environment* env, | ||
| FSReqBase* req_wrap, | ||
|
|
@@ -620,7 +622,6 @@ void Access(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { // access(path, mode, req) | ||
| AsyncCall(env, req_wrap, args, "access", UTF8, AfterNoArgs, | ||
| uv_fs_access, *path, mode); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { // access(path, mode, undefined, ctx) | ||
| CHECK_EQ(argc, 4); | ||
| fs_req_wrap req_wrap; | ||
|
|
@@ -642,7 +643,6 @@ void Close(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { // close(fd, req) | ||
| AsyncCall(env, req_wrap, args, "close", UTF8, AfterNoArgs, | ||
| uv_fs_close, fd); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { // close(fd, undefined, ctx) | ||
| CHECK_EQ(argc, 3); | ||
| fs_req_wrap req_wrap; | ||
|
|
@@ -751,7 +751,6 @@ static void Stat(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { // stat(path, req) | ||
| AsyncCall(env, req_wrap, args, "stat", UTF8, AfterStat, | ||
| uv_fs_stat, *path); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { // stat(path, undefined, ctx) | ||
| CHECK_EQ(argc, 3); | ||
| fs_req_wrap req_wrap; | ||
|
|
@@ -776,7 +775,6 @@ static void LStat(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { // lstat(path, req) | ||
| AsyncCall(env, req_wrap, args, "lstat", UTF8, AfterStat, | ||
| uv_fs_lstat, *path); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { // lstat(path, undefined, ctx) | ||
| CHECK_EQ(argc, 3); | ||
| fs_req_wrap req_wrap; | ||
|
|
@@ -801,7 +799,6 @@ static void FStat(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { // fstat(fd, req) | ||
| AsyncCall(env, req_wrap, args, "fstat", UTF8, AfterStat, | ||
| uv_fs_fstat, fd); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { // fstat(fd, undefined, ctx) | ||
| CHECK_EQ(argc, 3); | ||
| fs_req_wrap req_wrap; | ||
|
|
@@ -855,7 +852,6 @@ static void Link(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { // link(src, dest, req) | ||
| AsyncDestCall(env, req_wrap, args, "link", *dest, dest.length(), UTF8, | ||
| AfterNoArgs, uv_fs_link, *src, *dest); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { // link(src, dest) | ||
| CHECK_EQ(argc, 4); | ||
| fs_req_wrap req; | ||
|
|
@@ -879,7 +875,6 @@ static void ReadLink(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { // readlink(path, encoding, req) | ||
| AsyncCall(env, req_wrap, args, "readlink", encoding, AfterStringPtr, | ||
| uv_fs_readlink, *path); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| CHECK_EQ(argc, 4); | ||
| fs_req_wrap req; | ||
|
|
@@ -920,7 +915,6 @@ static void Rename(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncDestCall(env, req_wrap, args, "rename", *new_path, new_path.length(), | ||
| UTF8, AfterNoArgs, uv_fs_rename, *old_path, *new_path); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| CHECK_EQ(argc, 4); | ||
| fs_req_wrap req; | ||
|
|
@@ -944,7 +938,6 @@ static void FTruncate(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "ftruncate", UTF8, AfterNoArgs, | ||
| uv_fs_ftruncate, fd, len); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| CHECK_EQ(argc, 4); | ||
| fs_req_wrap req; | ||
|
|
@@ -965,7 +958,6 @@ static void Fdatasync(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "fdatasync", UTF8, AfterNoArgs, | ||
| uv_fs_fdatasync, fd); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| CHECK_EQ(argc, 3); | ||
| fs_req_wrap req; | ||
|
|
@@ -986,7 +978,6 @@ static void Fsync(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "fsync", UTF8, AfterNoArgs, | ||
| uv_fs_fsync, fd); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| CHECK_EQ(argc, 3); | ||
| fs_req_wrap req; | ||
|
|
@@ -1007,7 +998,6 @@ static void Unlink(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "unlink", UTF8, AfterNoArgs, | ||
| uv_fs_unlink, *path); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| CHECK_EQ(argc, 3); | ||
| fs_req_wrap req; | ||
|
|
@@ -1027,7 +1017,6 @@ static void RMDir(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "rmdir", UTF8, AfterNoArgs, | ||
| uv_fs_rmdir, *path); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(rmdir, *path, *path) | ||
| } | ||
|
|
@@ -1048,7 +1037,6 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "mkdir", UTF8, AfterNoArgs, | ||
| uv_fs_mkdir, *path, mode); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(mkdir, *path, *path, mode) | ||
| } | ||
|
|
@@ -1066,7 +1054,6 @@ static void RealPath(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "realpath", encoding, AfterStringPtr, | ||
| uv_fs_realpath, *path); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(realpath, *path, *path); | ||
| const char* link_path = static_cast<const char*>(SYNC_REQ.ptr); | ||
|
|
@@ -1098,7 +1085,6 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "scandir", encoding, AfterScanDir, | ||
| uv_fs_scandir, *path, 0 /*flags*/); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(scandir, *path, *path, 0 /*flags*/) | ||
|
|
||
|
|
@@ -1169,7 +1155,6 @@ static void Open(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "open", UTF8, AfterInteger, | ||
| uv_fs_open, *path, flags, mode); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(open, *path, *path, flags, mode) | ||
| args.GetReturnValue().Set(SYNC_RESULT); | ||
|
|
@@ -1194,7 +1179,6 @@ static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "open", UTF8, AfterOpenFileHandle, | ||
| uv_fs_open, *path, flags, mode); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(open, *path, *path, flags, mode) | ||
| HandleScope scope(env->isolate()); | ||
|
|
@@ -1219,7 +1203,6 @@ static void CopyFile(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "copyfile", UTF8, AfterNoArgs, | ||
| uv_fs_copyfile, *src, *dest, flags); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_DEST_CALL(copyfile, *src, *dest, *src, *dest, flags) | ||
| } | ||
|
|
@@ -1262,7 +1245,7 @@ static void WriteBuffer(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "write", UTF8, AfterInteger, | ||
| uv_fs_write, fd, &uvbuf, 1, pos); | ||
| return req_wrap->SetReturnValue(args); | ||
| return; | ||
| } | ||
|
|
||
| SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos) | ||
|
|
@@ -1299,7 +1282,7 @@ static void WriteBuffers(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "write", UTF8, AfterInteger, | ||
| uv_fs_write, fd, *iovs, iovs.length(), pos); | ||
| return req_wrap->SetReturnValue(args); | ||
| return; | ||
| } | ||
|
|
||
| SYNC_CALL(write, nullptr, fd, *iovs, iovs.length(), pos) | ||
|
|
@@ -1367,7 +1350,6 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "write", UTF8, AfterInteger, | ||
| uv_fs_write, fd, &uvbuf, 1, pos); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos) | ||
| return args.GetReturnValue().Set(SYNC_RESULT); | ||
|
|
@@ -1422,7 +1404,6 @@ static void Read(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "read", UTF8, AfterInteger, | ||
| uv_fs_read, fd, &uvbuf, 1, pos); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(read, 0, fd, &uvbuf, 1, pos) | ||
| args.GetReturnValue().Set(SYNC_RESULT); | ||
|
|
@@ -1448,7 +1429,6 @@ static void Chmod(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "chmod", UTF8, AfterNoArgs, | ||
| uv_fs_chmod, *path, mode); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(chmod, *path, *path, mode); | ||
| } | ||
|
|
@@ -1471,7 +1451,6 @@ static void FChmod(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "fchmod", UTF8, AfterNoArgs, | ||
| uv_fs_fchmod, fd, mode); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(fchmod, 0, fd, mode); | ||
| } | ||
|
|
@@ -1499,7 +1478,6 @@ static void Chown(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "chown", UTF8, AfterNoArgs, | ||
| uv_fs_chown, *path, uid, gid); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(chown, *path, *path, uid, gid); | ||
| } | ||
|
|
@@ -1524,7 +1502,6 @@ static void FChown(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "fchown", UTF8, AfterNoArgs, | ||
| uv_fs_fchown, fd, uid, gid); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(fchown, 0, fd, uid, gid); | ||
| } | ||
|
|
@@ -1548,7 +1525,6 @@ static void UTimes(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "utime", UTF8, AfterNoArgs, | ||
| uv_fs_utime, *path, atime, mtime); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(utime, *path, *path, atime, mtime); | ||
| } | ||
|
|
@@ -1569,7 +1545,6 @@ static void FUTimes(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "futime", UTF8, AfterNoArgs, | ||
| uv_fs_futime, fd, atime, mtime); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(futime, 0, fd, atime, mtime); | ||
| } | ||
|
|
@@ -1589,7 +1564,6 @@ static void Mkdtemp(const FunctionCallbackInfo<Value>& args) { | |
| if (req_wrap != nullptr) { | ||
| AsyncCall(env, req_wrap, args, "mkdtemp", encoding, AfterStringPath, | ||
| uv_fs_mkdtemp, *tmpl); | ||
| req_wrap->SetReturnValue(args); | ||
| } else { | ||
| SYNC_CALL(mkdtemp, *tmpl, *tmpl); | ||
| const char* path = static_cast<const char*>(SYNC_REQ.path); | ||
|
|
||
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.
Since you're here, maybe change this
ifto anelseof the previous conditional. Makes the logic a little more obvious, IMO.