diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/node_file.cc | 66 | ||||
-rw-r--r-- | src/node_file.h | 42 |
2 files changed, 71 insertions, 37 deletions
diff --git a/src/node_file.cc b/src/node_file.cc index 35c8e01a28..5513be3d7c 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -110,20 +110,29 @@ typedef void(*uv_fs_callback_t)(uv_fs_t*); // The FileHandle object wraps a file descriptor and will close it on garbage // collection if necessary. If that happens, a process warning will be // emitted (or a fatal exception will occur if the fd cannot be closed.) -FileHandle::FileHandle(Environment* env, int fd, Local<Object> obj) - : AsyncWrap(env, - obj.IsEmpty() ? env->fd_constructor_template() - ->NewInstance(env->context()).ToLocalChecked() : obj, - AsyncWrap::PROVIDER_FILEHANDLE), +FileHandle::FileHandle(Environment* env, Local<Object> obj, int fd) + : AsyncWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLE), StreamBase(env), fd_(fd) { MakeWeak(); +} + +FileHandle* FileHandle::New(Environment* env, int fd, Local<Object> obj) { + if (obj.IsEmpty() && !env->fd_constructor_template() + ->NewInstance(env->context()) + .ToLocal(&obj)) { + return nullptr; + } v8::PropertyAttribute attr = static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); - object()->DefineOwnProperty(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "fd"), - Integer::New(env->isolate(), fd), - attr).FromJust(); + if (obj->DefineOwnProperty(env->context(), + env->fd_string(), + Integer::New(env->isolate(), fd), + attr) + .IsNothing()) { + return nullptr; + } + return new FileHandle(env, obj, fd); } void FileHandle::New(const FunctionCallbackInfo<Value>& args) { @@ -132,7 +141,8 @@ void FileHandle::New(const FunctionCallbackInfo<Value>& args) { CHECK(args[0]->IsInt32()); FileHandle* handle = - new FileHandle(env, args[0].As<Int32>()->Value(), args.This()); + FileHandle::New(env, args[0].As<Int32>()->Value(), args.This()); + if (handle == nullptr) return; if (args[1]->IsNumber()) handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust(); if (args[2]->IsNumber()) @@ -232,7 +242,14 @@ inline MaybeLocal<Promise> FileHandle::ClosePromise() { CHECK(!reading_); if (!closed_ && !closing_) { closing_ = true; - CloseReq* req = new CloseReq(env(), promise, object()); + Local<Object> close_req_obj; + if (!env() + ->fdclose_constructor_template() + ->NewInstance(env()->context()) + .ToLocal(&close_req_obj)) { + return MaybeLocal<Promise>(); + } + CloseReq* req = new CloseReq(env(), close_req_obj, promise, object()); auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) { std::unique_ptr<CloseReq> close(CloseReq::from_req(req)); CHECK_NOT_NULL(close); @@ -260,7 +277,9 @@ inline MaybeLocal<Promise> FileHandle::ClosePromise() { void FileHandle::Close(const FunctionCallbackInfo<Value>& args) { FileHandle* fd; ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder()); - args.GetReturnValue().Set(fd->ClosePromise().ToLocalChecked()); + Local<Promise> ret; + if (!fd->ClosePromise().ToLocal(&ret)) return; + args.GetReturnValue().Set(ret); } @@ -318,8 +337,13 @@ int FileHandle::ReadStart() { read_wrap->AsyncReset(); read_wrap->file_handle_ = this; } else { - Local<Object> wrap_obj = env()->filehandlereadwrap_template() - ->NewInstance(env()->context()).ToLocalChecked(); + Local<Object> wrap_obj; + if (!env() + ->filehandlereadwrap_template() + ->NewInstance(env()->context()) + .ToLocal(&wrap_obj)) { + return UV_EBUSY; + } read_wrap.reset(new FileHandleReadWrap(this, wrap_obj)); } } @@ -520,7 +544,8 @@ void AfterOpenFileHandle(uv_fs_t* req) { FSReqAfterScope after(req_wrap, req); if (after.Proceed()) { - FileHandle* fd = new FileHandle(req_wrap->env(), req->result); + FileHandle* fd = FileHandle::New(req_wrap->env(), req->result); + if (fd == nullptr) return; req_wrap->Resolve(fd->object()); } } @@ -724,15 +749,18 @@ inline int SyncCall(Environment* env, Local<Value> ctx, FSReqWrapSync* req_wrap, return err; } +// TODO(addaleax): Currently, callers check the return value and assume +// that nullptr indicates a synchronous call, rather than a failure. +// Failure conditions should be disambiguated and handled appropriately. inline FSReqBase* GetReqWrap(Environment* env, Local<Value> value, bool use_bigint = false) { if (value->IsObject()) { return Unwrap<FSReqBase>(value.As<Object>()); } else if (value->StrictEquals(env->fs_use_promises_symbol())) { if (use_bigint) { - return new FSReqPromise<uint64_t, BigUint64Array>(env, use_bigint); + return FSReqPromise<uint64_t, BigUint64Array>::New(env, use_bigint); } else { - return new FSReqPromise<double, Float64Array>(env, use_bigint); + return FSReqPromise<double, Float64Array>::New(env, use_bigint); } } return nullptr; @@ -1562,8 +1590,8 @@ static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) { if (result < 0) { return; // syscall failed, no need to continue, error info is in ctx } - HandleScope scope(isolate); - FileHandle* fd = new FileHandle(env, result); + FileHandle* fd = FileHandle::New(env, result); + if (fd == nullptr) return; args.GetReturnValue().Set(fd->object()); } } diff --git a/src/node_file.h b/src/node_file.h index e2f8bdc55e..5ae01df9ef 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -237,17 +237,19 @@ inline Local<Value> FillGlobalStatsArray(Environment* env, template <typename NativeT = double, typename V8T = v8::Float64Array> class FSReqPromise : public FSReqBase { public: - explicit FSReqPromise(Environment* env, bool use_bigint) - : FSReqBase(env, - env->fsreqpromise_constructor_template() - ->NewInstance(env->context()).ToLocalChecked(), - AsyncWrap::PROVIDER_FSREQPROMISE, - use_bigint), - stats_field_array_(env->isolate(), kFsStatsFieldsNumber) { - const auto resolver = - Promise::Resolver::New(env->context()).ToLocalChecked(); - USE(object()->Set(env->context(), env->promise_string(), - resolver).FromJust()); + static FSReqPromise* New(Environment* env, bool use_bigint) { + v8::Local<Object> obj; + if (!env->fsreqpromise_constructor_template() + ->NewInstance(env->context()) + .ToLocal(&obj)) { + return nullptr; + } + v8::Local<v8::Promise::Resolver> resolver; + if (!v8::Promise::Resolver::New(env->context()).ToLocal(&resolver) || + obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) { + return nullptr; + } + return new FSReqPromise(env, obj, use_bigint); } ~FSReqPromise() override { @@ -304,6 +306,10 @@ class FSReqPromise : public FSReqBase { FSReqPromise& operator=(const FSReqPromise&&) = delete; private: + FSReqPromise(Environment* env, v8::Local<v8::Object> obj, bool use_bigint) + : FSReqBase(env, obj, AsyncWrap::PROVIDER_FSREQPROMISE, use_bigint), + stats_field_array_(env->isolate(), kFsStatsFieldsNumber) {} + bool finished_ = false; AliasedBuffer<NativeT, V8T> stats_field_array_; }; @@ -356,9 +362,9 @@ class FileHandleReadWrap : public ReqWrap<uv_fs_t> { // the object is garbage collected class FileHandle : public AsyncWrap, public StreamBase { public: - FileHandle(Environment* env, - int fd, - v8::Local<v8::Object> obj = v8::Local<v8::Object>()); + static FileHandle* New(Environment* env, + int fd, + v8::Local<v8::Object> obj = v8::Local<v8::Object>()); virtual ~FileHandle(); static void New(const v8::FunctionCallbackInfo<v8::Value>& args); @@ -404,6 +410,8 @@ class FileHandle : public AsyncWrap, public StreamBase { FileHandle& operator=(const FileHandle&&) = delete; private: + FileHandle(Environment* env, v8::Local<v8::Object> obj, int fd); + // Synchronous close that emits a warning void Close(); void AfterClose(); @@ -411,12 +419,10 @@ class FileHandle : public AsyncWrap, public StreamBase { class CloseReq : public ReqWrap<uv_fs_t> { public: CloseReq(Environment* env, + Local<Object> obj, Local<Promise> promise, Local<Value> ref) - : ReqWrap(env, - env->fdclose_constructor_template() - ->NewInstance(env->context()).ToLocalChecked(), - AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) { + : ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) { promise_.Reset(env->isolate(), promise); ref_.Reset(env->isolate(), ref); } |