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: add error code helpers to env #19465

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions doc/api/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,12 @@ A callback function was required but was not been provided to a Node.js API.

Invalid characters were detected in headers.

<a id="ERR_INVALID_CONSTRUCTOR_CALL"></a>
### ERR_INVALID_CONSTRUCTOR_CALL

A function that should not be invoked as a construcor was invoked with `new`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

construcor -> constructor

or a constructor was invoked without `new`.

<a id="ERR_INVALID_CURSOR_POS"></a>
### ERR_INVALID_CURSOR_POS

Expand Down Expand Up @@ -1343,6 +1349,11 @@ An attempt was made to `require()` an [ES6 module][].
Script execution was interrupted by `SIGINT` (For example, when Ctrl+C was
pressed).

<a id="ERR_SCRIPT_EXECUTION_TIMEOUT"></a>
### ERR_SCRIPT_EXECUTION_TIMEOUT

Script execution timed out, possibly due to bugs in the script being executed.

<a id="ERR_SERVER_ALREADY_LISTEN"></a>
### ERR_SERVER_ALREADY_LISTEN

Expand Down
17 changes: 17 additions & 0 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,23 @@ inline void Environment::SetTemplateMethod(v8::Local<v8::FunctionTemplate> that,
ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)
#undef V

#define V(code, type) \
inline v8::Local<v8::Value> Environment::code(const char* message) const { \
v8::Local<v8::String> js_code = OneByteString(isolate(), #code); \
v8::Local<v8::String> js_msg = OneByteString(isolate(), message); \
v8::Local<v8::Object> e = \
v8::Exception::type(js_msg)->ToObject( \
isolate()->GetCurrentContext()).ToLocalChecked(); \
e->Set(code_string(), js_code); \
return e; \
} \
\
inline void Environment::THROW_ ## code(const char* message) const { \
isolate()->ThrowException(code(message)); \
}
ENVIRONMENT_ERROR_HELPERS(V)
#undef V

} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
Expand Down
21 changes: 21 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,21 @@ struct PackageConfig {
V(url_constructor_function, v8::Function) \
V(write_wrap_template, v8::ObjectTemplate)

#define ENVIRONMENT_ERROR_HELPERS(V) \
V(ERR_BUFFER_OUT_OF_BOUNDS, RangeError) \
V(ERR_INDEX_OUT_OF_RANGE, RangeError) \
V(ERR_INSPECTOR_ALREADY_CONNECTED, Error) \
V(ERR_INVALID_ARG_VALUE, Error) \
V(ERR_INVALID_ARG_TYPE, TypeError) \
V(ERR_INVALID_CALLBACK, TypeError) \
V(ERR_INVALID_CONSTRUCTOR_CALL, TypeError) \
V(ERR_INVALID_THIS, TypeError) \
V(ERR_MISSING_ARGS, TypeError) \
V(ERR_MISSING_MODULE, Error) \
V(ERR_OUT_OF_RANGE, RangeError) \
V(ERR_SCRIPT_EXECUTION_INTERRUPTED, Error) \
V(ERR_SCRIPT_EXECUTION_TIMEOUT, Error)

class Environment;

class IsolateData {
Expand Down Expand Up @@ -716,6 +731,12 @@ class Environment {
ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)
#undef V

#define V(code, _) \
inline v8::Local<v8::Value> code(const char* message) const; \
inline void THROW_ ## code(const char* message) const;
ENVIRONMENT_ERROR_HELPERS(V)
#undef V

#if HAVE_INSPECTOR
inline inspector::Agent* inspector_agent() const {
return inspector_agent_.get();
Expand Down
32 changes: 18 additions & 14 deletions src/module_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,20 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();

if (!args.IsConstructCall()) {
env->ThrowError("constructor must be called using new");
env->THROW_ERR_INVALID_CONSTRUCTOR_CALL(
"constructor must be called using new");
return;
}

if (!args[0]->IsString()) {
env->ThrowError("first argument is not a string");
env->THROW_ERR_INVALID_ARG_TYPE("first argument is not a string");
return;
}

Local<String> source_text = args[0].As<String>();

if (!args[1]->IsString()) {
env->ThrowError("second argument is not a string");
env->THROW_ERR_INVALID_ARG_TYPE("second argument is not a string");
return;
}

Expand Down Expand Up @@ -162,7 +163,7 @@ void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = args.GetIsolate();
if (!args[0]->IsFunction()) {
env->ThrowError("first argument is not a function");
env->THROW_ERR_INVALID_ARG_TYPE("first argument is not a function");
return;
}

Expand Down Expand Up @@ -283,9 +284,10 @@ void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
// which this timeout is nested, so check whether one of the watchdogs
// from this invocation is responsible for termination.
if (timed_out) {
env->ThrowError("Script execution timed out.");
env->THROW_ERR_SCRIPT_EXECUTION_TIMEOUT("Script execution timed out.");
} else if (received_signal) {
env->ThrowError("Script execution interrupted.");
env->THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(
"Script execution interrupted.");
}
env->isolate()->CancelTerminateExecution();
}
Expand Down Expand Up @@ -666,37 +668,39 @@ void ModuleWrap::Resolve(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

if (args.IsConstructCall()) {
env->ThrowError("resolve() must not be called as a constructor");
env->THROW_ERR_INVALID_CONSTRUCTOR_CALL(
"resolve() must not be called as a constructor");
return;
}
if (args.Length() != 2) {
env->ThrowError("resolve must have exactly 2 arguments (string, string)");
env->THROW_ERR_INVALID_ARG_TYPE(
"resolve must have exactly 2 arguments (string, string)");
return;
}

if (!args[0]->IsString()) {
env->ThrowError("first argument is not a string");
env->THROW_ERR_INVALID_ARG_TYPE("first argument is not a string");
return;
}
Utf8Value specifier_utf8(env->isolate(), args[0]);
std::string specifier_std(*specifier_utf8, specifier_utf8.length());

if (!args[1]->IsString()) {
env->ThrowError("second argument is not a string");
env->THROW_ERR_INVALID_ARG_TYPE("second argument is not a string");
return;
}
Utf8Value url_utf8(env->isolate(), args[1]);
URL url(*url_utf8, url_utf8.length());

if (url.flags() & URL_FLAGS_FAILED) {
env->ThrowError("second argument is not a URL string");
env->THROW_ERR_INVALID_ARG_TYPE("second argument is not a URL string");
return;
}

Maybe<URL> result = node::loader::Resolve(env, specifier_std, url);
if (result.IsNothing() || (result.FromJust().flags() & URL_FLAGS_FAILED)) {
std::string msg = "Cannot find module " + specifier_std;
env->ThrowError(msg.c_str());
env->THROW_ERR_MISSING_MODULE(msg.c_str());
return;
}

Expand Down Expand Up @@ -749,7 +753,7 @@ void ModuleWrap::SetImportModuleDynamicallyCallback(
Environment* env = Environment::GetCurrent(args);
HandleScope handle_scope(iso);
if (!args[0]->IsFunction()) {
env->ThrowError("first argument is not a function");
env->THROW_ERR_INVALID_ARG_TYPE("first argument is not a function");
return;
}

Expand Down Expand Up @@ -782,7 +786,7 @@ void ModuleWrap::SetInitializeImportMetaObjectCallback(
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();
if (!args[0]->IsFunction()) {
env->ThrowError("first argument is not a function");
env->THROW_ERR_INVALID_ARG_TYPE("first argument is not a function");
return;
}

Expand Down
33 changes: 20 additions & 13 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1577,7 +1577,7 @@ static void Chdir(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

if (args.Length() != 1 || !args[0]->IsString()) {
return env->ThrowTypeError("Bad argument.");
return env->THROW_ERR_INVALID_ARG_TYPE("Bad argument.");
}

node::Utf8Value path(args.GetIsolate(), args[0]);
Expand Down Expand Up @@ -1619,7 +1619,8 @@ static void Umask(const FunctionCallbackInfo<Value>& args) {
old = umask(0);
umask(static_cast<mode_t>(old));
} else if (!args[0]->IsInt32() && !args[0]->IsString()) {
return env->ThrowTypeError("argument must be an integer or octal string.");
return env->THROW_ERR_INVALID_ARG_TYPE(
"argument must be an integer or octal string.");
} else {
int oct;
if (args[0]->IsInt32()) {
Expand All @@ -1632,7 +1633,7 @@ static void Umask(const FunctionCallbackInfo<Value>& args) {
for (size_t i = 0; i < str.length(); i++) {
char c = (*str)[i];
if (c > '7' || c < '0') {
return env->ThrowTypeError("invalid octal string");
return env->THROW_ERR_INVALID_ARG_VALUE("invalid octal string");
}
oct *= 8;
oct += c - '0';
Expand Down Expand Up @@ -1776,7 +1777,8 @@ static void SetGid(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

if (!args[0]->IsUint32() && !args[0]->IsString()) {
return env->ThrowTypeError("setgid argument must be a number or a string");
return env->THROW_ERR_INVALID_ARG_TYPE(
"setgid argument must be a number or a string");
}

gid_t gid = gid_by_name(env->isolate(), args[0]);
Expand All @@ -1795,7 +1797,8 @@ static void SetEGid(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

if (!args[0]->IsUint32() && !args[0]->IsString()) {
return env->ThrowTypeError("setegid argument must be a number or string");
return env->THROW_ERR_INVALID_ARG_TYPE(
"setegid argument must be a number or string");
}

gid_t gid = gid_by_name(env->isolate(), args[0]);
Expand All @@ -1814,7 +1817,8 @@ static void SetUid(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

if (!args[0]->IsUint32() && !args[0]->IsString()) {
return env->ThrowTypeError("setuid argument must be a number or a string");
return env->THROW_ERR_INVALID_ARG_TYPE(
"setuid argument must be a number or a string");
}

uid_t uid = uid_by_name(env->isolate(), args[0]);
Expand All @@ -1833,7 +1837,8 @@ static void SetEUid(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

if (!args[0]->IsUint32() && !args[0]->IsString()) {
return env->ThrowTypeError("seteuid argument must be a number or string");
return env->THROW_ERR_INVALID_ARG_TYPE(
"seteuid argument must be a number or string");
}

uid_t uid = uid_by_name(env->isolate(), args[0]);
Expand Down Expand Up @@ -1890,7 +1895,7 @@ static void SetGroups(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

if (!args[0]->IsArray()) {
return env->ThrowTypeError("argument 1 must be an array");
return env->THROW_ERR_INVALID_ARG_TYPE("argument 1 must be an array");
}

Local<Array> groups_list = args[0].As<Array>();
Expand Down Expand Up @@ -1921,11 +1926,13 @@ static void InitGroups(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

if (!args[0]->IsUint32() && !args[0]->IsString()) {
return env->ThrowTypeError("argument 1 must be a number or a string");
return env->THROW_ERR_INVALID_ARG_TYPE(
"argument 1 must be a number or a string");
}

if (!args[1]->IsUint32() && !args[1]->IsString()) {
return env->ThrowTypeError("argument 2 must be a number or a string");
return env->THROW_ERR_INVALID_ARG_TYPE(
"argument 2 must be a number or a string");
}

node::Utf8Value arg0(env->isolate(), args[0]);
Expand Down Expand Up @@ -2040,7 +2047,7 @@ static void Kill(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

if (args.Length() != 2) {
return env->ThrowError("Bad argument.");
return env->THROW_ERR_MISSING_ARGS("Bad argument.");
}

int pid = args[0]->Int32Value();
Expand Down Expand Up @@ -2238,13 +2245,13 @@ static void DLOpen(const FunctionCallbackInfo<Value>& args) {
CHECK_EQ(modpending, nullptr);

if (args.Length() < 2) {
env->ThrowError("process.dlopen needs at least 2 arguments.");
env->THROW_ERR_MISSING_ARGS("process.dlopen needs at least 2 arguments.");
return;
}

int32_t flags = DLib::kDefaultFlags;
if (args.Length() > 2 && !args[2]->Int32Value(context).To(&flags)) {
return env->ThrowTypeError("flag argument must be an integer.");
return env->THROW_ERR_INVALID_ARG_TYPE("flag argument must be an integer.");
}

Local<Object> module;
Expand Down
17 changes: 9 additions & 8 deletions src/node_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@

#define MIN(a, b) ((a) < (b) ? (a) : (b))

#define THROW_AND_RETURN_IF_OOB(r) \
do { \
if (!(r)) return env->ThrowRangeError("Index out of range"); \
#define THROW_AND_RETURN_IF_OOB(r) \
do { \
if (!(r)) return env->THROW_ERR_INDEX_OUT_OF_RANGE("Index out of range"); \
} while (0)

#define SLICE_START_END(start_arg, end_arg, end_max) \
Expand Down Expand Up @@ -544,7 +544,7 @@ void Copy(const FunctionCallbackInfo<Value> &args) {
return args.GetReturnValue().Set(0);

if (source_start > ts_obj_length)
return env->ThrowRangeError("Index out of range");
return env->THROW_ERR_INDEX_OUT_OF_RANGE("Index out of range");

if (source_end - source_start > target_length - target_start)
source_end = source_start + target_length - target_start;
Expand Down Expand Up @@ -657,7 +657,7 @@ void StringWrite(const FunctionCallbackInfo<Value>& args) {
SPREAD_BUFFER_ARG(args.This(), ts_obj);

if (!args[0]->IsString())
return env->ThrowTypeError("Argument must be a string");
return env->THROW_ERR_INVALID_ARG_TYPE("Argument must be a string");

Local<String> str = args[0]->ToString(env->context()).ToLocalChecked();

Expand All @@ -666,7 +666,8 @@ void StringWrite(const FunctionCallbackInfo<Value>& args) {

THROW_AND_RETURN_IF_OOB(ParseArrayIndex(args[1], 0, &offset));
if (offset > ts_obj_length)
return env->ThrowRangeError("Offset is out of bounds");
return env->THROW_ERR_BUFFER_OUT_OF_BOUNDS(
"\"offset\" is outside of buffer bounds");

THROW_AND_RETURN_IF_OOB(ParseArrayIndex(args[2], ts_obj_length - offset,
&max_length));
Expand Down Expand Up @@ -728,9 +729,9 @@ void CompareOffset(const FunctionCallbackInfo<Value> &args) {
THROW_AND_RETURN_IF_OOB(ParseArrayIndex(args[5], ts_obj_length, &source_end));

if (source_start > ts_obj_length)
return env->ThrowRangeError("Index out of range");
return env->THROW_ERR_INDEX_OUT_OF_RANGE("Index out of range");
if (target_start > target_length)
return env->ThrowRangeError("Index out of range");
return env->THROW_ERR_INDEX_OUT_OF_RANGE("Index out of range");

CHECK_LE(source_start, source_end);
CHECK_LE(target_start, target_end);
Expand Down
Loading