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