Skip to content
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

src: pass along errors from object instantiations (part II) #25822

wants to merge 4 commits into from
Changes from all commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.


Just for now

@@ -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,
FileHandle::FileHandle(Environment* env, Local<Object> obj, int fd)
: AsyncWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLE),
fd_(fd) {

FileHandle* FileHandle::New(Environment* env, int fd, Local<Object> obj) {
if (obj.IsEmpty() && !env->fd_constructor_template()
.ToLocal(&obj)) {
return nullptr;
v8::PropertyAttribute attr =
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
FIXED_ONE_BYTE_STRING(env->isolate(), "fd"),
Integer::New(env->isolate(), fd),
if (obj->DefineOwnProperty(env->context(),
Integer::New(env->isolate(), fd),
.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) {

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() {
if (!closed_ && !closing_) {
closing_ = true;
CloseReq* req = new CloseReq(env(), promise, object());
Local<Object> close_req_obj;
if (!env()
.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));
@@ -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());
Local<Promise> ret;
if (!fd->ClosePromise().ToLocal(&ret)) return;

@@ -318,8 +337,13 @@ int FileHandle::ReadStart() {
read_wrap->file_handle_ = this;
} else {
Local<Object> wrap_obj = env()->filehandlereadwrap_template()
Local<Object> wrap_obj;
if (!env()
.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;
@@ -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;
@@ -237,17 +237,19 @@ inline Local<Value> FillGlobalStatsArray(Environment* env,
template <typename NativeT = double, typename V8T = v8::Float64Array>
class FSReqPromise : public FSReqBase {
explicit FSReqPromise(Environment* env, bool use_bigint)
: FSReqBase(env,
stats_field_array_(env->isolate(), kFsStatsFieldsNumber) {
const auto resolver =
USE(object()->Set(env->context(), env->promise_string(),
static FSReqPromise* New(Environment* env, bool use_bigint) {
v8::Local<Object> obj;
if (!env->fsreqpromise_constructor_template()
.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;

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 {
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,19 +410,19 @@ class FileHandle : public AsyncWrap, public StreamBase {
FileHandle& operator=(const FileHandle&&) = delete;

FileHandle(Environment* env, v8::Local<v8::Object> obj, int fd);

// Synchronous close that emits a warning
void Close();
void AfterClose();

class CloseReq : public ReqWrap<uv_fs_t> {
CloseReq(Environment* env,

This comment has been minimized.

Copy link

gireeshpunathil Feb 8, 2019


any reason why CloseReq does not follow the suit - i.e., a private constructor and a static factory?

This comment has been minimized.

Copy link

addaleax Feb 8, 2019

Author Member

Just that it’s used at only one call site rather than multiple ones. I can add/use a factory constructor if you like?

This comment has been minimized.

Copy link

gireeshpunathil Feb 8, 2019


ok, I thought so. I think it is fine; doesn't look like anything beneficial of doing so.

Local<Object> obj,
Local<Promise> promise,
Local<Value> ref)
: ReqWrap(env,
: ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
promise_.Reset(env->isolate(), promise);
ref_.Reset(env->isolate(), ref);
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.