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