11cb0ef41Sopenharmony_ci// This file contains implementation of error APIs exposed in node.h
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci#include "env-inl.h"
41cb0ef41Sopenharmony_ci#include "node.h"
51cb0ef41Sopenharmony_ci#include "node_errors.h"
61cb0ef41Sopenharmony_ci#include "util-inl.h"
71cb0ef41Sopenharmony_ci#include "uv.h"
81cb0ef41Sopenharmony_ci#include "v8.h"
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci#include <cstring>
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_cinamespace node {
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ciusing v8::Context;
151cb0ef41Sopenharmony_ciusing v8::Exception;
161cb0ef41Sopenharmony_ciusing v8::Integer;
171cb0ef41Sopenharmony_ciusing v8::Isolate;
181cb0ef41Sopenharmony_ciusing v8::Local;
191cb0ef41Sopenharmony_ciusing v8::Object;
201cb0ef41Sopenharmony_ciusing v8::String;
211cb0ef41Sopenharmony_ciusing v8::Value;
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ciLocal<Value> ErrnoException(Isolate* isolate,
241cb0ef41Sopenharmony_ci                            int errorno,
251cb0ef41Sopenharmony_ci                            const char* syscall,
261cb0ef41Sopenharmony_ci                            const char* msg,
271cb0ef41Sopenharmony_ci                            const char* path) {
281cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(isolate);
291cb0ef41Sopenharmony_ci  CHECK_NOT_NULL(env);
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci  Local<Value> e;
321cb0ef41Sopenharmony_ci  Local<String> estring = OneByteString(isolate, errors::errno_string(errorno));
331cb0ef41Sopenharmony_ci  if (msg == nullptr || msg[0] == '\0') {
341cb0ef41Sopenharmony_ci    msg = strerror(errorno);
351cb0ef41Sopenharmony_ci  }
361cb0ef41Sopenharmony_ci  Local<String> message = OneByteString(isolate, msg);
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  Local<String> cons =
391cb0ef41Sopenharmony_ci      String::Concat(isolate, estring, FIXED_ONE_BYTE_STRING(isolate, ", "));
401cb0ef41Sopenharmony_ci  cons = String::Concat(isolate, cons, message);
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci  Local<String> path_string;
431cb0ef41Sopenharmony_ci  if (path != nullptr) {
441cb0ef41Sopenharmony_ci    // FIXME(bnoordhuis) It's questionable to interpret the file path as UTF-8.
451cb0ef41Sopenharmony_ci    path_string = String::NewFromUtf8(isolate, path).ToLocalChecked();
461cb0ef41Sopenharmony_ci  }
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci  if (path_string.IsEmpty() == false) {
491cb0ef41Sopenharmony_ci    cons = String::Concat(isolate, cons, FIXED_ONE_BYTE_STRING(isolate, " '"));
501cb0ef41Sopenharmony_ci    cons = String::Concat(isolate, cons, path_string);
511cb0ef41Sopenharmony_ci    cons = String::Concat(isolate, cons, FIXED_ONE_BYTE_STRING(isolate, "'"));
521cb0ef41Sopenharmony_ci  }
531cb0ef41Sopenharmony_ci  e = Exception::Error(cons);
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci  Local<Context> context = env->context();
561cb0ef41Sopenharmony_ci  Local<Object> obj = e.As<Object>();
571cb0ef41Sopenharmony_ci  obj->Set(context,
581cb0ef41Sopenharmony_ci           env->errno_string(),
591cb0ef41Sopenharmony_ci           Integer::New(isolate, errorno)).Check();
601cb0ef41Sopenharmony_ci  obj->Set(context, env->code_string(), estring).Check();
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci  if (path_string.IsEmpty() == false) {
631cb0ef41Sopenharmony_ci    obj->Set(context, env->path_string(), path_string).Check();
641cb0ef41Sopenharmony_ci  }
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci  if (syscall != nullptr) {
671cb0ef41Sopenharmony_ci    obj->Set(context,
681cb0ef41Sopenharmony_ci             env->syscall_string(),
691cb0ef41Sopenharmony_ci             OneByteString(isolate, syscall)).Check();
701cb0ef41Sopenharmony_ci  }
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci  return e;
731cb0ef41Sopenharmony_ci}
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_cistatic Local<String> StringFromPath(Isolate* isolate, const char* path) {
761cb0ef41Sopenharmony_ci#ifdef _WIN32
771cb0ef41Sopenharmony_ci  if (strncmp(path, "\\\\?\\UNC\\", 8) == 0) {
781cb0ef41Sopenharmony_ci    return String::Concat(
791cb0ef41Sopenharmony_ci        isolate,
801cb0ef41Sopenharmony_ci        FIXED_ONE_BYTE_STRING(isolate, "\\\\"),
811cb0ef41Sopenharmony_ci        String::NewFromUtf8(isolate, path + 8).ToLocalChecked());
821cb0ef41Sopenharmony_ci  } else if (strncmp(path, "\\\\?\\", 4) == 0) {
831cb0ef41Sopenharmony_ci    return String::NewFromUtf8(isolate, path + 4).ToLocalChecked();
841cb0ef41Sopenharmony_ci  }
851cb0ef41Sopenharmony_ci#endif
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  return String::NewFromUtf8(isolate, path).ToLocalChecked();
881cb0ef41Sopenharmony_ci}
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ciLocal<Value> UVException(Isolate* isolate,
921cb0ef41Sopenharmony_ci                         int errorno,
931cb0ef41Sopenharmony_ci                         const char* syscall,
941cb0ef41Sopenharmony_ci                         const char* msg,
951cb0ef41Sopenharmony_ci                         const char* path,
961cb0ef41Sopenharmony_ci                         const char* dest) {
971cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(isolate);
981cb0ef41Sopenharmony_ci  CHECK_NOT_NULL(env);
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci  if (!msg || !msg[0])
1011cb0ef41Sopenharmony_ci    msg = uv_strerror(errorno);
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  Local<String> js_code = OneByteString(isolate, uv_err_name(errorno));
1041cb0ef41Sopenharmony_ci  Local<String> js_syscall = OneByteString(isolate, syscall);
1051cb0ef41Sopenharmony_ci  Local<String> js_path;
1061cb0ef41Sopenharmony_ci  Local<String> js_dest;
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci  Local<String> js_msg = js_code;
1091cb0ef41Sopenharmony_ci  js_msg =
1101cb0ef41Sopenharmony_ci      String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, ": "));
1111cb0ef41Sopenharmony_ci  js_msg = String::Concat(isolate, js_msg, OneByteString(isolate, msg));
1121cb0ef41Sopenharmony_ci  js_msg =
1131cb0ef41Sopenharmony_ci      String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, ", "));
1141cb0ef41Sopenharmony_ci  js_msg = String::Concat(isolate, js_msg, js_syscall);
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ci  if (path != nullptr) {
1171cb0ef41Sopenharmony_ci    js_path = StringFromPath(isolate, path);
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci    js_msg =
1201cb0ef41Sopenharmony_ci        String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, " '"));
1211cb0ef41Sopenharmony_ci    js_msg = String::Concat(isolate, js_msg, js_path);
1221cb0ef41Sopenharmony_ci    js_msg =
1231cb0ef41Sopenharmony_ci        String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, "'"));
1241cb0ef41Sopenharmony_ci  }
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci  if (dest != nullptr) {
1271cb0ef41Sopenharmony_ci    js_dest = StringFromPath(isolate, dest);
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci    js_msg = String::Concat(
1301cb0ef41Sopenharmony_ci        isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, " -> '"));
1311cb0ef41Sopenharmony_ci    js_msg = String::Concat(isolate, js_msg, js_dest);
1321cb0ef41Sopenharmony_ci    js_msg =
1331cb0ef41Sopenharmony_ci        String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, "'"));
1341cb0ef41Sopenharmony_ci  }
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci  Local<Object> e =
1371cb0ef41Sopenharmony_ci    Exception::Error(js_msg)->ToObject(isolate->GetCurrentContext())
1381cb0ef41Sopenharmony_ci      .ToLocalChecked();
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci  Local<Context> context = env->context();
1411cb0ef41Sopenharmony_ci  e->Set(context,
1421cb0ef41Sopenharmony_ci         env->errno_string(),
1431cb0ef41Sopenharmony_ci         Integer::New(isolate, errorno)).Check();
1441cb0ef41Sopenharmony_ci  e->Set(context, env->code_string(), js_code).Check();
1451cb0ef41Sopenharmony_ci  e->Set(context, env->syscall_string(), js_syscall).Check();
1461cb0ef41Sopenharmony_ci  if (!js_path.IsEmpty())
1471cb0ef41Sopenharmony_ci    e->Set(context, env->path_string(), js_path).Check();
1481cb0ef41Sopenharmony_ci  if (!js_dest.IsEmpty())
1491cb0ef41Sopenharmony_ci    e->Set(context, env->dest_string(), js_dest).Check();
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci  return e;
1521cb0ef41Sopenharmony_ci}
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci#ifdef _WIN32
1551cb0ef41Sopenharmony_ci// Does about the same as strerror(),
1561cb0ef41Sopenharmony_ci// but supports all windows error messages
1571cb0ef41Sopenharmony_cistatic const char* winapi_strerror(const int errorno, bool* must_free) {
1581cb0ef41Sopenharmony_ci  char* errmsg = nullptr;
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
1611cb0ef41Sopenharmony_ci                    FORMAT_MESSAGE_IGNORE_INSERTS,
1621cb0ef41Sopenharmony_ci                nullptr,
1631cb0ef41Sopenharmony_ci                errorno,
1641cb0ef41Sopenharmony_ci                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1651cb0ef41Sopenharmony_ci                reinterpret_cast<LPTSTR>(&errmsg),
1661cb0ef41Sopenharmony_ci                0,
1671cb0ef41Sopenharmony_ci                nullptr);
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci  if (errmsg) {
1701cb0ef41Sopenharmony_ci    *must_free = true;
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ci    // Remove trailing newlines
1731cb0ef41Sopenharmony_ci    for (int i = strlen(errmsg) - 1;
1741cb0ef41Sopenharmony_ci         i >= 0 && (errmsg[i] == '\n' || errmsg[i] == '\r');
1751cb0ef41Sopenharmony_ci         i--) {
1761cb0ef41Sopenharmony_ci      errmsg[i] = '\0';
1771cb0ef41Sopenharmony_ci    }
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ci    return errmsg;
1801cb0ef41Sopenharmony_ci  } else {
1811cb0ef41Sopenharmony_ci    // FormatMessage failed
1821cb0ef41Sopenharmony_ci    *must_free = false;
1831cb0ef41Sopenharmony_ci    return "Unknown error";
1841cb0ef41Sopenharmony_ci  }
1851cb0ef41Sopenharmony_ci}
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ciLocal<Value> WinapiErrnoException(Isolate* isolate,
1881cb0ef41Sopenharmony_ci                                  int errorno,
1891cb0ef41Sopenharmony_ci                                  const char* syscall,
1901cb0ef41Sopenharmony_ci                                  const char* msg,
1911cb0ef41Sopenharmony_ci                                  const char* path) {
1921cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(isolate);
1931cb0ef41Sopenharmony_ci  CHECK_NOT_NULL(env);
1941cb0ef41Sopenharmony_ci  Local<Value> e;
1951cb0ef41Sopenharmony_ci  bool must_free = false;
1961cb0ef41Sopenharmony_ci  if (!msg || !msg[0]) {
1971cb0ef41Sopenharmony_ci    msg = winapi_strerror(errorno, &must_free);
1981cb0ef41Sopenharmony_ci  }
1991cb0ef41Sopenharmony_ci  Local<String> message = OneByteString(isolate, msg);
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci  if (path) {
2021cb0ef41Sopenharmony_ci    Local<String> cons1 =
2031cb0ef41Sopenharmony_ci        String::Concat(isolate, message, FIXED_ONE_BYTE_STRING(isolate, " '"));
2041cb0ef41Sopenharmony_ci    Local<String> cons2 = String::Concat(
2051cb0ef41Sopenharmony_ci        isolate,
2061cb0ef41Sopenharmony_ci        cons1,
2071cb0ef41Sopenharmony_ci        String::NewFromUtf8(isolate, path).ToLocalChecked());
2081cb0ef41Sopenharmony_ci    Local<String> cons3 =
2091cb0ef41Sopenharmony_ci        String::Concat(isolate, cons2, FIXED_ONE_BYTE_STRING(isolate, "'"));
2101cb0ef41Sopenharmony_ci    e = Exception::Error(cons3);
2111cb0ef41Sopenharmony_ci  } else {
2121cb0ef41Sopenharmony_ci    e = Exception::Error(message);
2131cb0ef41Sopenharmony_ci  }
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_ci  Local<Context> context = env->context();
2161cb0ef41Sopenharmony_ci  Local<Object> obj = e.As<Object>();
2171cb0ef41Sopenharmony_ci  obj->Set(context, env->errno_string(), Integer::New(isolate, errorno))
2181cb0ef41Sopenharmony_ci      .Check();
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_ci  if (path != nullptr) {
2211cb0ef41Sopenharmony_ci    obj->Set(context,
2221cb0ef41Sopenharmony_ci             env->path_string(),
2231cb0ef41Sopenharmony_ci             String::NewFromUtf8(isolate, path).ToLocalChecked())
2241cb0ef41Sopenharmony_ci        .Check();
2251cb0ef41Sopenharmony_ci  }
2261cb0ef41Sopenharmony_ci
2271cb0ef41Sopenharmony_ci  if (syscall != nullptr) {
2281cb0ef41Sopenharmony_ci    obj->Set(context,
2291cb0ef41Sopenharmony_ci             env->syscall_string(),
2301cb0ef41Sopenharmony_ci             OneByteString(isolate, syscall))
2311cb0ef41Sopenharmony_ci        .Check();
2321cb0ef41Sopenharmony_ci  }
2331cb0ef41Sopenharmony_ci
2341cb0ef41Sopenharmony_ci  if (must_free) {
2351cb0ef41Sopenharmony_ci    LocalFree(const_cast<char*>(msg));
2361cb0ef41Sopenharmony_ci  }
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_ci  return e;
2391cb0ef41Sopenharmony_ci}
2401cb0ef41Sopenharmony_ci#endif  // _WIN32
2411cb0ef41Sopenharmony_ci
2421cb0ef41Sopenharmony_ci// Implement the legacy name exposed in node.h. This has not been in fact
2431cb0ef41Sopenharmony_ci// fatal any more, as the user can handle the exception in the
2441cb0ef41Sopenharmony_ci// TryCatch by listening to `uncaughtException`.
2451cb0ef41Sopenharmony_ci// TODO(joyeecheung): deprecate it in favor of a more accurate name.
2461cb0ef41Sopenharmony_civoid FatalException(Isolate* isolate, const v8::TryCatch& try_catch) {
2471cb0ef41Sopenharmony_ci  errors::TriggerUncaughtException(isolate, try_catch);
2481cb0ef41Sopenharmony_ci}
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_ci}  // namespace node
251