Skip to content

Commit d6f3b87

Browse files
committed
src: pass along errors from fs object creations
PR-URL: #25822 Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
1 parent 0672c24 commit d6f3b87

File tree

2 files changed

+71
-37
lines changed

2 files changed

+71
-37
lines changed

src/node_file.cc

+47-19
Original file line numberDiff line numberDiff line change
@@ -110,20 +110,29 @@ typedef void(*uv_fs_callback_t)(uv_fs_t*);
110110
// The FileHandle object wraps a file descriptor and will close it on garbage
111111
// collection if necessary. If that happens, a process warning will be
112112
// emitted (or a fatal exception will occur if the fd cannot be closed.)
113-
FileHandle::FileHandle(Environment* env, int fd, Local<Object> obj)
114-
: AsyncWrap(env,
115-
obj.IsEmpty() ? env->fd_constructor_template()
116-
->NewInstance(env->context()).ToLocalChecked() : obj,
117-
AsyncWrap::PROVIDER_FILEHANDLE),
113+
FileHandle::FileHandle(Environment* env, Local<Object> obj, int fd)
114+
: AsyncWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLE),
118115
StreamBase(env),
119116
fd_(fd) {
120117
MakeWeak();
118+
}
119+
120+
FileHandle* FileHandle::New(Environment* env, int fd, Local<Object> obj) {
121+
if (obj.IsEmpty() && !env->fd_constructor_template()
122+
->NewInstance(env->context())
123+
.ToLocal(&obj)) {
124+
return nullptr;
125+
}
121126
v8::PropertyAttribute attr =
122127
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
123-
object()->DefineOwnProperty(env->context(),
124-
FIXED_ONE_BYTE_STRING(env->isolate(), "fd"),
125-
Integer::New(env->isolate(), fd),
126-
attr).FromJust();
128+
if (obj->DefineOwnProperty(env->context(),
129+
env->fd_string(),
130+
Integer::New(env->isolate(), fd),
131+
attr)
132+
.IsNothing()) {
133+
return nullptr;
134+
}
135+
return new FileHandle(env, obj, fd);
127136
}
128137

129138
void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
@@ -132,7 +141,8 @@ void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
132141
CHECK(args[0]->IsInt32());
133142

134143
FileHandle* handle =
135-
new FileHandle(env, args[0].As<Int32>()->Value(), args.This());
144+
FileHandle::New(env, args[0].As<Int32>()->Value(), args.This());
145+
if (handle == nullptr) return;
136146
if (args[1]->IsNumber())
137147
handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
138148
if (args[2]->IsNumber())
@@ -232,7 +242,14 @@ inline MaybeLocal<Promise> FileHandle::ClosePromise() {
232242
CHECK(!reading_);
233243
if (!closed_ && !closing_) {
234244
closing_ = true;
235-
CloseReq* req = new CloseReq(env(), promise, object());
245+
Local<Object> close_req_obj;
246+
if (!env()
247+
->fdclose_constructor_template()
248+
->NewInstance(env()->context())
249+
.ToLocal(&close_req_obj)) {
250+
return MaybeLocal<Promise>();
251+
}
252+
CloseReq* req = new CloseReq(env(), close_req_obj, promise, object());
236253
auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
237254
std::unique_ptr<CloseReq> close(CloseReq::from_req(req));
238255
CHECK_NOT_NULL(close);
@@ -260,7 +277,9 @@ inline MaybeLocal<Promise> FileHandle::ClosePromise() {
260277
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
261278
FileHandle* fd;
262279
ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
263-
args.GetReturnValue().Set(fd->ClosePromise().ToLocalChecked());
280+
Local<Promise> ret;
281+
if (!fd->ClosePromise().ToLocal(&ret)) return;
282+
args.GetReturnValue().Set(ret);
264283
}
265284

266285

@@ -318,8 +337,13 @@ int FileHandle::ReadStart() {
318337
read_wrap->AsyncReset();
319338
read_wrap->file_handle_ = this;
320339
} else {
321-
Local<Object> wrap_obj = env()->filehandlereadwrap_template()
322-
->NewInstance(env()->context()).ToLocalChecked();
340+
Local<Object> wrap_obj;
341+
if (!env()
342+
->filehandlereadwrap_template()
343+
->NewInstance(env()->context())
344+
.ToLocal(&wrap_obj)) {
345+
return UV_EBUSY;
346+
}
323347
read_wrap.reset(new FileHandleReadWrap(this, wrap_obj));
324348
}
325349
}
@@ -520,7 +544,8 @@ void AfterOpenFileHandle(uv_fs_t* req) {
520544
FSReqAfterScope after(req_wrap, req);
521545

522546
if (after.Proceed()) {
523-
FileHandle* fd = new FileHandle(req_wrap->env(), req->result);
547+
FileHandle* fd = FileHandle::New(req_wrap->env(), req->result);
548+
if (fd == nullptr) return;
524549
req_wrap->Resolve(fd->object());
525550
}
526551
}
@@ -724,15 +749,18 @@ inline int SyncCall(Environment* env, Local<Value> ctx, FSReqWrapSync* req_wrap,
724749
return err;
725750
}
726751

752+
// TODO(addaleax): Currently, callers check the return value and assume
753+
// that nullptr indicates a synchronous call, rather than a failure.
754+
// Failure conditions should be disambiguated and handled appropriately.
727755
inline FSReqBase* GetReqWrap(Environment* env, Local<Value> value,
728756
bool use_bigint = false) {
729757
if (value->IsObject()) {
730758
return Unwrap<FSReqBase>(value.As<Object>());
731759
} else if (value->StrictEquals(env->fs_use_promises_symbol())) {
732760
if (use_bigint) {
733-
return new FSReqPromise<uint64_t, BigUint64Array>(env, use_bigint);
761+
return FSReqPromise<uint64_t, BigUint64Array>::New(env, use_bigint);
734762
} else {
735-
return new FSReqPromise<double, Float64Array>(env, use_bigint);
763+
return FSReqPromise<double, Float64Array>::New(env, use_bigint);
736764
}
737765
}
738766
return nullptr;
@@ -1562,8 +1590,8 @@ static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
15621590
if (result < 0) {
15631591
return; // syscall failed, no need to continue, error info is in ctx
15641592
}
1565-
HandleScope scope(isolate);
1566-
FileHandle* fd = new FileHandle(env, result);
1593+
FileHandle* fd = FileHandle::New(env, result);
1594+
if (fd == nullptr) return;
15671595
args.GetReturnValue().Set(fd->object());
15681596
}
15691597
}

src/node_file.h

+24-18
Original file line numberDiff line numberDiff line change
@@ -237,17 +237,19 @@ inline Local<Value> FillGlobalStatsArray(Environment* env,
237237
template <typename NativeT = double, typename V8T = v8::Float64Array>
238238
class FSReqPromise : public FSReqBase {
239239
public:
240-
explicit FSReqPromise(Environment* env, bool use_bigint)
241-
: FSReqBase(env,
242-
env->fsreqpromise_constructor_template()
243-
->NewInstance(env->context()).ToLocalChecked(),
244-
AsyncWrap::PROVIDER_FSREQPROMISE,
245-
use_bigint),
246-
stats_field_array_(env->isolate(), kFsStatsFieldsNumber) {
247-
const auto resolver =
248-
Promise::Resolver::New(env->context()).ToLocalChecked();
249-
USE(object()->Set(env->context(), env->promise_string(),
250-
resolver).FromJust());
240+
static FSReqPromise* New(Environment* env, bool use_bigint) {
241+
v8::Local<Object> obj;
242+
if (!env->fsreqpromise_constructor_template()
243+
->NewInstance(env->context())
244+
.ToLocal(&obj)) {
245+
return nullptr;
246+
}
247+
v8::Local<v8::Promise::Resolver> resolver;
248+
if (!v8::Promise::Resolver::New(env->context()).ToLocal(&resolver) ||
249+
obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) {
250+
return nullptr;
251+
}
252+
return new FSReqPromise(env, obj, use_bigint);
251253
}
252254

253255
~FSReqPromise() override {
@@ -304,6 +306,10 @@ class FSReqPromise : public FSReqBase {
304306
FSReqPromise& operator=(const FSReqPromise&&) = delete;
305307

306308
private:
309+
FSReqPromise(Environment* env, v8::Local<v8::Object> obj, bool use_bigint)
310+
: FSReqBase(env, obj, AsyncWrap::PROVIDER_FSREQPROMISE, use_bigint),
311+
stats_field_array_(env->isolate(), kFsStatsFieldsNumber) {}
312+
307313
bool finished_ = false;
308314
AliasedBuffer<NativeT, V8T> stats_field_array_;
309315
};
@@ -356,9 +362,9 @@ class FileHandleReadWrap : public ReqWrap<uv_fs_t> {
356362
// the object is garbage collected
357363
class FileHandle : public AsyncWrap, public StreamBase {
358364
public:
359-
FileHandle(Environment* env,
360-
int fd,
361-
v8::Local<v8::Object> obj = v8::Local<v8::Object>());
365+
static FileHandle* New(Environment* env,
366+
int fd,
367+
v8::Local<v8::Object> obj = v8::Local<v8::Object>());
362368
virtual ~FileHandle();
363369

364370
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -404,19 +410,19 @@ class FileHandle : public AsyncWrap, public StreamBase {
404410
FileHandle& operator=(const FileHandle&&) = delete;
405411

406412
private:
413+
FileHandle(Environment* env, v8::Local<v8::Object> obj, int fd);
414+
407415
// Synchronous close that emits a warning
408416
void Close();
409417
void AfterClose();
410418

411419
class CloseReq : public ReqWrap<uv_fs_t> {
412420
public:
413421
CloseReq(Environment* env,
422+
Local<Object> obj,
414423
Local<Promise> promise,
415424
Local<Value> ref)
416-
: ReqWrap(env,
417-
env->fdclose_constructor_template()
418-
->NewInstance(env->context()).ToLocalChecked(),
419-
AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
425+
: ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
420426
promise_.Reset(env->isolate(), promise);
421427
ref_.Reset(env->isolate(), ref);
422428
}

0 commit comments

Comments
 (0)