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 "debug_utils-inl.h"
7 #include "env.h"
8 #include "v8.h"
9
10 // Use ostringstream to print exact-width integer types
11 // because the format specifiers are not available on AIX.
12 #include <sstream>
13
14 namespace node {
15
16 enum ErrorHandlingMode { CONTEXTIFY_ERROR, FATAL_ERROR, MODULE_ERROR };
17 void AppendExceptionLine(Environment* env,
18 v8::Local<v8::Value> er,
19 v8::Local<v8::Message> message,
20 enum ErrorHandlingMode mode);
21
22 [[noreturn]] void FatalError(const char* location, const char* message);
23 [[noreturn]] void OnFatalError(const char* location, const char* message);
24 [[noreturn]] void OOMErrorHandler(const char* location, bool is_heap_oom);
25
26 // Helpers to construct errors similar to the ones provided by
27 // lib/internal/errors.js.
28 // Example: with `V(ERR_INVALID_ARG_TYPE, TypeError)`, there will be
29 // `node::ERR_INVALID_ARG_TYPE(isolate, "message")` returning
30 // a `Local<Value>` containing the TypeError with proper code and message
31
32 #define ERRORS_WITH_CODE(V) \
33 V(ERR_BUFFER_CONTEXT_NOT_AVAILABLE, Error) \
34 V(ERR_BUFFER_OUT_OF_BOUNDS, RangeError) \
35 V(ERR_BUFFER_TOO_LARGE, Error) \
36 V(ERR_CLOSED_MESSAGE_PORT, Error) \
37 V(ERR_CONSTRUCT_CALL_REQUIRED, TypeError) \
38 V(ERR_CONSTRUCT_CALL_INVALID, TypeError) \
39 V(ERR_CRYPTO_INITIALIZATION_FAILED, Error) \
40 V(ERR_CRYPTO_INVALID_AUTH_TAG, TypeError) \
41 V(ERR_CRYPTO_INVALID_COUNTER, TypeError) \
42 V(ERR_CRYPTO_INVALID_CURVE, TypeError) \
43 V(ERR_CRYPTO_INVALID_DIGEST, TypeError) \
44 V(ERR_CRYPTO_INVALID_IV, TypeError) \
45 V(ERR_CRYPTO_INVALID_JWK, TypeError) \
46 V(ERR_CRYPTO_INVALID_KEYLEN, RangeError) \
47 V(ERR_CRYPTO_INVALID_KEYPAIR, RangeError) \
48 V(ERR_CRYPTO_INVALID_KEYTYPE, RangeError) \
49 V(ERR_CRYPTO_INVALID_MESSAGELEN, RangeError) \
50 V(ERR_CRYPTO_INVALID_SCRYPT_PARAMS, RangeError) \
51 V(ERR_CRYPTO_INVALID_STATE, Error) \
52 V(ERR_CRYPTO_INVALID_TAG_LENGTH, RangeError) \
53 V(ERR_CRYPTO_JWK_UNSUPPORTED_CURVE, Error) \
54 V(ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE, Error) \
55 V(ERR_CRYPTO_OPERATION_FAILED, Error) \
56 V(ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH, RangeError) \
57 V(ERR_CRYPTO_UNKNOWN_CIPHER, Error) \
58 V(ERR_CRYPTO_UNKNOWN_DH_GROUP, Error) \
59 V(ERR_CRYPTO_UNSUPPORTED_OPERATION, Error) \
60 V(ERR_CRYPTO_JOB_INIT_FAILED, Error) \
61 V(ERR_DLOPEN_DISABLED, Error) \
62 V(ERR_DLOPEN_FAILED, Error) \
63 V(ERR_ENCODING_INVALID_ENCODED_DATA, TypeError) \
64 V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, Error) \
65 V(ERR_ILLEGAL_CONSTRUCTOR, Error) \
66 V(ERR_INVALID_ADDRESS, Error) \
67 V(ERR_INVALID_ARG_VALUE, TypeError) \
68 V(ERR_OSSL_EVP_INVALID_DIGEST, Error) \
69 V(ERR_INVALID_ARG_TYPE, TypeError) \
70 V(ERR_INVALID_OBJECT_DEFINE_PROPERTY, TypeError) \
71 V(ERR_INVALID_MODULE, Error) \
72 V(ERR_INVALID_STATE, Error) \
73 V(ERR_INVALID_THIS, TypeError) \
74 V(ERR_INVALID_TRANSFER_OBJECT, TypeError) \
75 V(ERR_MEMORY_ALLOCATION_FAILED, Error) \
76 V(ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE, Error) \
77 V(ERR_MISSING_ARGS, TypeError) \
78 V(ERR_MISSING_TRANSFERABLE_IN_TRANSFER_LIST, TypeError) \
79 V(ERR_MISSING_PASSPHRASE, TypeError) \
80 V(ERR_MISSING_PLATFORM_FOR_WORKER, Error) \
81 V(ERR_NON_CONTEXT_AWARE_DISABLED, Error) \
82 V(ERR_OUT_OF_RANGE, RangeError) \
83 V(ERR_SCRIPT_EXECUTION_INTERRUPTED, Error) \
84 V(ERR_SCRIPT_EXECUTION_TIMEOUT, Error) \
85 V(ERR_STRING_TOO_LONG, Error) \
86 V(ERR_TLS_INVALID_PROTOCOL_METHOD, TypeError) \
87 V(ERR_TLS_PSK_SET_IDENTIY_HINT_FAILED, Error) \
88 V(ERR_VM_MODULE_CACHED_DATA_REJECTED, Error) \
89 V(ERR_VM_MODULE_LINK_FAILURE, Error) \
90 V(ERR_WASI_NOT_STARTED, Error) \
91 V(ERR_WORKER_INIT_FAILED, Error) \
92 V(ERR_PROTO_ACCESS, Error)
93
94 #define V(code, type) \
95 template <typename... Args> \
96 inline v8::Local<v8::Value> code( \
97 v8::Isolate* isolate, const char* format, Args&&... args) { \
98 std::string message = SPrintF(format, std::forward<Args>(args)...); \
99 v8::Local<v8::String> js_code = OneByteString(isolate, #code); \
100 v8::Local<v8::String> js_msg = \
101 OneByteString(isolate, message.c_str(), message.length()); \
102 v8::Local<v8::Object> e = v8::Exception::type(js_msg) \
103 ->ToObject(isolate->GetCurrentContext()) \
104 .ToLocalChecked(); \
105 e->Set(isolate->GetCurrentContext(), \
106 OneByteString(isolate, "code"), \
107 js_code) \
108 .Check(); \
109 return e; \
110 } \
111 template <typename... Args> \
112 inline void THROW_##code( \
113 v8::Isolate* isolate, const char* format, Args&&... args) { \
114 isolate->ThrowException( \
115 code(isolate, format, std::forward<Args>(args)...)); \
116 } \
117 template <typename... Args> \
118 inline void THROW_##code( \
119 Environment* env, const char* format, Args&&... args) { \
120 THROW_##code(env->isolate(), format, std::forward<Args>(args)...); \
121 }
122 ERRORS_WITH_CODE(V)
123 #undef V
124
125 // Errors with predefined static messages
126
127 #define PREDEFINED_ERROR_MESSAGES(V) \
128 V(ERR_BUFFER_CONTEXT_NOT_AVAILABLE, \
129 "Buffer is not available for the current Context") \
130 V(ERR_CLOSED_MESSAGE_PORT, "Cannot send data on closed MessagePort") \
131 V(ERR_CONSTRUCT_CALL_INVALID, "Constructor cannot be called") \
132 V(ERR_CONSTRUCT_CALL_REQUIRED, "Cannot call constructor without `new`") \
133 V(ERR_CRYPTO_INITIALIZATION_FAILED, "Initialization failed") \
134 V(ERR_CRYPTO_INVALID_AUTH_TAG, "Invalid authentication tag") \
135 V(ERR_CRYPTO_INVALID_COUNTER, "Invalid counter") \
136 V(ERR_CRYPTO_INVALID_CURVE, "Invalid EC curve name") \
137 V(ERR_CRYPTO_INVALID_DIGEST, "Invalid digest") \
138 V(ERR_CRYPTO_INVALID_IV, "Invalid initialization vector") \
139 V(ERR_CRYPTO_INVALID_JWK, "Invalid JWK format") \
140 V(ERR_CRYPTO_INVALID_KEYLEN, "Invalid key length") \
141 V(ERR_CRYPTO_INVALID_KEYPAIR, "Invalid key pair") \
142 V(ERR_CRYPTO_INVALID_KEYTYPE, "Invalid key type") \
143 V(ERR_CRYPTO_INVALID_MESSAGELEN, "Invalid message length") \
144 V(ERR_CRYPTO_INVALID_SCRYPT_PARAMS, "Invalid scrypt params") \
145 V(ERR_CRYPTO_INVALID_STATE, "Invalid state") \
146 V(ERR_CRYPTO_INVALID_TAG_LENGTH, "Invalid taglength") \
147 V(ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE, "Unsupported JWK Key Type.") \
148 V(ERR_CRYPTO_OPERATION_FAILED, "Operation failed") \
149 V(ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH, \
150 "Input buffers must have the same byte length") \
151 V(ERR_CRYPTO_UNKNOWN_CIPHER, "Unknown cipher") \
152 V(ERR_CRYPTO_UNKNOWN_DH_GROUP, "Unknown DH group") \
153 V(ERR_CRYPTO_UNSUPPORTED_OPERATION, "Unsupported crypto operation") \
154 V(ERR_CRYPTO_JOB_INIT_FAILED, "Failed to initialize crypto job config") \
155 V(ERR_DLOPEN_FAILED, "DLOpen failed") \
156 V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, \
157 "Context not associated with Node.js environment") \
158 V(ERR_ILLEGAL_CONSTRUCTOR, "Illegal constructor") \
159 V(ERR_INVALID_ADDRESS, "Invalid socket address") \
160 V(ERR_INVALID_MODULE, "No such module") \
161 V(ERR_INVALID_THIS, "Value of \"this\" is the wrong type") \
162 V(ERR_INVALID_TRANSFER_OBJECT, "Found invalid object in transferList") \
163 V(ERR_MEMORY_ALLOCATION_FAILED, "Failed to allocate memory") \
164 V(ERR_OSSL_EVP_INVALID_DIGEST, "Invalid digest used") \
165 V(ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE, \
166 "A message object could not be deserialized successfully in the target " \
167 "vm.Context") \
168 V(ERR_MISSING_TRANSFERABLE_IN_TRANSFER_LIST, \
169 "Object that needs transfer was found in message but not listed " \
170 "in transferList") \
171 V(ERR_MISSING_PLATFORM_FOR_WORKER, \
172 "The V8 platform used by this instance of Node does not support " \
173 "creating Workers") \
174 V(ERR_NON_CONTEXT_AWARE_DISABLED, \
175 "Loading non context-aware native addons has been disabled") \
176 V(ERR_SCRIPT_EXECUTION_INTERRUPTED, \
177 "Script execution was interrupted by `SIGINT`") \
178 V(ERR_TLS_PSK_SET_IDENTIY_HINT_FAILED, "Failed to set PSK identity hint") \
179 V(ERR_WASI_NOT_STARTED, "wasi.start() has not been called") \
180 V(ERR_WORKER_INIT_FAILED, "Worker initialization failure") \
181 V(ERR_PROTO_ACCESS, \
182 "Accessing Object.prototype.__proto__ has been " \
183 "disallowed with --disable-proto=throw")
184
185 #define V(code, message) \
186 inline v8::Local<v8::Value> code(v8::Isolate* isolate) { \
187 return code(isolate, message); \
188 } \
189 inline void THROW_ ## code(v8::Isolate* isolate) { \
190 isolate->ThrowException(code(isolate, message)); \
191 } \
192 inline void THROW_ ## code(Environment* env) { \
193 THROW_ ## code(env->isolate()); \
194 }
PREDEFINED_ERROR_MESSAGES(V)195 PREDEFINED_ERROR_MESSAGES(V)
196 #undef V
197
198 // Errors with predefined non-static messages
199 inline void THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(Environment* env,
200 int64_t timeout) {
201 std::ostringstream message;
202 message << "Script execution timed out after ";
203 message << timeout << "ms";
204 THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, message.str().c_str());
205 }
206
ERR_BUFFER_TOO_LARGE(v8::Isolate * isolate)207 inline v8::Local<v8::Value> ERR_BUFFER_TOO_LARGE(v8::Isolate* isolate) {
208 char message[128];
209 snprintf(message, sizeof(message),
210 "Cannot create a Buffer larger than 0x%zx bytes",
211 v8::TypedArray::kMaxLength);
212 return ERR_BUFFER_TOO_LARGE(isolate, message);
213 }
214
ERR_STRING_TOO_LONG(v8::Isolate * isolate)215 inline v8::Local<v8::Value> ERR_STRING_TOO_LONG(v8::Isolate* isolate) {
216 char message[128];
217 snprintf(message, sizeof(message),
218 "Cannot create a string longer than 0x%x characters",
219 v8::String::kMaxLength);
220 return ERR_STRING_TOO_LONG(isolate, message);
221 }
222
223 #define THROW_AND_RETURN_IF_NOT_BUFFER(env, val, prefix) \
224 do { \
225 if (!Buffer::HasInstance(val)) \
226 return node::THROW_ERR_INVALID_ARG_TYPE(env, \
227 prefix " must be a buffer"); \
228 } while (0)
229
230 #define THROW_AND_RETURN_IF_NOT_STRING(env, val, prefix) \
231 do { \
232 if (!val->IsString()) \
233 return node::THROW_ERR_INVALID_ARG_TYPE(env, \
234 prefix " must be a string"); \
235 } while (0)
236
237 namespace errors {
238
239 class TryCatchScope : public v8::TryCatch {
240 public:
241 enum class CatchMode { kNormal, kFatal };
242
243 explicit TryCatchScope(Environment* env, CatchMode mode = CatchMode::kNormal)
244 : v8::TryCatch(env->isolate()), env_(env), mode_(mode) {}
245 ~TryCatchScope();
246
247 // Since the dtor is not virtual we need to make sure no one creates
248 // object of it in the free store that might be held by polymorphic pointers.
249 void* operator new(std::size_t count) = delete;
250 void* operator new[](std::size_t count) = delete;
251 TryCatchScope(TryCatchScope&) = delete;
252 TryCatchScope(TryCatchScope&&) = delete;
253 TryCatchScope operator=(TryCatchScope&) = delete;
254 TryCatchScope operator=(TryCatchScope&&) = delete;
255
256 private:
257 Environment* env_;
258 CatchMode mode_;
259 };
260
261 // Trigger the global uncaught exception handler `process._fatalException`
262 // in JS land (which emits the 'uncaughtException' event). If that returns
263 // true, continue program execution, otherwise exit the process.
264 void TriggerUncaughtException(v8::Isolate* isolate,
265 const v8::TryCatch& try_catch);
266 void TriggerUncaughtException(v8::Isolate* isolate,
267 v8::Local<v8::Value> error,
268 v8::Local<v8::Message> message,
269 bool from_promise = false);
270
271 const char* errno_string(int errorno);
272 void PerIsolateMessageListener(v8::Local<v8::Message> message,
273 v8::Local<v8::Value> error);
274
275 void DecorateErrorStack(Environment* env,
276 const errors::TryCatchScope& try_catch);
277 } // namespace errors
278
279 v8::ModifyCodeGenerationFromStringsResult ModifyCodeGenerationFromStrings(
280 v8::Local<v8::Context> context,
281 v8::Local<v8::Value> source,
282 bool is_code_like);
283
284 } // namespace node
285
286 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
287
288 #endif // SRC_NODE_ERRORS_H_
289