GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: util.cc Lines: 164 198 82.8 %
Date: 2022-10-23 04:21:34 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
3485433
static void MakeUtf8String(Isolate* isolate,
66
                           Local<Value> value,
67
                           MaybeStackBuffer<T>* target) {
68
  Local<String> string;
69
6970866
  if (!value->ToString(isolate->GetCurrentContext()).ToLocal(&string)) return;
70
71
  size_t storage;
72
6970864
  if (!StringBytes::StorageSize(isolate, string, UTF8).To(&storage)) return;
73
3485432
  storage += 1;
74
3485432
  target->AllocateSufficientStorage(storage);
75
3485432
  const int flags =
76
      String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8;
77
3485432
  const int length =
78
      string->WriteUtf8(isolate, target->out(), storage, nullptr, flags);
79
3485432
  target->SetLengthAndZeroTerminate(length);
80
}
81
82
3256273
Utf8Value::Utf8Value(Isolate* isolate, Local<Value> value) {
83
3256273
  if (value.IsEmpty())
84
1974
    return;
85
86
3254299
  MakeUtf8String(isolate, value, this);
87
}
88
89
90
1196863
TwoByteValue::TwoByteValue(Isolate* isolate, Local<Value> value) {
91
1196863
  if (value.IsEmpty()) {
92
    return;
93
  }
94
95
  Local<String> string;
96
2393726
  if (!value->ToString(isolate->GetCurrentContext()).ToLocal(&string)) return;
97
98
  // Allocate enough space to include the null terminator
99
1196863
  const size_t storage = string->Length() + 1;
100
1196863
  AllocateSufficientStorage(storage);
101
102
1196863
  const int flags = String::NO_NULL_TERMINATION;
103
1196863
  const int length = string->Write(isolate, out(), 0, storage, flags);
104
1196863
  SetLengthAndZeroTerminate(length);
105
}
106
107
238750
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
238750
  if (value.IsEmpty()) {
112
    // Dereferencing this object will return nullptr.
113
    Invalidate();
114
    return;
115
  }
116
117
477500
  if (value->IsString()) {
118
231134
    MakeUtf8String(isolate, value, this);
119
7616
  } else if (value->IsArrayBufferView()) {
120
7616
    const size_t len = value.As<ArrayBufferView>()->ByteLength();
121
    // Leave place for the terminating '\0' byte.
122
7616
    AllocateSufficientStorage(len + 1);
123
7616
    value.As<ArrayBufferView>()->CopyContents(out(), len);
124
7616
    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
5826
std::string GetProcessTitle(const char* default_title) {
140
17478
  std::string buf(16, '\0');
141
142
  for (;;) {
143
16036
    const int rc = uv_get_process_title(&buf[0], buf.size());
144
145
16036
    if (rc == 0)
146
5783
      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

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

31762
    if (item.empty() && skipEmpty) continue;
179
31762
    out.emplace_back(std::move(item));
180
  }
181
15633
  return out;
182
}
183
184
void ThrowErrStringTooLong(Isolate* isolate) {
185
  isolate->ThrowException(ERR_STRING_TOO_LONG(isolate));
186
}
187
188
12646
double GetCurrentTimeInMicroseconds() {
189
12646
  constexpr double kMicrosecondsPerSecond = 1e6;
190
  uv_timeval64_t tv;
191
12646
  CHECK_EQ(0, uv_gettimeofday(&tv));
192
12646
  return kMicrosecondsPerSecond * tv.tv_sec + tv.tv_usec;
193
}
194
195
6316
int WriteFileSync(const char* path, uv_buf_t buf) {
196
  uv_fs_t req;
197
6316
  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
6316
  uv_fs_req_cleanup(&req);
204
6316
  if (fd < 0) {
205
2
    return fd;
206
  }
207
208
6314
  int err = uv_fs_write(nullptr, &req, fd, &buf, 1, 0, nullptr);
209
6314
  uv_fs_req_cleanup(&req);
210
6314
  if (err < 0) {
211
    return err;
212
  }
213
214
6314
  err = uv_fs_close(nullptr, &req, fd, nullptr);
215
6314
  uv_fs_req_cleanup(&req);
216
6314
  return err;
217
}
218
219
6316
int WriteFileSync(v8::Isolate* isolate,
220
                  const char* path,
221
                  v8::Local<v8::String> string) {
222
12632
  node::Utf8Value utf8(isolate, string);
223
6316
  uv_buf_t buf = uv_buf_init(utf8.out(), utf8.length());
224
6316
  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
1165346
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
1165346
                                   c_function);
336
}
337
338
280736
void SetMethod(Local<v8::Context> context,
339
               Local<v8::Object> that,
340
               const char* name,
341
               v8::FunctionCallback callback) {
342
280736
  Isolate* isolate = context->GetIsolate();
343
  Local<v8::Function> function =
344
280736
      NewFunctionTemplate(isolate,
345
                          callback,
346
                          Local<v8::Signature>(),
347
                          v8::ConstructorBehavior::kThrow,
348
280736
                          v8::SideEffectType::kHasSideEffect)
349
280736
          ->GetFunction(context)
350
280736
          .ToLocalChecked();
351
  // kInternalized strings are created in the old space.
352
280736
  const v8::NewStringType type = v8::NewStringType::kInternalized;
353
  Local<v8::String> name_string =
354
561472
      v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
355
561472
  that->Set(context, name_string, function).Check();
356
280736
  function->SetName(name_string);  // NODE_SET_METHOD() compatibility.
357
280736
}
358
359
1576
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
1576
  Isolate* isolate = context->GetIsolate();
365
  Local<v8::Function> function =
366
1576
      NewFunctionTemplate(isolate,
367
                          slow_callback,
368
                          Local<v8::Signature>(),
369
                          v8::ConstructorBehavior::kThrow,
370
                          v8::SideEffectType::kHasNoSideEffect,
371
1576
                          c_function)
372
1576
          ->GetFunction(context)
373
1576
          .ToLocalChecked();
374
1576
  const v8::NewStringType type = v8::NewStringType::kInternalized;
375
  Local<v8::String> name_string =
376
3152
      v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
377
1576
  that->Set(context, name_string, function).Check();
378
1576
}
379
380
71625
void SetMethodNoSideEffect(Local<v8::Context> context,
381
                           Local<v8::Object> that,
382
                           const char* name,
383
                           v8::FunctionCallback callback) {
384
71625
  Isolate* isolate = context->GetIsolate();
385
  Local<v8::Function> function =
386
71625
      NewFunctionTemplate(isolate,
387
                          callback,
388
                          Local<v8::Signature>(),
389
                          v8::ConstructorBehavior::kThrow,
390
71625
                          v8::SideEffectType::kHasNoSideEffect)
391
71625
          ->GetFunction(context)
392
71625
          .ToLocalChecked();
393
  // kInternalized strings are created in the old space.
394
71625
  const v8::NewStringType type = v8::NewStringType::kInternalized;
395
  Local<v8::String> name_string =
396
143250
      v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
397
143250
  that->Set(context, name_string, function).Check();
398
71625
  function->SetName(name_string);  // NODE_SET_METHOD() compatibility.
399
71625
}
400
401
559538
void SetProtoMethod(v8::Isolate* isolate,
402
                    Local<v8::FunctionTemplate> that,
403
                    const char* name,
404
                    v8::FunctionCallback callback) {
405
559538
  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
559538
                          v8::SideEffectType::kHasSideEffect);
412
  // kInternalized strings are created in the old space.
413
559538
  const v8::NewStringType type = v8::NewStringType::kInternalized;
414
  Local<v8::String> name_string =
415
1119076
      v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
416
1119076
  that->PrototypeTemplate()->Set(name_string, t);
417
559538
  t->SetClassName(name_string);  // NODE_SET_PROTOTYPE_METHOD() compatibility.
418
559538
}
419
420
87715
void SetProtoMethodNoSideEffect(v8::Isolate* isolate,
421
                                Local<v8::FunctionTemplate> that,
422
                                const char* name,
423
                                v8::FunctionCallback callback) {
424
87715
  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
87715
                          v8::SideEffectType::kHasNoSideEffect);
431
  // kInternalized strings are created in the old space.
432
87715
  const v8::NewStringType type = v8::NewStringType::kInternalized;
433
  Local<v8::String> name_string =
434
175430
      v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
435
175430
  that->PrototypeTemplate()->Set(name_string, t);
436
87715
  t->SetClassName(name_string);  // NODE_SET_PROTOTYPE_METHOD() compatibility.
437
87715
}
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
105584
void SetConstructorFunction(Local<v8::Context> context,
459
                            Local<v8::Object> that,
460
                            const char* name,
461
                            Local<v8::FunctionTemplate> tmpl,
462
                            SetConstructorFunctionFlag flag) {
463
105584
  Isolate* isolate = context->GetIsolate();
464
105584
  SetConstructorFunction(
465
      context, that, OneByteString(isolate, name), tmpl, flag);
466
105584
}
467
468
109524
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
109524
  if (LIKELY(flag == SetConstructorFunctionFlag::SET_CLASS_NAME))
474
96132
    tmpl->SetClassName(name);
475
219048
  that->Set(context, name, tmpl->GetFunction(context).ToLocalChecked()).Check();
476
109524
}
477
478
}  // namespace node