src: make more error handling improvements

PR-URL: https://github.com/nodejs/node/pull/57262
Reviewed-By: Daeyeon Jeong <daeyeon.dev@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
This commit is contained in:
James M Snell 2025-03-01 11:56:27 -08:00
parent 2cff256065
commit 52ac44888d
8 changed files with 131 additions and 85 deletions

View file

@ -54,10 +54,12 @@ using v8::HeapProfiler;
using v8::HeapSpaceStatistics; using v8::HeapSpaceStatistics;
using v8::Integer; using v8::Integer;
using v8::Isolate; using v8::Isolate;
using v8::JustVoid;
using v8::Local; using v8::Local;
using v8::Maybe; using v8::Maybe;
using v8::MaybeLocal; using v8::MaybeLocal;
using v8::NewStringType; using v8::NewStringType;
using v8::Nothing;
using v8::Number; using v8::Number;
using v8::Object; using v8::Object;
using v8::ObjectTemplate; using v8::ObjectTemplate;
@ -1590,7 +1592,7 @@ Local<Value> Environment::GetNow() {
return Number::New(isolate(), static_cast<double>(now)); return Number::New(isolate(), static_cast<double>(now));
} }
void CollectExceptionInfo(Environment* env, Maybe<void> CollectExceptionInfo(Environment* env,
Local<Object> obj, Local<Object> obj,
int errorno, int errorno,
const char* err_string, const char* err_string,
@ -1598,46 +1600,58 @@ void CollectExceptionInfo(Environment* env,
const char* message, const char* message,
const char* path, const char* path,
const char* dest) { const char* dest) {
obj->Set(env->context(), if (obj->Set(env->context(),
env->errno_string(), env->errno_string(),
Integer::New(env->isolate(), errorno)).Check(); Integer::New(env->isolate(), errorno))
.IsNothing() ||
obj->Set(env->context(), env->code_string(), obj->Set(env->context(),
OneByteString(env->isolate(), err_string)).Check(); env->code_string(),
OneByteString(env->isolate(), err_string))
if (message != nullptr) { .IsNothing() ||
obj->Set(env->context(), env->message_string(), (message != nullptr && obj->Set(env->context(),
OneByteString(env->isolate(), message)).Check(); env->message_string(),
OneByteString(env->isolate(), message))
.IsNothing())) {
return Nothing<void>();
} }
Local<Value> path_buffer; Local<Value> path_buffer;
if (path != nullptr) { if (path != nullptr) {
path_buffer = if (!Buffer::Copy(env->isolate(), path, strlen(path))
Buffer::Copy(env->isolate(), path, strlen(path)).ToLocalChecked(); .ToLocal(&path_buffer) ||
obj->Set(env->context(), env->path_string(), path_buffer).Check(); obj->Set(env->context(), env->path_string(), path_buffer).IsNothing()) {
return Nothing<void>();
}
} }
Local<Value> dest_buffer; Local<Value> dest_buffer;
if (dest != nullptr) { if (dest != nullptr) {
dest_buffer = if (!Buffer::Copy(env->isolate(), dest, strlen(dest))
Buffer::Copy(env->isolate(), dest, strlen(dest)).ToLocalChecked(); .ToLocal(&dest_buffer) ||
obj->Set(env->context(), env->dest_string(), dest_buffer).Check(); obj->Set(env->context(), env->dest_string(), dest_buffer).IsNothing()) {
return Nothing<void>();
}
} }
if (syscall != nullptr) { if (syscall != nullptr) {
obj->Set(env->context(), env->syscall_string(), if (obj->Set(env->context(),
OneByteString(env->isolate(), syscall)).Check(); env->syscall_string(),
OneByteString(env->isolate(), syscall))
.IsNothing()) {
return Nothing<void>();
} }
} }
void Environment::CollectUVExceptionInfo(Local<Value> object, return JustVoid();
}
Maybe<void> Environment::CollectUVExceptionInfo(Local<Value> object,
int errorno, int errorno,
const char* syscall, const char* syscall,
const char* message, const char* message,
const char* path, const char* path,
const char* dest) { const char* dest) {
if (!object->IsObject() || errorno == 0) if (!object->IsObject() || errorno == 0) return JustVoid();
return;
Local<Object> obj = object.As<Object>(); Local<Object> obj = object.As<Object>();
const char* err_string = uv_err_name(errorno); const char* err_string = uv_err_name(errorno);
@ -1646,7 +1660,7 @@ void Environment::CollectUVExceptionInfo(Local<Value> object,
message = uv_strerror(errorno); message = uv_strerror(errorno);
} }
CollectExceptionInfo( return CollectExceptionInfo(
this, obj, errorno, err_string, syscall, message, path, dest); this, obj, errorno, err_string, syscall, message, path, dest);
} }

View file

@ -767,7 +767,7 @@ class Environment final : public MemoryRetainer {
inline performance::PerformanceState* performance_state(); inline performance::PerformanceState* performance_state();
void CollectUVExceptionInfo(v8::Local<v8::Value> context, v8::Maybe<void> CollectUVExceptionInfo(v8::Local<v8::Value> context,
int errorno, int errorno,
const char* syscall = nullptr, const char* syscall = nullptr,
const char* message = nullptr, const char* message = nullptr,

View file

@ -685,8 +685,9 @@ void GetLinkedBinding(const FunctionCallbackInfo<Value>& args) {
Local<Object> module = Object::New(env->isolate()); Local<Object> module = Object::New(env->isolate());
Local<Object> exports = Object::New(env->isolate()); Local<Object> exports = Object::New(env->isolate());
Local<String> exports_prop = env->exports_string(); if (module->Set(env->context(), env->exports_string(), exports).IsNothing()) {
module->Set(env->context(), exports_prop, exports).Check(); return;
}
if (mod->nm_context_register_func != nullptr) { if (mod->nm_context_register_func != nullptr) {
mod->nm_context_register_func( mod->nm_context_register_func(
@ -698,11 +699,12 @@ void GetLinkedBinding(const FunctionCallbackInfo<Value>& args) {
env, "Linked binding has no declared entry point."); env, "Linked binding has no declared entry point.");
} }
auto effective_exports = Local<Value> effective_exports;
module->Get(env->context(), exports_prop).ToLocalChecked(); if (module->Get(env->context(), env->exports_string())
.ToLocal(&effective_exports)) {
args.GetReturnValue().Set(effective_exports); args.GetReturnValue().Set(effective_exports);
} }
}
// Call built-in bindings' _register_<module name> function to // Call built-in bindings' _register_<module name> function to
// do binding registration explicitly. // do binding registration explicitly.

View file

@ -1215,9 +1215,12 @@ void TriggerUncaughtException(Isolate* isolate,
// monkey-patchable. // monkey-patchable.
Local<Object> process_object = env->process_object(); Local<Object> process_object = env->process_object();
Local<String> fatal_exception_string = env->fatal_exception_string(); Local<String> fatal_exception_string = env->fatal_exception_string();
Local<Value> fatal_exception_function = Local<Value> fatal_exception_function;
process_object->Get(env->context(), if (!process_object->Get(env->context(), fatal_exception_string)
fatal_exception_string).ToLocalChecked(); .ToLocal(&fatal_exception_function)) {
// V8 will have scheduled a superseding error to throw
return;
}
// If the exception happens before process._fatalException is attached // If the exception happens before process._fatalException is attached
// during bootstrap, or if the user has patched it incorrectly, exit // during bootstrap, or if the user has patched it incorrectly, exit
// the current Node.js instance. // the current Node.js instance.

View file

@ -67,9 +67,9 @@ static void GetHostname(const FunctionCallbackInfo<Value>& args) {
if (r != 0) { if (r != 0) {
CHECK_GE(args.Length(), 1); CHECK_GE(args.Length(), 1);
env->CollectUVExceptionInfo(args[args.Length() - 1], r, USE(env->CollectUVExceptionInfo(
"uv_os_gethostname"); args[args.Length() - 1], r, "uv_os_gethostname"));
return args.GetReturnValue().SetUndefined(); return;
} }
Local<Value> ret; Local<Value> ret;
@ -85,8 +85,9 @@ static void GetOSInformation(const FunctionCallbackInfo<Value>& args) {
if (err != 0) { if (err != 0) {
CHECK_GE(args.Length(), 1); CHECK_GE(args.Length(), 1);
env->CollectUVExceptionInfo(args[args.Length() - 1], err, "uv_os_uname"); USE(env->CollectUVExceptionInfo(
return args.GetReturnValue().SetUndefined(); args[args.Length() - 1], err, "uv_os_uname"));
return;
} }
// [sysname, version, release, machine] // [sysname, version, release, machine]
@ -159,8 +160,8 @@ static void GetUptime(const FunctionCallbackInfo<Value>& args) {
double uptime; double uptime;
int err = uv_uptime(&uptime); int err = uv_uptime(&uptime);
if (err != 0) { if (err != 0) {
env->CollectUVExceptionInfo(args[args.Length() - 1], err, "uv_uptime"); USE(env->CollectUVExceptionInfo(args[args.Length() - 1], err, "uv_uptime"));
return args.GetReturnValue().SetUndefined(); return;
} }
args.GetReturnValue().Set(uptime); args.GetReturnValue().Set(uptime);
@ -189,14 +190,13 @@ static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) {
int err = uv_interface_addresses(&interfaces, &count); int err = uv_interface_addresses(&interfaces, &count);
if (err == UV_ENOSYS) if (err == UV_ENOSYS) return;
return args.GetReturnValue().SetUndefined();
if (err) { if (err) {
CHECK_GE(args.Length(), 1); CHECK_GE(args.Length(), 1);
env->CollectUVExceptionInfo(args[args.Length() - 1], errno, USE(env->CollectUVExceptionInfo(
"uv_interface_addresses"); args[args.Length() - 1], errno, "uv_interface_addresses"));
return args.GetReturnValue().SetUndefined(); return;
} }
Local<Value> no_scope_id = Integer::New(isolate, -1); Local<Value> no_scope_id = Integer::New(isolate, -1);
@ -267,8 +267,9 @@ static void GetHomeDirectory(const FunctionCallbackInfo<Value>& args) {
if (err) { if (err) {
CHECK_GE(args.Length(), 1); CHECK_GE(args.Length(), 1);
env->CollectUVExceptionInfo(args[args.Length() - 1], err, "uv_os_homedir"); USE(env->CollectUVExceptionInfo(
return args.GetReturnValue().SetUndefined(); args[args.Length() - 1], err, "uv_os_homedir"));
return;
} }
Local<String> home; Local<String> home;
@ -299,9 +300,9 @@ static void GetUserInfo(const FunctionCallbackInfo<Value>& args) {
if (const int err = uv_os_get_passwd(&pwd)) { if (const int err = uv_os_get_passwd(&pwd)) {
CHECK_GE(args.Length(), 2); CHECK_GE(args.Length(), 2);
env->CollectUVExceptionInfo(args[args.Length() - 1], err, USE(env->CollectUVExceptionInfo(
"uv_os_get_passwd"); args[args.Length() - 1], err, "uv_os_get_passwd"));
return args.GetReturnValue().SetUndefined(); return;
} }
auto free_passwd = OnScopeLeave([&] { uv_os_free_passwd(&pwd); }); auto free_passwd = OnScopeLeave([&] { uv_os_free_passwd(&pwd); });
@ -371,7 +372,10 @@ static void SetPriority(const FunctionCallbackInfo<Value>& args) {
if (err) { if (err) {
CHECK(args[2]->IsObject()); CHECK(args[2]->IsObject());
env->CollectUVExceptionInfo(args[2], err, "uv_os_setpriority"); if (env->CollectUVExceptionInfo(args[2], err, "uv_os_setpriority")
.IsNothing()) {
return;
}
} }
args.GetReturnValue().Set(err); args.GetReturnValue().Set(err);
@ -390,7 +394,7 @@ static void GetPriority(const FunctionCallbackInfo<Value>& args) {
if (err) { if (err) {
CHECK(args[1]->IsObject()); CHECK(args[1]->IsObject());
env->CollectUVExceptionInfo(args[1], err, "uv_os_getpriority"); USE(env->CollectUVExceptionInfo(args[1], err, "uv_os_getpriority"));
return; return;
} }

View file

@ -134,12 +134,26 @@ void WASI::New(const FunctionCallbackInfo<Value>& args) {
Local<Array> stdio = args[3].As<Array>(); Local<Array> stdio = args[3].As<Array>();
CHECK_EQ(stdio->Length(), 3); CHECK_EQ(stdio->Length(), 3);
options.in = stdio->Get(context, 0).ToLocalChecked()->
Int32Value(context).FromJust(); Local<Value> val;
options.out = stdio->Get(context, 1).ToLocalChecked()-> int32_t tmp;
Int32Value(context).FromJust(); if (!stdio->Get(context, 0).ToLocal(&val) ||
options.err = stdio->Get(context, 2).ToLocalChecked()-> !val->Int32Value(context).To(&tmp)) {
Int32Value(context).FromJust(); return;
}
options.in = tmp;
if (!stdio->Get(context, 1).ToLocal(&val) ||
!val->Int32Value(context).To(&tmp)) {
return;
}
options.out = tmp;
if (!stdio->Get(context, 2).ToLocal(&val) ||
!val->Int32Value(context).To(&tmp)) {
return;
}
options.err = tmp;
options.fd_table_size = 3; options.fd_table_size = 3;
options.argc = argc; options.argc = argc;
@ -147,7 +161,10 @@ void WASI::New(const FunctionCallbackInfo<Value>& args) {
const_cast<const char**>(argc == 0 ? nullptr : new char*[argc]); const_cast<const char**>(argc == 0 ? nullptr : new char*[argc]);
for (uint32_t i = 0; i < argc; i++) { for (uint32_t i = 0; i < argc; i++) {
auto arg = argv->Get(context, i).ToLocalChecked(); Local<Value> arg;
if (!argv->Get(context, i).ToLocal(&arg)) {
return;
}
CHECK(arg->IsString()); CHECK(arg->IsString());
node::Utf8Value str(env->isolate(), arg); node::Utf8Value str(env->isolate(), arg);
options.argv[i] = strdup(*str); options.argv[i] = strdup(*str);
@ -158,7 +175,10 @@ void WASI::New(const FunctionCallbackInfo<Value>& args) {
const uint32_t envc = env_pairs->Length(); const uint32_t envc = env_pairs->Length();
options.envp = const_cast<const char**>(new char*[envc + 1]); options.envp = const_cast<const char**>(new char*[envc + 1]);
for (uint32_t i = 0; i < envc; i++) { for (uint32_t i = 0; i < envc; i++) {
auto pair = env_pairs->Get(context, i).ToLocalChecked(); Local<Value> pair;
if (!env_pairs->Get(context, i).ToLocal(&pair)) {
return;
}
CHECK(pair->IsString()); CHECK(pair->IsString());
node::Utf8Value str(env->isolate(), pair); node::Utf8Value str(env->isolate(), pair);
options.envp[i] = strdup(*str); options.envp[i] = strdup(*str);
@ -172,8 +192,12 @@ void WASI::New(const FunctionCallbackInfo<Value>& args) {
options.preopens = Calloc<uvwasi_preopen_t>(options.preopenc); options.preopens = Calloc<uvwasi_preopen_t>(options.preopenc);
int index = 0; int index = 0;
for (uint32_t i = 0; i < preopens->Length(); i += 2) { for (uint32_t i = 0; i < preopens->Length(); i += 2) {
auto mapped = preopens->Get(context, i).ToLocalChecked(); Local<Value> mapped;
auto real = preopens->Get(context, i + 1).ToLocalChecked(); Local<Value> real;
if (!preopens->Get(context, i).ToLocal(&mapped) ||
!preopens->Get(context, i + 1).ToLocal(&real)) {
return;
}
CHECK(mapped->IsString()); CHECK(mapped->IsString());
CHECK(real->IsString()); CHECK(real->IsString());
node::Utf8Value mapped_path(env->isolate(), mapped); node::Utf8Value mapped_path(env->isolate(), mapped);

View file

@ -136,8 +136,7 @@ void TTYWrap::New(const FunctionCallbackInfo<Value>& args) {
int err = 0; int err = 0;
new TTYWrap(env, args.This(), fd, &err); new TTYWrap(env, args.This(), fd, &err);
if (err != 0) { if (err != 0) {
env->CollectUVExceptionInfo(args[1], err, "uv_tty_init"); USE(env->CollectUVExceptionInfo(args[1], err, "uv_tty_init"));
args.GetReturnValue().SetUndefined();
} }
} }

View file

@ -384,8 +384,8 @@ void UDPWrap::BufferSize(const FunctionCallbackInfo<Value>& args) {
"uv_send_buffer_size"; "uv_send_buffer_size";
if (!args[0]->IsInt32()) { if (!args[0]->IsInt32()) {
env->CollectUVExceptionInfo(args[2], UV_EINVAL, uv_func_name); USE(env->CollectUVExceptionInfo(args[2], UV_EINVAL, uv_func_name));
return args.GetReturnValue().SetUndefined(); return;
} }
uv_handle_t* handle = reinterpret_cast<uv_handle_t*>(&wrap->handle_); uv_handle_t* handle = reinterpret_cast<uv_handle_t*>(&wrap->handle_);
@ -398,8 +398,8 @@ void UDPWrap::BufferSize(const FunctionCallbackInfo<Value>& args) {
err = uv_send_buffer_size(handle, &size); err = uv_send_buffer_size(handle, &size);
if (err != 0) { if (err != 0) {
env->CollectUVExceptionInfo(args[2], err, uv_func_name); USE(env->CollectUVExceptionInfo(args[2], err, uv_func_name));
return args.GetReturnValue().SetUndefined(); return;
} }
args.GetReturnValue().Set(size); args.GetReturnValue().Set(size);