GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: util.cc Lines: 178 212 84.0 %
Date: 2022-12-31 04:22:30 Branches: 33 56 58.9 %

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::Context;
60
using v8::FunctionTemplate;
61
using v8::Isolate;
62
using v8::Local;
63
using v8::Object;
64
using v8::String;
65
using v8::Template;
66
using v8::Value;
67
68
template <typename T>
69
3507838
static void MakeUtf8String(Isolate* isolate,
70
                           Local<Value> value,
71
                           MaybeStackBuffer<T>* target) {
72
  Local<String> string;
73
7015676
  if (!value->ToString(isolate->GetCurrentContext()).ToLocal(&string)) return;
74
75
  size_t storage;
76
7015674
  if (!StringBytes::StorageSize(isolate, string, UTF8).To(&storage)) return;
77
3507837
  storage += 1;
78
3507837
  target->AllocateSufficientStorage(storage);
79
3507837
  const int flags =
80
      String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8;
81
3507837
  const int length =
82
      string->WriteUtf8(isolate, target->out(), storage, nullptr, flags);
83
3507837
  target->SetLengthAndZeroTerminate(length);
84
}
85
86
3277290
Utf8Value::Utf8Value(Isolate* isolate, Local<Value> value) {
87
3277290
  if (value.IsEmpty())
88
2018
    return;
89
90
3275272
  MakeUtf8String(isolate, value, this);
91
}
92
93
94
1196669
TwoByteValue::TwoByteValue(Isolate* isolate, Local<Value> value) {
95
1196669
  if (value.IsEmpty()) {
96
    return;
97
  }
98
99
  Local<String> string;
100
2393338
  if (!value->ToString(isolate->GetCurrentContext()).ToLocal(&string)) return;
101
102
  // Allocate enough space to include the null terminator
103
1196669
  const size_t storage = string->Length() + 1;
104
1196669
  AllocateSufficientStorage(storage);
105
106
1196669
  const int flags = String::NO_NULL_TERMINATION;
107
1196669
  const int length = string->Write(isolate, out(), 0, storage, flags);
108
1196669
  SetLengthAndZeroTerminate(length);
109
}
110
111
240660
BufferValue::BufferValue(Isolate* isolate, Local<Value> value) {
112
  // Slightly different take on Utf8Value. If value is a String,
113
  // it will return a Utf8 encoded string. If value is a Buffer,
114
  // it will copy the data out of the Buffer as is.
115
240660
  if (value.IsEmpty()) {
116
    // Dereferencing this object will return nullptr.
117
    Invalidate();
118
    return;
119
  }
120
121
481320
  if (value->IsString()) {
122
232566
    MakeUtf8String(isolate, value, this);
123
8094
  } else if (value->IsArrayBufferView()) {
124
8094
    const size_t len = value.As<ArrayBufferView>()->ByteLength();
125
    // Leave place for the terminating '\0' byte.
126
8094
    AllocateSufficientStorage(len + 1);
127
8094
    value.As<ArrayBufferView>()->CopyContents(out(), len);
128
8094
    SetLengthAndZeroTerminate(len);
129
  } else {
130
    Invalidate();
131
  }
132
}
133
134
void LowMemoryNotification() {
135
  if (per_process::v8_initialized) {
136
    auto isolate = Isolate::TryGetCurrent();
137
    if (isolate != nullptr) {
138
      isolate->LowMemoryNotification();
139
    }
140
  }
141
}
142
143
5989
std::string GetProcessTitle(const char* default_title) {
144
17967
  std::string buf(16, '\0');
145
146
  for (;;) {
147
16505
    const int rc = uv_get_process_title(&buf[0], buf.size());
148
149
16505
    if (rc == 0)
150
5947
      break;
151
152
    // If uv_setup_args() was not called, `uv_get_process_title()` will always
153
    // return `UV_ENOBUFS`, no matter the input size. Guard against a possible
154
    // infinite loop by limiting the buffer size.
155

10558
    if (rc != UV_ENOBUFS || buf.size() >= 1024 * 1024)
156
42
      return default_title;
157
158
10516
    buf.resize(2 * buf.size());
159
10516
  }
160
161
  // Strip excess trailing nul bytes. Using strlen() here is safe,
162
  // uv_get_process_title() always zero-terminates the result.
163
5947
  buf.resize(strlen(&buf[0]));
164
165
5947
  return buf;
166
}
167
168
5777
std::string GetHumanReadableProcessName() {
169
5777
  return SPrintF("%s[%d]", GetProcessTitle("Node.js"), uv_os_getpid());
170
}
171
172
15873
std::vector<std::string> SplitString(const std::string& in,
173
                                     char delim,
174
                                     bool skipEmpty) {
175
15873
  std::vector<std::string> out;
176
15873
  if (in.empty())
177
2
    return out;
178
31742
  std::istringstream in_stream(in);
179
48058
  while (in_stream.good()) {
180
32187
    std::string item;
181
32187
    std::getline(in_stream, item, delim);
182

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