1 #ifndef SRC_NODE_ERRORS_H_
2 #define SRC_NODE_ERRORS_H_
3
4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6 #include "env.h"
7 #include "v8.h"
8
9 // Use ostringstream to print exact-width integer types
10 // because the format specifiers are not available on AIX.
11 #include <sstream>
12
13 namespace node {
14
15 enum ErrorHandlingMode { CONTEXTIFY_ERROR, FATAL_ERROR, MODULE_ERROR };
16 void AppendExceptionLine(Environment* env,
17 v8::Local<v8::Value> er,
18 v8::Local<v8::Message> message,
19 enum ErrorHandlingMode mode);
20
21 [[noreturn]] void FatalError(const char* location, const char* message);
22 void OnFatalError(const char* location, const char* message);
23
24 // Helpers to construct errors similar to the ones provided by
25 // lib/internal/errors.js.
26 // Example: with `V(ERR_INVALID_ARG_TYPE, TypeError)`, there will be
27 // `node::ERR_INVALID_ARG_TYPE(isolate, "message")` returning
28 // a `Local<Value>` containing the TypeError with proper code and message
29
30 #define ERRORS_WITH_CODE(V) \
31 V(ERR_BUFFER_CONTEXT_NOT_AVAILABLE, Error) \
32 V(ERR_BUFFER_OUT_OF_BOUNDS, RangeError) \
33 V(ERR_BUFFER_TOO_LARGE, Error) \
34 V(ERR_CONSTRUCT_CALL_REQUIRED, TypeError) \
35 V(ERR_CONSTRUCT_CALL_INVALID, TypeError) \
36 V(ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH, RangeError) \
37 V(ERR_CRYPTO_UNKNOWN_CIPHER, Error) \
38 V(ERR_CRYPTO_UNKNOWN_DH_GROUP, Error) \
39 V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, Error) \
40 V(ERR_INVALID_ARG_VALUE, TypeError) \
41 V(ERR_OSSL_EVP_INVALID_DIGEST, Error) \
42 V(ERR_INVALID_ARG_TYPE, TypeError) \
43 V(ERR_INVALID_THIS, TypeError) \
44 V(ERR_INVALID_TRANSFER_OBJECT, TypeError) \
45 V(ERR_MEMORY_ALLOCATION_FAILED, Error) \
46 V(ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE, Error) \
47 V(ERR_MISSING_ARGS, TypeError) \
48 V(ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST, TypeError) \
49 V(ERR_MISSING_PASSPHRASE, TypeError) \
50 V(ERR_MISSING_PLATFORM_FOR_WORKER, Error) \
51 V(ERR_NON_CONTEXT_AWARE_DISABLED, Error) \
52 V(ERR_OUT_OF_RANGE, RangeError) \
53 V(ERR_SCRIPT_EXECUTION_INTERRUPTED, Error) \
54 V(ERR_SCRIPT_EXECUTION_TIMEOUT, Error) \
55 V(ERR_STRING_TOO_LONG, Error) \
56 V(ERR_TLS_INVALID_PROTOCOL_METHOD, TypeError) \
57 V(ERR_TRANSFERRING_EXTERNALIZED_SHAREDARRAYBUFFER, TypeError) \
58 V(ERR_TLS_PSK_SET_IDENTIY_HINT_FAILED, Error) \
59 V(ERR_VM_MODULE_CACHED_DATA_REJECTED, Error) \
60 V(ERR_WASI_NOT_STARTED, Error) \
61 V(ERR_WORKER_INIT_FAILED, Error) \
62 V(ERR_PROTO_ACCESS, Error)
63
64 #define V(code, type) \
65 inline v8::Local<v8::Value> code(v8::Isolate* isolate, \
66 const char* message) { \
67 v8::Local<v8::String> js_code = OneByteString(isolate, #code); \
68 v8::Local<v8::String> js_msg = OneByteString(isolate, message); \
69 v8::Local<v8::Object> e = \
70 v8::Exception::type(js_msg)->ToObject( \
71 isolate->GetCurrentContext()).ToLocalChecked(); \
72 e->Set(isolate->GetCurrentContext(), OneByteString(isolate, "code"), \
73 js_code).Check(); \
74 return e; \
75 } \
76 inline void THROW_ ## code(v8::Isolate* isolate, const char* message) { \
77 isolate->ThrowException(code(isolate, message)); \
78 } \
79 inline void THROW_ ## code(Environment* env, const char* message) { \
80 THROW_ ## code(env->isolate(), message); \
81 }
82 ERRORS_WITH_CODE(V)
83 #undef V
84
85 // Errors with predefined static messages
86
87 #define PREDEFINED_ERROR_MESSAGES(V) \
88 V(ERR_BUFFER_CONTEXT_NOT_AVAILABLE, \
89 "Buffer is not available for the current Context") \
90 V(ERR_CONSTRUCT_CALL_INVALID, "Constructor cannot be called") \
91 V(ERR_CONSTRUCT_CALL_REQUIRED, "Cannot call constructor without `new`") \
92 V(ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH, \
93 "Input buffers must have the same byte length") \
94 V(ERR_CRYPTO_UNKNOWN_CIPHER, "Unknown cipher") \
95 V(ERR_CRYPTO_UNKNOWN_DH_GROUP, "Unknown DH group") \
96 V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, \
97 "Context not associated with Node.js environment") \
98 V(ERR_INVALID_THIS, "Value of \"this\" is the wrong type") \
99 V(ERR_INVALID_TRANSFER_OBJECT, "Found invalid object in transferList") \
100 V(ERR_MEMORY_ALLOCATION_FAILED, "Failed to allocate memory") \
101 V(ERR_OSSL_EVP_INVALID_DIGEST, "Invalid digest used") \
102 V(ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE, \
103 "A message object could not be deserialized successfully in the target " \
104 "vm.Context") \
105 V(ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST, \
106 "Object that needs transfer was found in message but not listed " \
107 "in transferList") \
108 V(ERR_MISSING_PLATFORM_FOR_WORKER, \
109 "The V8 platform used by this instance of Node does not support " \
110 "creating Workers") \
111 V(ERR_NON_CONTEXT_AWARE_DISABLED, \
112 "Loading non context-aware native modules has been disabled") \
113 V(ERR_SCRIPT_EXECUTION_INTERRUPTED, \
114 "Script execution was interrupted by `SIGINT`") \
115 V(ERR_TRANSFERRING_EXTERNALIZED_SHAREDARRAYBUFFER, \
116 "Cannot serialize externalized SharedArrayBuffer") \
117 V(ERR_TLS_PSK_SET_IDENTIY_HINT_FAILED, "Failed to set PSK identity hint") \
118 V(ERR_WASI_NOT_STARTED, "wasi.start() has not been called") \
119 V(ERR_WORKER_INIT_FAILED, "Worker initialization failure") \
120 V(ERR_PROTO_ACCESS, \
121 "Accessing Object.prototype.__proto__ has been " \
122 "disallowed with --disable-proto=throw")
123
124 #define V(code, message) \
125 inline v8::Local<v8::Value> code(v8::Isolate* isolate) { \
126 return code(isolate, message); \
127 } \
128 inline void THROW_ ## code(v8::Isolate* isolate) { \
129 isolate->ThrowException(code(isolate, message)); \
130 } \
131 inline void THROW_ ## code(Environment* env) { \
132 THROW_ ## code(env->isolate()); \
133 }
PREDEFINED_ERROR_MESSAGES(V)134 PREDEFINED_ERROR_MESSAGES(V)
135 #undef V
136
137 // Errors with predefined non-static messages
138 inline void THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(Environment* env,
139 int64_t timeout) {
140 std::ostringstream message;
141 message << "Script execution timed out after ";
142 message << timeout << "ms";
143 THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, message.str().c_str());
144 }
145
ERR_BUFFER_TOO_LARGE(v8::Isolate * isolate)146 inline v8::Local<v8::Value> ERR_BUFFER_TOO_LARGE(v8::Isolate* isolate) {
147 char message[128];
148 snprintf(message, sizeof(message),
149 "Cannot create a Buffer larger than 0x%zx bytes",
150 v8::TypedArray::kMaxLength);
151 return ERR_BUFFER_TOO_LARGE(isolate, message);
152 }
153
ERR_STRING_TOO_LONG(v8::Isolate * isolate)154 inline v8::Local<v8::Value> ERR_STRING_TOO_LONG(v8::Isolate* isolate) {
155 char message[128];
156 snprintf(message, sizeof(message),
157 "Cannot create a string longer than 0x%x characters",
158 v8::String::kMaxLength);
159 return ERR_STRING_TOO_LONG(isolate, message);
160 }
161
162 #define THROW_AND_RETURN_IF_NOT_BUFFER(env, val, prefix) \
163 do { \
164 if (!Buffer::HasInstance(val)) \
165 return node::THROW_ERR_INVALID_ARG_TYPE(env, \
166 prefix " must be a buffer"); \
167 } while (0)
168
169 #define THROW_AND_RETURN_IF_NOT_STRING(env, val, prefix) \
170 do { \
171 if (!val->IsString()) \
172 return node::THROW_ERR_INVALID_ARG_TYPE(env, \
173 prefix " must be a string"); \
174 } while (0)
175
176 namespace errors {
177
178 class TryCatchScope : public v8::TryCatch {
179 public:
180 enum class CatchMode { kNormal, kFatal };
181
182 explicit TryCatchScope(Environment* env, CatchMode mode = CatchMode::kNormal)
183 : v8::TryCatch(env->isolate()), env_(env), mode_(mode) {}
184 ~TryCatchScope();
185
186 // Since the dtor is not virtual we need to make sure no one creates
187 // object of it in the free store that might be held by polymorphic pointers.
188 void* operator new(std::size_t count) = delete;
189 void* operator new[](std::size_t count) = delete;
190 TryCatchScope(TryCatchScope&) = delete;
191 TryCatchScope(TryCatchScope&&) = delete;
192 TryCatchScope operator=(TryCatchScope&) = delete;
193 TryCatchScope operator=(TryCatchScope&&) = delete;
194
195 private:
196 Environment* env_;
197 CatchMode mode_;
198 };
199
200 // Trigger the global uncaught exception handler `process._fatalException`
201 // in JS land (which emits the 'uncaughtException' event). If that returns
202 // true, continue program execution, otherwise exit the process.
203 void TriggerUncaughtException(v8::Isolate* isolate,
204 const v8::TryCatch& try_catch);
205 void TriggerUncaughtException(v8::Isolate* isolate,
206 v8::Local<v8::Value> error,
207 v8::Local<v8::Message> message,
208 bool from_promise = false);
209
210 const char* errno_string(int errorno);
211 void PerIsolateMessageListener(v8::Local<v8::Message> message,
212 v8::Local<v8::Value> error);
213
214 void DecorateErrorStack(Environment* env,
215 const errors::TryCatchScope& try_catch);
216 } // namespace errors
217
218 } // namespace node
219
220 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
221
222 #endif // SRC_NODE_ERRORS_H_
223