• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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