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