Skip to content

Commit 12412ef

Browse files
committed
fs: fix potential segfault in async calls
When the async uv_fs_* call errors out synchronously in AsyncDestCall, the after callbacks (e.g. AfterNoArgs) would delete the req_wrap in FSReqAfterScope, and AsyncDestCall would set those req_wrap to nullptr afterwards. But when it returns to the top-layer bindings, the bindings all call `req_wrap->SetReturnValue()` again without checking if `req_wrap` is nullptr, causing a segfault. This has not been caught in any of the tests because we usually do a lot of argument checking in the JS layer before invoking the uv_fs_* functions, so it's rare to get a synchronous error from them. Currently we never need the binding to return the wrap to JS layer, so we can just call `req_wrap->SetReturnValue()` to return undefined for normal FSReqWrap and the promise for FSReqPromise in AsyncDestCall instead of doing this in the top-level bindings. PR-URL: #18811 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
1 parent 472cde6 commit 12412ef

File tree

1 file changed

+7
-34
lines changed

1 file changed

+7
-34
lines changed

src/node_file.cc

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ class fs_req_wrap {
516516
DISALLOW_COPY_AND_ASSIGN(fs_req_wrap);
517517
};
518518

519+
// Returns nullptr if the operation fails from the start.
519520
template <typename Func, typename... Args>
520521
inline FSReqBase* AsyncDestCall(Environment* env,
521522
FSReqBase* req_wrap,
@@ -530,16 +531,16 @@ inline FSReqBase* AsyncDestCall(Environment* env,
530531
uv_fs_t* uv_req = req_wrap->req();
531532
uv_req->result = err;
532533
uv_req->path = nullptr;
533-
after(uv_req);
534+
after(uv_req); // after may delete req_wrap if there is an error
534535
req_wrap = nullptr;
536+
} else {
537+
req_wrap->SetReturnValue(args);
535538
}
536539

537-
if (req_wrap != nullptr) {
538-
args.GetReturnValue().Set(req_wrap->persistent());
539-
}
540540
return req_wrap;
541541
}
542542

543+
// Returns nullptr if the operation fails from the start.
543544
template <typename Func, typename... Args>
544545
inline FSReqBase* AsyncCall(Environment* env,
545546
FSReqBase* req_wrap,
@@ -618,7 +619,6 @@ void Access(const FunctionCallbackInfo<Value>& args) {
618619
if (req_wrap != nullptr) { // access(path, mode, req)
619620
AsyncCall(env, req_wrap, args, "access", UTF8, AfterNoArgs,
620621
uv_fs_access, *path, mode);
621-
req_wrap->SetReturnValue(args);
622622
} else { // access(path, mode, undefined, ctx)
623623
CHECK_EQ(argc, 4);
624624
fs_req_wrap req_wrap;
@@ -640,7 +640,6 @@ void Close(const FunctionCallbackInfo<Value>& args) {
640640
if (req_wrap != nullptr) { // close(fd, req)
641641
AsyncCall(env, req_wrap, args, "close", UTF8, AfterNoArgs,
642642
uv_fs_close, fd);
643-
req_wrap->SetReturnValue(args);
644643
} else { // close(fd, undefined, ctx)
645644
CHECK_EQ(argc, 3);
646645
fs_req_wrap req_wrap;
@@ -749,7 +748,6 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
749748
if (req_wrap != nullptr) { // stat(path, req)
750749
AsyncCall(env, req_wrap, args, "stat", UTF8, AfterStat,
751750
uv_fs_stat, *path);
752-
req_wrap->SetReturnValue(args);
753751
} else { // stat(path, undefined, ctx)
754752
CHECK_EQ(argc, 3);
755753
fs_req_wrap req_wrap;
@@ -774,7 +772,6 @@ static void LStat(const FunctionCallbackInfo<Value>& args) {
774772
if (req_wrap != nullptr) { // lstat(path, req)
775773
AsyncCall(env, req_wrap, args, "lstat", UTF8, AfterStat,
776774
uv_fs_lstat, *path);
777-
req_wrap->SetReturnValue(args);
778775
} else { // lstat(path, undefined, ctx)
779776
CHECK_EQ(argc, 3);
780777
fs_req_wrap req_wrap;
@@ -799,7 +796,6 @@ static void FStat(const FunctionCallbackInfo<Value>& args) {
799796
if (req_wrap != nullptr) { // fstat(fd, req)
800797
AsyncCall(env, req_wrap, args, "fstat", UTF8, AfterStat,
801798
uv_fs_fstat, fd);
802-
req_wrap->SetReturnValue(args);
803799
} else { // fstat(fd, undefined, ctx)
804800
CHECK_EQ(argc, 3);
805801
fs_req_wrap req_wrap;
@@ -853,7 +849,6 @@ static void Link(const FunctionCallbackInfo<Value>& args) {
853849
if (req_wrap != nullptr) { // link(src, dest, req)
854850
AsyncDestCall(env, req_wrap, args, "link", *dest, dest.length(), UTF8,
855851
AfterNoArgs, uv_fs_link, *src, *dest);
856-
req_wrap->SetReturnValue(args);
857852
} else { // link(src, dest)
858853
CHECK_EQ(argc, 4);
859854
fs_req_wrap req;
@@ -877,7 +872,6 @@ static void ReadLink(const FunctionCallbackInfo<Value>& args) {
877872
if (req_wrap != nullptr) { // readlink(path, encoding, req)
878873
AsyncCall(env, req_wrap, args, "readlink", encoding, AfterStringPtr,
879874
uv_fs_readlink, *path);
880-
req_wrap->SetReturnValue(args);
881875
} else {
882876
CHECK_EQ(argc, 4);
883877
fs_req_wrap req;
@@ -918,7 +912,6 @@ static void Rename(const FunctionCallbackInfo<Value>& args) {
918912
if (req_wrap != nullptr) {
919913
AsyncDestCall(env, req_wrap, args, "rename", *new_path, new_path.length(),
920914
UTF8, AfterNoArgs, uv_fs_rename, *old_path, *new_path);
921-
req_wrap->SetReturnValue(args);
922915
} else {
923916
CHECK_EQ(argc, 4);
924917
fs_req_wrap req;
@@ -942,7 +935,6 @@ static void FTruncate(const FunctionCallbackInfo<Value>& args) {
942935
if (req_wrap != nullptr) {
943936
AsyncCall(env, req_wrap, args, "ftruncate", UTF8, AfterNoArgs,
944937
uv_fs_ftruncate, fd, len);
945-
req_wrap->SetReturnValue(args);
946938
} else {
947939
CHECK_EQ(argc, 4);
948940
fs_req_wrap req;
@@ -963,7 +955,6 @@ static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
963955
if (req_wrap != nullptr) {
964956
AsyncCall(env, req_wrap, args, "fdatasync", UTF8, AfterNoArgs,
965957
uv_fs_fdatasync, fd);
966-
req_wrap->SetReturnValue(args);
967958
} else {
968959
CHECK_EQ(argc, 3);
969960
fs_req_wrap req;
@@ -984,7 +975,6 @@ static void Fsync(const FunctionCallbackInfo<Value>& args) {
984975
if (req_wrap != nullptr) {
985976
AsyncCall(env, req_wrap, args, "fsync", UTF8, AfterNoArgs,
986977
uv_fs_fsync, fd);
987-
req_wrap->SetReturnValue(args);
988978
} else {
989979
CHECK_EQ(argc, 3);
990980
fs_req_wrap req;
@@ -1005,7 +995,6 @@ static void Unlink(const FunctionCallbackInfo<Value>& args) {
1005995
if (req_wrap != nullptr) {
1006996
AsyncCall(env, req_wrap, args, "unlink", UTF8, AfterNoArgs,
1007997
uv_fs_unlink, *path);
1008-
req_wrap->SetReturnValue(args);
1009998
} else {
1010999
CHECK_EQ(argc, 3);
10111000
fs_req_wrap req;
@@ -1025,7 +1014,6 @@ static void RMDir(const FunctionCallbackInfo<Value>& args) {
10251014
if (req_wrap != nullptr) {
10261015
AsyncCall(env, req_wrap, args, "rmdir", UTF8, AfterNoArgs,
10271016
uv_fs_rmdir, *path);
1028-
req_wrap->SetReturnValue(args);
10291017
} else {
10301018
SYNC_CALL(rmdir, *path, *path)
10311019
}
@@ -1046,7 +1034,6 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) {
10461034
if (req_wrap != nullptr) {
10471035
AsyncCall(env, req_wrap, args, "mkdir", UTF8, AfterNoArgs,
10481036
uv_fs_mkdir, *path, mode);
1049-
req_wrap->SetReturnValue(args);
10501037
} else {
10511038
SYNC_CALL(mkdir, *path, *path, mode)
10521039
}
@@ -1064,7 +1051,6 @@ static void RealPath(const FunctionCallbackInfo<Value>& args) {
10641051
if (req_wrap != nullptr) {
10651052
AsyncCall(env, req_wrap, args, "realpath", encoding, AfterStringPtr,
10661053
uv_fs_realpath, *path);
1067-
req_wrap->SetReturnValue(args);
10681054
} else {
10691055
SYNC_CALL(realpath, *path, *path);
10701056
const char* link_path = static_cast<const char*>(SYNC_REQ.ptr);
@@ -1096,7 +1082,6 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) {
10961082
if (req_wrap != nullptr) {
10971083
AsyncCall(env, req_wrap, args, "scandir", encoding, AfterScanDir,
10981084
uv_fs_scandir, *path, 0 /*flags*/);
1099-
req_wrap->SetReturnValue(args);
11001085
} else {
11011086
SYNC_CALL(scandir, *path, *path, 0 /*flags*/)
11021087

@@ -1167,7 +1152,6 @@ static void Open(const FunctionCallbackInfo<Value>& args) {
11671152
if (req_wrap != nullptr) {
11681153
AsyncCall(env, req_wrap, args, "open", UTF8, AfterInteger,
11691154
uv_fs_open, *path, flags, mode);
1170-
req_wrap->SetReturnValue(args);
11711155
} else {
11721156
SYNC_CALL(open, *path, *path, flags, mode)
11731157
args.GetReturnValue().Set(SYNC_RESULT);
@@ -1192,7 +1176,6 @@ static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
11921176
if (req_wrap != nullptr) {
11931177
AsyncCall(env, req_wrap, args, "open", UTF8, AfterOpenFileHandle,
11941178
uv_fs_open, *path, flags, mode);
1195-
req_wrap->SetReturnValue(args);
11961179
} else {
11971180
SYNC_CALL(open, *path, *path, flags, mode)
11981181
HandleScope scope(env->isolate());
@@ -1217,7 +1200,6 @@ static void CopyFile(const FunctionCallbackInfo<Value>& args) {
12171200
if (req_wrap != nullptr) {
12181201
AsyncCall(env, req_wrap, args, "copyfile", UTF8, AfterNoArgs,
12191202
uv_fs_copyfile, *src, *dest, flags);
1220-
req_wrap->SetReturnValue(args);
12211203
} else {
12221204
SYNC_DEST_CALL(copyfile, *src, *dest, *src, *dest, flags)
12231205
}
@@ -1260,7 +1242,7 @@ static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
12601242
if (req_wrap != nullptr) {
12611243
AsyncCall(env, req_wrap, args, "write", UTF8, AfterInteger,
12621244
uv_fs_write, fd, &uvbuf, 1, pos);
1263-
return req_wrap->SetReturnValue(args);
1245+
return;
12641246
}
12651247

12661248
SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos)
@@ -1297,7 +1279,7 @@ static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
12971279
if (req_wrap != nullptr) {
12981280
AsyncCall(env, req_wrap, args, "write", UTF8, AfterInteger,
12991281
uv_fs_write, fd, *iovs, iovs.length(), pos);
1300-
return req_wrap->SetReturnValue(args);
1282+
return;
13011283
}
13021284

13031285
SYNC_CALL(write, nullptr, fd, *iovs, iovs.length(), pos)
@@ -1365,7 +1347,6 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
13651347
if (req_wrap != nullptr) {
13661348
AsyncCall(env, req_wrap, args, "write", UTF8, AfterInteger,
13671349
uv_fs_write, fd, &uvbuf, 1, pos);
1368-
req_wrap->SetReturnValue(args);
13691350
} else {
13701351
SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos)
13711352
return args.GetReturnValue().Set(SYNC_RESULT);
@@ -1420,7 +1401,6 @@ static void Read(const FunctionCallbackInfo<Value>& args) {
14201401
if (req_wrap != nullptr) {
14211402
AsyncCall(env, req_wrap, args, "read", UTF8, AfterInteger,
14221403
uv_fs_read, fd, &uvbuf, 1, pos);
1423-
req_wrap->SetReturnValue(args);
14241404
} else {
14251405
SYNC_CALL(read, 0, fd, &uvbuf, 1, pos)
14261406
args.GetReturnValue().Set(SYNC_RESULT);
@@ -1446,7 +1426,6 @@ static void Chmod(const FunctionCallbackInfo<Value>& args) {
14461426
if (req_wrap != nullptr) {
14471427
AsyncCall(env, req_wrap, args, "chmod", UTF8, AfterNoArgs,
14481428
uv_fs_chmod, *path, mode);
1449-
req_wrap->SetReturnValue(args);
14501429
} else {
14511430
SYNC_CALL(chmod, *path, *path, mode);
14521431
}
@@ -1469,7 +1448,6 @@ static void FChmod(const FunctionCallbackInfo<Value>& args) {
14691448
if (req_wrap != nullptr) {
14701449
AsyncCall(env, req_wrap, args, "fchmod", UTF8, AfterNoArgs,
14711450
uv_fs_fchmod, fd, mode);
1472-
req_wrap->SetReturnValue(args);
14731451
} else {
14741452
SYNC_CALL(fchmod, 0, fd, mode);
14751453
}
@@ -1497,7 +1475,6 @@ static void Chown(const FunctionCallbackInfo<Value>& args) {
14971475
if (req_wrap != nullptr) {
14981476
AsyncCall(env, req_wrap, args, "chown", UTF8, AfterNoArgs,
14991477
uv_fs_chown, *path, uid, gid);
1500-
req_wrap->SetReturnValue(args);
15011478
} else {
15021479
SYNC_CALL(chown, *path, *path, uid, gid);
15031480
}
@@ -1522,7 +1499,6 @@ static void FChown(const FunctionCallbackInfo<Value>& args) {
15221499
if (req_wrap != nullptr) {
15231500
AsyncCall(env, req_wrap, args, "fchown", UTF8, AfterNoArgs,
15241501
uv_fs_fchown, fd, uid, gid);
1525-
req_wrap->SetReturnValue(args);
15261502
} else {
15271503
SYNC_CALL(fchown, 0, fd, uid, gid);
15281504
}
@@ -1546,7 +1522,6 @@ static void UTimes(const FunctionCallbackInfo<Value>& args) {
15461522
if (req_wrap != nullptr) {
15471523
AsyncCall(env, req_wrap, args, "utime", UTF8, AfterNoArgs,
15481524
uv_fs_utime, *path, atime, mtime);
1549-
req_wrap->SetReturnValue(args);
15501525
} else {
15511526
SYNC_CALL(utime, *path, *path, atime, mtime);
15521527
}
@@ -1567,7 +1542,6 @@ static void FUTimes(const FunctionCallbackInfo<Value>& args) {
15671542
if (req_wrap != nullptr) {
15681543
AsyncCall(env, req_wrap, args, "futime", UTF8, AfterNoArgs,
15691544
uv_fs_futime, fd, atime, mtime);
1570-
req_wrap->SetReturnValue(args);
15711545
} else {
15721546
SYNC_CALL(futime, 0, fd, atime, mtime);
15731547
}
@@ -1587,7 +1561,6 @@ static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
15871561
if (req_wrap != nullptr) {
15881562
AsyncCall(env, req_wrap, args, "mkdtemp", encoding, AfterStringPath,
15891563
uv_fs_mkdtemp, *tmpl);
1590-
req_wrap->SetReturnValue(args);
15911564
} else {
15921565
SYNC_CALL(mkdtemp, *tmpl, *tmpl);
15931566
const char* path = static_cast<const char*>(SYNC_REQ.path);

0 commit comments

Comments
 (0)