GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: util.cc Lines: 164 198 82.8 %
Date: 2022-09-25 04:23:55 Branches: 32 54 59.3 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "util.h"  // NOLINT(build/include_inline)
23
#include "util-inl.h"
24
25
#include "debug_utils-inl.h"
26
#include "env-inl.h"
27
#include "node_buffer.h"
28
#include "node_errors.h"
29
#include "node_internals.h"
30
#include "node_util.h"
31
#include "string_bytes.h"
32
#include "uv.h"
33
34
#ifdef _WIN32
35
#include <io.h>  // _S_IREAD _S_IWRITE
36
#include <time.h>
37
#ifndef S_IRUSR
38
#define S_IRUSR _S_IREAD
39
#endif  // S_IRUSR
40
#ifndef S_IWUSR
41
#define S_IWUSR _S_IWRITE
42
#endif  // S_IWUSR
43
#else
44
#include <sys/time.h>
45
#include <sys/types.h>
46
#endif
47
48
#include <atomic>
49
#include <cstdio>
50
#include <cstring>
51
#include <iomanip>
52
#include <sstream>
53
54
static std::atomic_int seq = {0};  // Sequence number for diagnostic filenames.
55
56
namespace node {
57
58
using v8::ArrayBufferView;
59
using v8::Isolate;
60
using v8::Local;
61
using v8::String;
62
using v8::Value;
63
64
template <typename T>
65
3333484
static void MakeUtf8String(Isolate* isolate,
66
                           Local<Value> value,
67
                           MaybeStackBuffer<T>* target) {
68
  Local<String> string;
69
6666968
  if (!value->ToString(isolate->GetCurrentContext()).ToLocal(&string)) return;
70
71
  size_t storage;
72
6666966
  if (!StringBytes::StorageSize(isolate, string, UTF8).To(&storage)) return;
73
3333483
  storage += 1;
74
3333483
  target->AllocateSufficientStorage(storage);
75
3333483
  const int flags =
76
      String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8;
77
3333483
  const int length =
78
      string->WriteUtf8(isolate, target->out(), storage, nullptr, flags);
79
3333483
  target->SetLengthAndZeroTerminate(length);
80
}
81
82
3107041
Utf8Value::Utf8Value(Isolate* isolate, Local<Value> value) {
83
3107041
  if (value.IsEmpty())
84
1983
    return;
85
86
3105058
  MakeUtf8String(isolate, value, this);
87
}
88
89
90
1197356
TwoByteValue::TwoByteValue(Isolate* isolate, Local<Value> value) {
91
1197356
  if (value.IsEmpty()) {
92
    return;
93
  }
94
95
  Local<String> string;
96
2394712
  if (!value->ToString(isolate->GetCurrentContext()).ToLocal(&string)) return;
97
98
  // Allocate enough space to include the null terminator
99
1197356
  const size_t storage = string->Length() + 1;
100
1197356
  AllocateSufficientStorage(storage);
101
102
1197356
  const int flags = String::NO_NULL_TERMINATION;
103
1197356
  const int length = string->Write(isolate, out(), 0, storage, flags);
104
1197356
  SetLengthAndZeroTerminate(length);
105
}
106
107
236008
BufferValue::BufferValue(Isolate* isolate, Local<Value> value) {
108
  // Slightly different take on Utf8Value. If value is a String,
109
  // it will return a Utf8 encoded string. If value is a Buffer,
110
  // it will copy the data out of the Buffer as is.
111
236008
  if (value.IsEmpty()) {
112
    // Dereferencing this object will return nullptr.
113
    Invalidate();
114
    return;
115
  }
116
117
472016
  if (value->IsString()) {
118
228426
    MakeUtf8String(isolate, value, this);
119
7582
  } else if (value->IsArrayBufferView()) {
120
7582
    const size_t len = value.As<ArrayBufferView>()->ByteLength();
121
    // Leave place for the terminating '\0' byte.
122
7582
    AllocateSufficientStorage(len + 1);
123
7582
    value.As<ArrayBufferView>()->CopyContents(out(), len);
124
7582
    SetLengthAndZeroTerminate(len);
125
  } else {
126
    Invalidate();
127
  }
128
}
129
130
void LowMemoryNotification() {
131
  if (per_process::v8_initialized) {
132
    auto isolate = Isolate::TryGetCurrent();
133
    if (isolate != nullptr) {
134
      isolate->LowMemoryNotification();
135
    }
136
  }
137
}
138
139
5781
std::string GetProcessTitle(const char* default_title) {
140
17343
  std::string buf(16, '\0');
141
142
  for (;;) {
143
15892
    const int rc = uv_get_process_title(&buf[0], buf.size());
144
145
15892
    if (rc == 0)
146
5738
      break;
147
148
    // If uv_setup_args() was not called, `uv_get_process_title()` will always
149
    // return `UV_ENOBUFS`, no matter the input size. Guard against a possible
150
    // infinite loop by limiting the buffer size.
151

10154
    if (rc != UV_ENOBUFS || buf.size() >= 1024 * 1024)
152
43
      return default_title;
153
154
10111
    buf.resize(2 * buf.size());
155
10111
  }
156
157
  // Strip excess trailing nul bytes. Using strlen() here is safe,
158
  // uv_get_process_title() always zero-terminates the result.
159
5738
  buf.resize(strlen(&buf[0]));
160
161
5738
  return buf;
162
}
163
164
5584
std::string GetHumanReadableProcessName() {
165
5584
  return SPrintF("%s[%d]", GetProcessTitle("Node.js"), uv_os_getpid());
166
}
167
168
15527
std::vector<std::string> SplitString(const std::string& in,
169
                                     char delim,
170
                                     bool skipEmpty) {
171
15527
  std::vector<std::string> out;
172
15527
  if (in.empty())
173
2
    return out;
174
31050
  std::istringstream in_stream(in);
175
47072
  while (in_stream.good()) {
176
31547
    std::string item;
177
31547
    std::getline(in_stream, item, delim);
178

31547
    if (item.empty() && skipEmpty) continue;
179
31547
    out.emplace_back(std::move(item));
180
  }
181
15525
  return out;
182
}
183
184
void ThrowErrStringTooLong(Isolate* isolate) {
185
  isolate->ThrowException(ERR_STRING_TOO_LONG(isolate));
186
}
187
188
12553
double GetCurrentTimeInMicroseconds() {
189
12553
  constexpr double kMicrosecondsPerSecond = 1e6;
190
  uv_timeval64_t tv;
191
12553
  CHECK_EQ(0, uv_gettimeofday(&tv));
192
12553
  return kMicrosecondsPerSecond * tv.tv_sec + tv.tv_usec;
193
}
194
195
6270
int WriteFileSync(const char* path, uv_buf_t buf) {
196
  uv_fs_t req;
197
6270
  int fd = uv_fs_open(nullptr,
198
                      &req,
199
                      path,
200
                      O_WRONLY | O_CREAT | O_TRUNC,
201
                      S_IWUSR | S_IRUSR,
202
                      nullptr);
203
6270
  uv_fs_req_cleanup(&req);
204
6270
  if (fd < 0) {
205
6
    return fd;
206
  }
207
208
6264
  int err = uv_fs_write(nullptr, &req, fd, &buf, 1, 0, nullptr);
209
6264
  uv_fs_req_cleanup(&req);
210
6264
  if (err < 0) {
211
    return err;
212
  }
213
214
6264
  err = uv_fs_close(nullptr, &req, fd, nullptr);
215
6264
  uv_fs_req_cleanup(&req);
216
6264
  return err;
217
}
218
219
6270
int WriteFileSync(v8::Isolate* isolate,
220
                  const char* path,
221
                  v8::Local<v8::String> string) {
222
12540
  node::Utf8Value utf8(isolate, string);
223
6270
  uv_buf_t buf = uv_buf_init(utf8.out(), utf8.length());
224
6270
  return WriteFileSync(path, buf);
225
}
226
227
int ReadFileSync(std::string* result, const char* path) {
228
  uv_fs_t req;
229
  auto defer_req_cleanup = OnScopeLeave([&req]() {
230
    uv_fs_req_cleanup(&req);
231
  });
232
233
  uv_file file = uv_fs_open(nullptr, &req, path, O_RDONLY, 0, nullptr);
234
  if (req.result < 0) {
235
    // req will be cleaned up by scope leave.
236
    return req.result;
237
  }
238
  uv_fs_req_cleanup(&req);
239
240
  auto defer_close = OnScopeLeave([file]() {
241
    uv_fs_t close_req;
242
    CHECK_EQ(0, uv_fs_close(nullptr, &close_req, file, nullptr));
243
    uv_fs_req_cleanup(&close_req);
244
  });
245
246
  *result = std::string("");
247
  char buffer[4096];
248
  uv_buf_t buf = uv_buf_init(buffer, sizeof(buffer));
249
250
  while (true) {
251
    const int r =
252
        uv_fs_read(nullptr, &req, file, &buf, 1, result->length(), nullptr);
253
    if (req.result < 0) {
254
      // req will be cleaned up by scope leave.
255
      return req.result;
256
    }
257
    uv_fs_req_cleanup(&req);
258
    if (r <= 0) {
259
      break;
260
    }
261
    result->append(buf.base, r);
262
  }
263
  return 0;
264
}
265
266
76
void DiagnosticFilename::LocalTime(TIME_TYPE* tm_struct) {
267
#ifdef _WIN32
268
  GetLocalTime(tm_struct);
269
#else  // UNIX, OSX
270
  struct timeval time_val;
271
76
  gettimeofday(&time_val, nullptr);
272
76
  localtime_r(&time_val.tv_sec, tm_struct);
273
#endif
274
76
}
275
276
// Defined in node_internals.h
277
41
std::string DiagnosticFilename::MakeFilename(
278
    uint64_t thread_id,
279
    const char* prefix,
280
    const char* ext) {
281
82
  std::ostringstream oss;
282
  TIME_TYPE tm_struct;
283
41
  LocalTime(&tm_struct);
284
41
  oss << prefix;
285
#ifdef _WIN32
286
  oss << "." << std::setfill('0') << std::setw(4) << tm_struct.wYear;
287
  oss << std::setfill('0') << std::setw(2) << tm_struct.wMonth;
288
  oss << std::setfill('0') << std::setw(2) << tm_struct.wDay;
289
  oss << "." << std::setfill('0') << std::setw(2) << tm_struct.wHour;
290
  oss << std::setfill('0') << std::setw(2) << tm_struct.wMinute;
291
  oss << std::setfill('0') << std::setw(2) << tm_struct.wSecond;
292
#else  // UNIX, OSX
293
  oss << "."
294
            << std::setfill('0')
295
41
            << std::setw(4)
296
41
            << tm_struct.tm_year + 1900;
297
  oss << std::setfill('0')
298
41
            << std::setw(2)
299
41
            << tm_struct.tm_mon + 1;
300
  oss << std::setfill('0')
301
41
            << std::setw(2)
302
41
            << tm_struct.tm_mday;
303
  oss << "."
304
            << std::setfill('0')
305
41
            << std::setw(2)
306
41
            << tm_struct.tm_hour;
307
  oss << std::setfill('0')
308
41
            << std::setw(2)
309
41
            << tm_struct.tm_min;
310
  oss << std::setfill('0')
311
41
            << std::setw(2)
312
41
            << tm_struct.tm_sec;
313
#endif
314
41
  oss << "." << uv_os_getpid();
315
41
  oss << "." << thread_id;
316
41
  oss << "." << std::setfill('0') << std::setw(3) << ++seq;
317
41
  oss << "." << ext;
318
41
  return oss.str();
319
}
320
321
1158608
Local<v8::FunctionTemplate> NewFunctionTemplate(
322
    v8::Isolate* isolate,
323
    v8::FunctionCallback callback,
324
    Local<v8::Signature> signature,
325
    v8::ConstructorBehavior behavior,
326
    v8::SideEffectType side_effect_type,
327
    const v8::CFunction* c_function) {
328
  return v8::FunctionTemplate::New(isolate,
329
                                   callback,
330
                                   Local<v8::Value>(),
331
                                   signature,
332
                                   0,
333
                                   behavior,
334
                                   side_effect_type,
335
1158608
                                   c_function);
336
}
337
338
279502
void SetMethod(Local<v8::Context> context,
339
               Local<v8::Object> that,
340
               const char* name,
341
               v8::FunctionCallback callback) {
342
279502
  Isolate* isolate = context->GetIsolate();
343
  Local<v8::Function> function =
344
279502
      NewFunctionTemplate(isolate,
345
                          callback,
346
                          Local<v8::Signature>(),
347
                          v8::ConstructorBehavior::kThrow,
348
279502
                          v8::SideEffectType::kHasSideEffect)
349
279502
          ->GetFunction(context)
350
279502
          .ToLocalChecked();
351
  // kInternalized strings are created in the old space.
352
279502
  const v8::NewStringType type = v8::NewStringType::kInternalized;
353
  Local<v8::String> name_string =
354
559004
      v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
355
559004
  that->Set(context, name_string, function).Check();
356
279502
  function->SetName(name_string);  // NODE_SET_METHOD() compatibility.
357
279502
}
358
359
1574
void SetFastMethod(Local<v8::Context> context,
360
                   Local<v8::Object> that,
361
                   const char* name,
362
                   v8::FunctionCallback slow_callback,
363
                   const v8::CFunction* c_function) {
364
1574
  Isolate* isolate = context->GetIsolate();
365
  Local<v8::Function> function =
366
1574
      NewFunctionTemplate(isolate,
367
                          slow_callback,
368
                          Local<v8::Signature>(),
369
                          v8::ConstructorBehavior::kThrow,
370
                          v8::SideEffectType::kHasNoSideEffect,
371
1574
                          c_function)
372
1574
          ->GetFunction(context)
373
1574
          .ToLocalChecked();
374
1574
  const v8::NewStringType type = v8::NewStringType::kInternalized;
375
  Local<v8::String> name_string =
376
3148
      v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
377
1574
  that->Set(context, name_string, function).Check();
378
1574
}
379
380
71489
void SetMethodNoSideEffect(Local<v8::Context> context,
381
                           Local<v8::Object> that,
382
                           const char* name,
383
                           v8::FunctionCallback callback) {
384
71489
  Isolate* isolate = context->GetIsolate();
385
  Local<v8::Function> function =
386
71489
      NewFunctionTemplate(isolate,
387
                          callback,
388
                          Local<v8::Signature>(),
389
                          v8::ConstructorBehavior::kThrow,
390
71489
                          v8::SideEffectType::kHasNoSideEffect)
391
71489
          ->GetFunction(context)
392
71489
          .ToLocalChecked();
393
  // kInternalized strings are created in the old space.
394
71489
  const v8::NewStringType type = v8::NewStringType::kInternalized;
395
  Local<v8::String> name_string =
396
142978
      v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
397
142978
  that->Set(context, name_string, function).Check();
398
71489
  function->SetName(name_string);  // NODE_SET_METHOD() compatibility.
399
71489
}
400
401
556284
void SetProtoMethod(v8::Isolate* isolate,
402
                    Local<v8::FunctionTemplate> that,
403
                    const char* name,
404
                    v8::FunctionCallback callback) {
405
556284
  Local<v8::Signature> signature = v8::Signature::New(isolate, that);
406
  Local<v8::FunctionTemplate> t =
407
      NewFunctionTemplate(isolate,
408
                          callback,
409
                          signature,
410
                          v8::ConstructorBehavior::kThrow,
411
556284
                          v8::SideEffectType::kHasSideEffect);
412
  // kInternalized strings are created in the old space.
413
556284
  const v8::NewStringType type = v8::NewStringType::kInternalized;
414
  Local<v8::String> name_string =
415
1112568
      v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
416
1112568
  that->PrototypeTemplate()->Set(name_string, t);
417
556284
  t->SetClassName(name_string);  // NODE_SET_PROTOTYPE_METHOD() compatibility.
418
556284
}
419
420
87241
void SetProtoMethodNoSideEffect(v8::Isolate* isolate,
421
                                Local<v8::FunctionTemplate> that,
422
                                const char* name,
423
                                v8::FunctionCallback callback) {
424
87241
  Local<v8::Signature> signature = v8::Signature::New(isolate, that);
425
  Local<v8::FunctionTemplate> t =
426
      NewFunctionTemplate(isolate,
427
                          callback,
428
                          signature,
429
                          v8::ConstructorBehavior::kThrow,
430
87241
                          v8::SideEffectType::kHasNoSideEffect);
431
  // kInternalized strings are created in the old space.
432
87241
  const v8::NewStringType type = v8::NewStringType::kInternalized;
433
  Local<v8::String> name_string =
434
174482
      v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
435
174482
  that->PrototypeTemplate()->Set(name_string, t);
436
87241
  t->SetClassName(name_string);  // NODE_SET_PROTOTYPE_METHOD() compatibility.
437
87241
}
438
439
33
void SetInstanceMethod(v8::Isolate* isolate,
440
                       Local<v8::FunctionTemplate> that,
441
                       const char* name,
442
                       v8::FunctionCallback callback) {
443
33
  Local<v8::Signature> signature = v8::Signature::New(isolate, that);
444
  Local<v8::FunctionTemplate> t =
445
      NewFunctionTemplate(isolate,
446
                          callback,
447
                          signature,
448
                          v8::ConstructorBehavior::kThrow,
449
33
                          v8::SideEffectType::kHasSideEffect);
450
  // kInternalized strings are created in the old space.
451
33
  const v8::NewStringType type = v8::NewStringType::kInternalized;
452
  Local<v8::String> name_string =
453
66
      v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
454
66
  that->InstanceTemplate()->Set(name_string, t);
455
33
  t->SetClassName(name_string);
456
33
}
457
458
105051
void SetConstructorFunction(Local<v8::Context> context,
459
                            Local<v8::Object> that,
460
                            const char* name,
461
                            Local<v8::FunctionTemplate> tmpl,
462
                            SetConstructorFunctionFlag flag) {
463
105051
  Isolate* isolate = context->GetIsolate();
464
105051
  SetConstructorFunction(
465
      context, that, OneByteString(isolate, name), tmpl, flag);
466
105051
}
467
468
108986
void SetConstructorFunction(Local<v8::Context> context,
469
                            Local<v8::Object> that,
470
                            Local<v8::String> name,
471
                            Local<v8::FunctionTemplate> tmpl,
472
                            SetConstructorFunctionFlag flag) {
473
108986
  if (LIKELY(flag == SetConstructorFunctionFlag::SET_CLASS_NAME))
474
95689
    tmpl->SetClassName(name);
475
217972
  that->Set(context, name, tmpl->GetFunction(context).ToLocalChecked()).Check();
476
108986
}
477
478
}  // namespace node