GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/api/exceptions.cc Lines: 65 65 100.0 %
Date: 2019-05-05 22:32:45 Branches: 23 32 71.9 %

Line Branch Exec Source
1
// This file contains implementation of error APIs exposed in node.h
2
3
#include "env-inl.h"
4
#include "node.h"
5
#include "node_errors.h"
6
#include "util-inl.h"
7
#include "uv.h"
8
#include "v8.h"
9
10
#include <cstring>
11
12
namespace node {
13
14
using v8::Exception;
15
using v8::HandleScope;
16
using v8::Integer;
17
using v8::Isolate;
18
using v8::Local;
19
using v8::Message;
20
using v8::NewStringType;
21
using v8::Object;
22
using v8::String;
23
using v8::Value;
24
25
4
Local<Value> ErrnoException(Isolate* isolate,
26
                            int errorno,
27
                            const char* syscall,
28
                            const char* msg,
29
                            const char* path) {
30
4
  Environment* env = Environment::GetCurrent(isolate);
31
4
  CHECK_NOT_NULL(env);
32
33
  Local<Value> e;
34
4
  Local<String> estring = OneByteString(isolate, errors::errno_string(errorno));
35

4
  if (msg == nullptr || msg[0] == '\0') {
36
3
    msg = strerror(errorno);
37
  }
38
4
  Local<String> message = OneByteString(isolate, msg);
39
40
  Local<String> cons =
41
4
      String::Concat(isolate, estring, FIXED_ONE_BYTE_STRING(isolate, ", "));
42
4
  cons = String::Concat(isolate, cons, message);
43
44
  Local<String> path_string;
45
4
  if (path != nullptr) {
46
    // FIXME(bnoordhuis) It's questionable to interpret the file path as UTF-8.
47
    path_string = String::NewFromUtf8(isolate, path, NewStringType::kNormal)
48
2
                      .ToLocalChecked();
49
  }
50
51
4
  if (path_string.IsEmpty() == false) {
52
1
    cons = String::Concat(isolate, cons, FIXED_ONE_BYTE_STRING(isolate, " '"));
53
1
    cons = String::Concat(isolate, cons, path_string);
54
1
    cons = String::Concat(isolate, cons, FIXED_ONE_BYTE_STRING(isolate, "'"));
55
  }
56
4
  e = Exception::Error(cons);
57
58
4
  Local<Object> obj = e.As<Object>();
59
  obj->Set(env->context(),
60
           env->errno_string(),
61
20
           Integer::New(isolate, errorno)).Check();
62
16
  obj->Set(env->context(), env->code_string(), estring).Check();
63
64
4
  if (path_string.IsEmpty() == false) {
65
4
    obj->Set(env->context(), env->path_string(), path_string).Check();
66
  }
67
68
4
  if (syscall != nullptr) {
69
    obj->Set(env->context(),
70
             env->syscall_string(),
71
20
             OneByteString(isolate, syscall)).Check();
72
  }
73
74
4
  return e;
75
}
76
77
5177
static Local<String> StringFromPath(Isolate* isolate, const char* path) {
78
#ifdef _WIN32
79
  if (strncmp(path, "\\\\?\\UNC\\", 8) == 0) {
80
    return String::Concat(
81
        isolate,
82
        FIXED_ONE_BYTE_STRING(isolate, "\\\\"),
83
        String::NewFromUtf8(isolate, path + 8, NewStringType::kNormal)
84
            .ToLocalChecked());
85
  } else if (strncmp(path, "\\\\?\\", 4) == 0) {
86
    return String::NewFromUtf8(isolate, path + 4, NewStringType::kNormal)
87
        .ToLocalChecked();
88
  }
89
#endif
90
91
  return String::NewFromUtf8(isolate, path, NewStringType::kNormal)
92
10354
      .ToLocalChecked();
93
}
94
95
96
5091
Local<Value> UVException(Isolate* isolate,
97
                         int errorno,
98
                         const char* syscall,
99
                         const char* msg,
100
                         const char* path,
101
                         const char* dest) {
102
5091
  Environment* env = Environment::GetCurrent(isolate);
103
5091
  CHECK_NOT_NULL(env);
104
105

5091
  if (!msg || !msg[0])
106
5091
    msg = uv_strerror(errorno);
107
108
5091
  Local<String> js_code = OneByteString(isolate, uv_err_name(errorno));
109
5091
  Local<String> js_syscall = OneByteString(isolate, syscall);
110
  Local<String> js_path;
111
  Local<String> js_dest;
112
113
5091
  Local<String> js_msg = js_code;
114
  js_msg =
115
5091
      String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, ": "));
116
5091
  js_msg = String::Concat(isolate, js_msg, OneByteString(isolate, msg));
117
  js_msg =
118
5091
      String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, ", "));
119
5091
  js_msg = String::Concat(isolate, js_msg, js_syscall);
120
121
5091
  if (path != nullptr) {
122
5055
    js_path = StringFromPath(isolate, path);
123
124
    js_msg =
125
5055
        String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, " '"));
126
5055
    js_msg = String::Concat(isolate, js_msg, js_path);
127
    js_msg =
128
5055
        String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, "'"));
129
  }
130
131
5091
  if (dest != nullptr) {
132
122
    js_dest = StringFromPath(isolate, dest);
133
134
    js_msg = String::Concat(
135
122
        isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, " -> '"));
136
122
    js_msg = String::Concat(isolate, js_msg, js_dest);
137
    js_msg =
138
122
        String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, "'"));
139
  }
140
141
  Local<Object> e =
142
15273
    Exception::Error(js_msg)->ToObject(isolate->GetCurrentContext())
143
10182
      .ToLocalChecked();
144
145
  e->Set(env->context(),
146
         env->errno_string(),
147
25455
         Integer::New(isolate, errorno)).Check();
148
20364
  e->Set(env->context(), env->code_string(), js_code).Check();
149
20364
  e->Set(env->context(), env->syscall_string(), js_syscall).Check();
150
5091
  if (!js_path.IsEmpty())
151
20220
    e->Set(env->context(), env->path_string(), js_path).Check();
152
5091
  if (!js_dest.IsEmpty())
153
488
    e->Set(env->context(), env->dest_string(), js_dest).Check();
154
155
5091
  return e;
156
}
157
158
#ifdef _WIN32
159
// Does about the same as strerror(),
160
// but supports all windows error messages
161
static const char* winapi_strerror(const int errorno, bool* must_free) {
162
  char* errmsg = nullptr;
163
164
  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
165
                    FORMAT_MESSAGE_IGNORE_INSERTS,
166
                nullptr,
167
                errorno,
168
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
169
                reinterpret_cast<LPTSTR>(&errmsg),
170
                0,
171
                nullptr);
172
173
  if (errmsg) {
174
    *must_free = true;
175
176
    // Remove trailing newlines
177
    for (int i = strlen(errmsg) - 1;
178
         i >= 0 && (errmsg[i] == '\n' || errmsg[i] == '\r');
179
         i--) {
180
      errmsg[i] = '\0';
181
    }
182
183
    return errmsg;
184
  } else {
185
    // FormatMessage failed
186
    *must_free = false;
187
    return "Unknown error";
188
  }
189
}
190
191
Local<Value> WinapiErrnoException(Isolate* isolate,
192
                                  int errorno,
193
                                  const char* syscall,
194
                                  const char* msg,
195
                                  const char* path) {
196
  Environment* env = Environment::GetCurrent(isolate);
197
  CHECK_NOT_NULL(env);
198
  Local<Value> e;
199
  bool must_free = false;
200
  if (!msg || !msg[0]) {
201
    msg = winapi_strerror(errorno, &must_free);
202
  }
203
  Local<String> message = OneByteString(isolate, msg);
204
205
  if (path) {
206
    Local<String> cons1 =
207
        String::Concat(isolate, message, FIXED_ONE_BYTE_STRING(isolate, " '"));
208
    Local<String> cons2 = String::Concat(
209
        isolate,
210
        cons1,
211
        String::NewFromUtf8(isolate, path, NewStringType::kNormal)
212
            .ToLocalChecked());
213
    Local<String> cons3 =
214
        String::Concat(isolate, cons2, FIXED_ONE_BYTE_STRING(isolate, "'"));
215
    e = Exception::Error(cons3);
216
  } else {
217
    e = Exception::Error(message);
218
  }
219
220
  Local<Object> obj = e.As<Object>();
221
  obj->Set(env->context(), env->errno_string(), Integer::New(isolate, errorno))
222
      .Check();
223
224
  if (path != nullptr) {
225
    obj->Set(env->context(),
226
             env->path_string(),
227
             String::NewFromUtf8(isolate, path, NewStringType::kNormal)
228
                 .ToLocalChecked())
229
        .Check();
230
  }
231
232
  if (syscall != nullptr) {
233
    obj->Set(env->context(),
234
             env->syscall_string(),
235
             OneByteString(isolate, syscall))
236
        .Check();
237
  }
238
239
  if (must_free) {
240
    LocalFree(const_cast<char*>(msg));
241
  }
242
243
  return e;
244
}
245
#endif
246
247
3
void FatalException(Isolate* isolate, const v8::TryCatch& try_catch) {
248
  // If we try to print out a termination exception, we'd just get 'null',
249
  // so just crashing here with that information seems like a better idea,
250
  // and in particular it seems like we should handle terminations at the call
251
  // site for this function rather than by printing them out somewhere.
252
3
  CHECK(!try_catch.HasTerminated());
253
254
3
  HandleScope scope(isolate);
255
3
  if (!try_catch.IsVerbose()) {
256
3
    FatalException(isolate, try_catch.Exception(), try_catch.Message());
257
2
  }
258
2
}
259
260
}  // namespace node