Coverage Report

Created: 2025-10-31 09:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/src/util.cc
Line
Count
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 <cmath>
24
#include <cstdint>
25
#include "util-inl.h"
26
27
#include "debug_utils-inl.h"
28
#include "env-inl.h"
29
#include "node_buffer.h"
30
#include "node_errors.h"
31
#include "node_internals.h"
32
#include "node_snapshot_builder.h"
33
#include "node_v8_platform-inl.h"
34
#include "string_bytes.h"
35
#include "v8-value.h"
36
37
#ifdef _WIN32
38
#include <io.h>  // _S_IREAD _S_IWRITE
39
#include <time.h>
40
#ifndef S_IRUSR
41
#define S_IRUSR _S_IREAD
42
#endif  // S_IRUSR
43
#ifndef S_IWUSR
44
#define S_IWUSR _S_IWRITE
45
#endif  // S_IWUSR
46
#else
47
#include <sys/time.h>
48
#include <sys/types.h>
49
#endif
50
51
#include <simdutf.h>
52
53
#include <atomic>
54
#include <cstdio>
55
#include <cstring>
56
#include <iomanip>
57
#include <sstream>
58
59
static std::atomic_int seq = {0};  // Sequence number for diagnostic filenames.
60
61
// F_OK etc. constants
62
#ifdef _WIN32
63
#include "uv.h"
64
#else
65
#include <unistd.h>
66
#endif
67
68
// The access modes can be any of F_OK, R_OK, W_OK or X_OK. Some might not be
69
// available on specific systems. They can be used in combination as well
70
// (F_OK | R_OK | W_OK | X_OK).
71
constexpr int kMaximumAccessMode = F_OK | W_OK | R_OK | X_OK;
72
constexpr int kMinimumAccessMode = std::min({F_OK, W_OK, R_OK, X_OK});
73
74
constexpr int kDefaultCopyMode = 0;
75
// The copy modes can be any of UV_FS_COPYFILE_EXCL, UV_FS_COPYFILE_FICLONE or
76
// UV_FS_COPYFILE_FICLONE_FORCE. They can be used in combination as well
77
// (US_FS_COPYFILE_EXCL | US_FS_COPYFILE_FICLONE |
78
// US_FS_COPYFILE_FICLONE_FORCE).
79
constexpr int kMinimumCopyMode = std::min({kDefaultCopyMode,
80
                                           UV_FS_COPYFILE_EXCL,
81
                                           UV_FS_COPYFILE_FICLONE,
82
                                           UV_FS_COPYFILE_FICLONE_FORCE});
83
constexpr int kMaximumCopyMode =
84
    UV_FS_COPYFILE_EXCL | UV_FS_COPYFILE_FICLONE | UV_FS_COPYFILE_FICLONE_FORCE;
85
86
namespace node {
87
88
using v8::ArrayBuffer;
89
using v8::ArrayBufferView;
90
using v8::Context;
91
using v8::FunctionTemplate;
92
using v8::Isolate;
93
using v8::Local;
94
using v8::Object;
95
using v8::String;
96
using v8::Template;
97
using v8::Value;
98
99
template <typename T>
100
static void MakeUtf8String(Isolate* isolate,
101
                           Local<Value> value,
102
3.60k
                           MaybeStackBuffer<T>* target) {
103
3.60k
  Local<String> string;
104
3.60k
  if (!value->ToString(isolate->GetCurrentContext()).ToLocal(&string)) return;
105
3.60k
  String::ValueView value_view(isolate, string);
106
107
3.60k
  auto value_length = value_view.length();
108
109
3.60k
  if (value_view.is_one_byte()) {
110
3.60k
    auto const_char = reinterpret_cast<const char*>(value_view.data8());
111
3.60k
    auto expected_length =
112
3.60k
        target->capacity() < (static_cast<size_t>(value_length) * 2 + 1)
113
3.60k
            ? simdutf::utf8_length_from_latin1(const_char, value_length)
114
3.60k
            : value_length * 2;
115
116
    // Add +1 for null termination.
117
3.60k
    target->AllocateSufficientStorage(expected_length + 1);
118
3.60k
    const auto actual_length = simdutf::convert_latin1_to_utf8(
119
3.60k
        const_char, value_length, target->out());
120
3.60k
    target->SetLengthAndZeroTerminate(actual_length);
121
3.60k
    return;
122
3.60k
  }
123
124
  // Add +1 for null termination.
125
0
  size_t storage = (3 * value_length) + 1;
126
0
  target->AllocateSufficientStorage(storage);
127
128
0
  size_t length = string->WriteUtf8V2(
129
0
      isolate, target->out(), storage, String::WriteFlags::kReplaceInvalidUtf8);
130
0
  target->SetLengthAndZeroTerminate(length);
131
0
}
132
133
3.60k
Utf8Value::Utf8Value(Isolate* isolate, Local<Value> value) {
134
3.60k
  if (value.IsEmpty())
135
0
    return;
136
137
3.60k
  MakeUtf8String(isolate, value, this);
138
3.60k
}
139
140
141
0
TwoByteValue::TwoByteValue(Isolate* isolate, Local<Value> value) {
142
0
  if (value.IsEmpty()) {
143
0
    return;
144
0
  }
145
146
0
  Local<String> string;
147
0
  if (!value->ToString(isolate->GetCurrentContext()).ToLocal(&string)) return;
148
149
  // Allocate enough space to include the null terminator.
150
0
  const size_t length = string->Length();
151
0
  AllocateSufficientStorage(length + 1);
152
0
  string->WriteV2(isolate, 0, length, out());
153
0
  SetLengthAndZeroTerminate(length);
154
0
}
155
156
0
BufferValue::BufferValue(Isolate* isolate, Local<Value> value) {
157
  // Slightly different take on Utf8Value. If value is a String,
158
  // it will return a Utf8 encoded string. If value is a Buffer,
159
  // it will copy the data out of the Buffer as is.
160
0
  if (value.IsEmpty()) {
161
    // Dereferencing this object will return nullptr.
162
0
    Invalidate();
163
0
    return;
164
0
  }
165
166
0
  if (value->IsString()) {
167
0
    MakeUtf8String(isolate, value, this);
168
0
  } else if (value->IsArrayBufferView()) {
169
0
    const size_t len = value.As<ArrayBufferView>()->ByteLength();
170
    // Leave place for the terminating '\0' byte.
171
0
    AllocateSufficientStorage(len + 1);
172
0
    value.As<ArrayBufferView>()->CopyContents(out(), len);
173
0
    SetLengthAndZeroTerminate(len);
174
0
  } else {
175
0
    Invalidate();
176
0
  }
177
0
}
178
179
0
void LowMemoryNotification() {
180
0
  if (per_process::v8_initialized) {
181
0
    auto isolate = Isolate::TryGetCurrent();
182
0
    if (isolate != nullptr) {
183
0
      isolate->LowMemoryNotification();
184
0
    }
185
0
  }
186
0
}
187
188
35
std::string GetProcessTitle(const char* default_title) {
189
35
  std::string buf(16, '\0');
190
191
595
  for (;;) {
192
595
    const int rc = uv_get_process_title(buf.data(), buf.size());
193
194
595
    if (rc == 0)
195
0
      break;
196
197
    // If uv_setup_args() was not called, `uv_get_process_title()` will always
198
    // return `UV_ENOBUFS`, no matter the input size. Guard against a possible
199
    // infinite loop by limiting the buffer size.
200
595
    if (rc != UV_ENOBUFS || buf.size() >= 1024 * 1024)
201
35
      return default_title;
202
203
560
    buf.resize(2 * buf.size());
204
560
  }
205
206
  // Strip excess trailing nul bytes. Using strlen() here is safe,
207
  // uv_get_process_title() always zero-terminates the result.
208
0
  buf.resize(strlen(buf.data()));
209
210
0
  return buf;
211
35
}
212
213
35
std::string GetHumanReadableProcessName() {
214
35
  return SPrintF("%s[%d]", GetProcessTitle("Node.js"), uv_os_getpid());
215
35
}
216
217
0
void ThrowErrStringTooLong(Isolate* isolate) {
218
0
  isolate->ThrowException(ERR_STRING_TOO_LONG(isolate));
219
0
}
220
221
72
double GetCurrentTimeInMicroseconds() {
222
72
  constexpr double kMicrosecondsPerSecond = 1e6;
223
72
  uv_timeval64_t tv;
224
72
  CHECK_EQ(0, uv_gettimeofday(&tv));
225
72
  return kMicrosecondsPerSecond * tv.tv_sec + tv.tv_usec;
226
72
}
227
228
0
int WriteFileSync(const char* path, uv_buf_t buf) {
229
0
  return WriteFileSync(path, &buf, 1);
230
0
}
231
232
0
int WriteFileSync(const char* path, uv_buf_t* bufs, size_t buf_count) {
233
0
  uv_fs_t req;
234
0
  int fd = uv_fs_open(nullptr,
235
0
                      &req,
236
0
                      path,
237
0
                      O_WRONLY | O_CREAT | O_TRUNC,
238
0
                      S_IWUSR | S_IRUSR,
239
0
                      nullptr);
240
0
  uv_fs_req_cleanup(&req);
241
0
  if (fd < 0) {
242
0
    return fd;
243
0
  }
244
245
0
  int err = uv_fs_write(nullptr, &req, fd, bufs, buf_count, 0, nullptr);
246
0
  uv_fs_req_cleanup(&req);
247
0
  if (err < 0) {
248
0
    return err;
249
0
  }
250
251
0
  err = uv_fs_close(nullptr, &req, fd, nullptr);
252
0
  uv_fs_req_cleanup(&req);
253
0
  return err;
254
0
}
255
256
int WriteFileSync(v8::Isolate* isolate,
257
                  const char* path,
258
0
                  v8::Local<v8::String> string) {
259
0
  node::Utf8Value utf8(isolate, string);
260
0
  uv_buf_t buf = uv_buf_init(utf8.out(), utf8.length());
261
0
  return WriteFileSync(path, buf);
262
0
}
263
264
0
int ReadFileSync(std::string* result, const char* path) {
265
0
  uv_fs_t req;
266
0
  auto defer_req_cleanup = OnScopeLeave([&req]() {
267
0
    uv_fs_req_cleanup(&req);
268
0
  });
269
270
0
  uv_file file = uv_fs_open(nullptr, &req, path, O_RDONLY, 0, nullptr);
271
0
  if (req.result < 0) {
272
    // req will be cleaned up by scope leave.
273
0
    return req.result;
274
0
  }
275
0
  uv_fs_req_cleanup(&req);
276
277
0
  auto defer_close = OnScopeLeave([file]() {
278
0
    uv_fs_t close_req;
279
0
    CHECK_EQ(0, uv_fs_close(nullptr, &close_req, file, nullptr));
280
0
    uv_fs_req_cleanup(&close_req);
281
0
  });
282
283
0
  *result = std::string("");
284
0
  char buffer[4096];
285
0
  uv_buf_t buf = uv_buf_init(buffer, sizeof(buffer));
286
287
0
  while (true) {
288
0
    const int r =
289
0
        uv_fs_read(nullptr, &req, file, &buf, 1, result->length(), nullptr);
290
0
    if (req.result < 0) {
291
      // req will be cleaned up by scope leave.
292
0
      return req.result;
293
0
    }
294
0
    uv_fs_req_cleanup(&req);
295
0
    if (r <= 0) {
296
0
      break;
297
0
    }
298
0
    result->append(buf.base, r);
299
0
  }
300
0
  return 0;
301
0
}
302
303
0
std::vector<char> ReadFileSync(FILE* fp) {
304
0
  CHECK_EQ(ftell(fp), 0);
305
0
  int err = fseek(fp, 0, SEEK_END);
306
0
  CHECK_EQ(err, 0);
307
0
  size_t size = ftell(fp);
308
0
  CHECK_NE(size, static_cast<size_t>(-1L));
309
0
  err = fseek(fp, 0, SEEK_SET);
310
0
  CHECK_EQ(err, 0);
311
312
0
  std::vector<char> contents(size);
313
0
  size_t num_read = fread(contents.data(), size, 1, fp);
314
0
  CHECK_EQ(num_read, 1);
315
0
  return contents;
316
0
}
317
318
0
void DiagnosticFilename::LocalTime(TIME_TYPE* tm_struct) {
319
#ifdef _WIN32
320
  GetLocalTime(tm_struct);
321
#else  // UNIX, macOS
322
0
  struct timeval time_val;
323
0
  gettimeofday(&time_val, nullptr);
324
0
  localtime_r(&time_val.tv_sec, tm_struct);
325
0
#endif
326
0
}
327
328
// Defined in node_internals.h
329
std::string DiagnosticFilename::MakeFilename(
330
    uint64_t thread_id,
331
    const char* prefix,
332
0
    const char* ext) {
333
0
  std::ostringstream oss;
334
0
  TIME_TYPE tm_struct;
335
0
  LocalTime(&tm_struct);
336
0
  oss << prefix;
337
#ifdef _WIN32
338
  oss << "." << std::setfill('0') << std::setw(4) << tm_struct.wYear;
339
  oss << std::setfill('0') << std::setw(2) << tm_struct.wMonth;
340
  oss << std::setfill('0') << std::setw(2) << tm_struct.wDay;
341
  oss << "." << std::setfill('0') << std::setw(2) << tm_struct.wHour;
342
  oss << std::setfill('0') << std::setw(2) << tm_struct.wMinute;
343
  oss << std::setfill('0') << std::setw(2) << tm_struct.wSecond;
344
#else  // UNIX, macOS
345
0
  oss << "."
346
0
            << std::setfill('0')
347
0
            << std::setw(4)
348
0
            << tm_struct.tm_year + 1900;
349
0
  oss << std::setfill('0')
350
0
            << std::setw(2)
351
0
            << tm_struct.tm_mon + 1;
352
0
  oss << std::setfill('0')
353
0
            << std::setw(2)
354
0
            << tm_struct.tm_mday;
355
0
  oss << "."
356
0
            << std::setfill('0')
357
0
            << std::setw(2)
358
0
            << tm_struct.tm_hour;
359
0
  oss << std::setfill('0')
360
0
            << std::setw(2)
361
0
            << tm_struct.tm_min;
362
0
  oss << std::setfill('0')
363
0
            << std::setw(2)
364
0
            << tm_struct.tm_sec;
365
0
#endif
366
0
  oss << "." << uv_os_getpid();
367
0
  oss << "." << thread_id;
368
0
  oss << "." << std::setfill('0') << std::setw(3) << ++seq;
369
0
  oss << "." << ext;
370
0
  return oss.str();
371
0
}
372
373
Local<v8::FunctionTemplate> NewFunctionTemplate(
374
    v8::Isolate* isolate,
375
    v8::FunctionCallback callback,
376
    Local<v8::Signature> signature,
377
    v8::ConstructorBehavior behavior,
378
    v8::SideEffectType side_effect_type,
379
14.8k
    const v8::CFunction* c_function) {
380
14.8k
  return v8::FunctionTemplate::New(isolate,
381
14.8k
                                   callback,
382
14.8k
                                   Local<v8::Value>(),
383
14.8k
                                   signature,
384
14.8k
                                   0,
385
14.8k
                                   behavior,
386
14.8k
                                   side_effect_type,
387
14.8k
                                   c_function);
388
14.8k
}
389
390
void SetMethod(Local<v8::Context> context,
391
               Local<v8::Object> that,
392
               const std::string_view name,
393
2.03k
               v8::FunctionCallback callback) {
394
2.03k
  Isolate* isolate = Isolate::GetCurrent();
395
2.03k
  Local<v8::Function> function =
396
2.03k
      NewFunctionTemplate(isolate,
397
2.03k
                          callback,
398
2.03k
                          Local<v8::Signature>(),
399
2.03k
                          v8::ConstructorBehavior::kThrow,
400
2.03k
                          v8::SideEffectType::kHasSideEffect)
401
2.03k
          ->GetFunction(context)
402
2.03k
          .ToLocalChecked();
403
  // kInternalized strings are created in the old space.
404
2.03k
  const v8::NewStringType type = v8::NewStringType::kInternalized;
405
2.03k
  Local<v8::String> name_string =
406
2.03k
      v8::String::NewFromUtf8(isolate, name.data(), type, name.size())
407
2.03k
          .ToLocalChecked();
408
2.03k
  that->Set(context, name_string, function).Check();
409
2.03k
  function->SetName(name_string);  // NODE_SET_METHOD() compatibility.
410
2.03k
}
411
412
void SetMethod(v8::Isolate* isolate,
413
               v8::Local<v8::Template> that,
414
               const std::string_view name,
415
5.14k
               v8::FunctionCallback callback) {
416
5.14k
  Local<v8::FunctionTemplate> t =
417
5.14k
      NewFunctionTemplate(isolate,
418
5.14k
                          callback,
419
5.14k
                          Local<v8::Signature>(),
420
5.14k
                          v8::ConstructorBehavior::kThrow,
421
5.14k
                          v8::SideEffectType::kHasSideEffect);
422
  // kInternalized strings are created in the old space.
423
5.14k
  const v8::NewStringType type = v8::NewStringType::kInternalized;
424
5.14k
  Local<v8::String> name_string =
425
5.14k
      v8::String::NewFromUtf8(isolate, name.data(), type, name.size())
426
5.14k
          .ToLocalChecked();
427
5.14k
  that->Set(name_string, t);
428
5.14k
}
429
430
void SetFastMethod(Isolate* isolate,
431
                   Local<Template> that,
432
                   const std::string_view name,
433
                   v8::FunctionCallback slow_callback,
434
245
                   const v8::CFunction* c_function) {
435
245
  Local<v8::FunctionTemplate> t =
436
245
      NewFunctionTemplate(isolate,
437
245
                          slow_callback,
438
245
                          Local<v8::Signature>(),
439
245
                          v8::ConstructorBehavior::kThrow,
440
245
                          v8::SideEffectType::kHasSideEffect,
441
245
                          c_function);
442
  // kInternalized strings are created in the old space.
443
245
  const v8::NewStringType type = v8::NewStringType::kInternalized;
444
245
  Local<v8::String> name_string =
445
245
      v8::String::NewFromUtf8(isolate, name.data(), type, name.size())
446
245
          .ToLocalChecked();
447
245
  that->Set(name_string, t);
448
245
}
449
450
void SetFastMethod(Local<v8::Context> context,
451
                   Local<v8::Object> that,
452
                   const std::string_view name,
453
                   v8::FunctionCallback slow_callback,
454
140
                   const v8::CFunction* c_function) {
455
140
  Isolate* isolate = Isolate::GetCurrent();
456
140
  Local<v8::Function> function =
457
140
      NewFunctionTemplate(isolate,
458
140
                          slow_callback,
459
140
                          Local<v8::Signature>(),
460
140
                          v8::ConstructorBehavior::kThrow,
461
140
                          v8::SideEffectType::kHasSideEffect,
462
140
                          c_function)
463
140
          ->GetFunction(context)
464
140
          .ToLocalChecked();
465
140
  const v8::NewStringType type = v8::NewStringType::kInternalized;
466
140
  Local<v8::String> name_string =
467
140
      v8::String::NewFromUtf8(isolate, name.data(), type, name.size())
468
140
          .ToLocalChecked();
469
140
  that->Set(context, name_string, function).Check();
470
140
}
471
472
void SetFastMethodNoSideEffect(Local<v8::Context> context,
473
                               Local<v8::Object> that,
474
                               const std::string_view name,
475
                               v8::FunctionCallback slow_callback,
476
1.08k
                               const v8::CFunction* c_function) {
477
1.08k
  Isolate* isolate = Isolate::GetCurrent();
478
1.08k
  Local<v8::Function> function =
479
1.08k
      NewFunctionTemplate(isolate,
480
1.08k
                          slow_callback,
481
1.08k
                          Local<v8::Signature>(),
482
1.08k
                          v8::ConstructorBehavior::kThrow,
483
1.08k
                          v8::SideEffectType::kHasNoSideEffect,
484
1.08k
                          c_function)
485
1.08k
          ->GetFunction(context)
486
1.08k
          .ToLocalChecked();
487
1.08k
  const v8::NewStringType type = v8::NewStringType::kInternalized;
488
1.08k
  Local<v8::String> name_string =
489
1.08k
      v8::String::NewFromUtf8(isolate, name.data(), type, name.size())
490
1.08k
          .ToLocalChecked();
491
1.08k
  that->Set(context, name_string, function).Check();
492
1.08k
}
493
494
void SetFastMethodNoSideEffect(Isolate* isolate,
495
                               Local<Template> that,
496
                               const std::string_view name,
497
                               v8::FunctionCallback slow_callback,
498
350
                               const v8::CFunction* c_function) {
499
350
  Local<v8::FunctionTemplate> t =
500
350
      NewFunctionTemplate(isolate,
501
350
                          slow_callback,
502
350
                          Local<v8::Signature>(),
503
350
                          v8::ConstructorBehavior::kThrow,
504
350
                          v8::SideEffectType::kHasNoSideEffect,
505
350
                          c_function);
506
  // kInternalized strings are created in the old space.
507
350
  const v8::NewStringType type = v8::NewStringType::kInternalized;
508
350
  Local<v8::String> name_string =
509
350
      v8::String::NewFromUtf8(isolate, name.data(), type, name.size())
510
350
          .ToLocalChecked();
511
350
  that->Set(name_string, t);
512
350
}
513
514
void SetFastMethod(Isolate* isolate,
515
                   Local<Template> that,
516
                   const std::string_view name,
517
                   v8::FunctionCallback slow_callback,
518
0
                   const v8::MemorySpan<const v8::CFunction>& methods) {
519
0
  Local<v8::FunctionTemplate> t = FunctionTemplate::NewWithCFunctionOverloads(
520
0
      isolate,
521
0
      slow_callback,
522
0
      Local<Value>(),
523
0
      Local<v8::Signature>(),
524
0
      0,
525
0
      v8::ConstructorBehavior::kThrow,
526
0
      v8::SideEffectType::kHasSideEffect,
527
0
      methods);
528
529
  // kInternalized strings are created in the old space.
530
0
  const v8::NewStringType type = v8::NewStringType::kInternalized;
531
0
  Local<v8::String> name_string =
532
0
      v8::String::NewFromUtf8(isolate, name.data(), type, name.size())
533
0
          .ToLocalChecked();
534
0
  that->Set(name_string, t);
535
0
}
536
537
void SetFastMethodNoSideEffect(
538
    Isolate* isolate,
539
    Local<Template> that,
540
    const std::string_view name,
541
    v8::FunctionCallback slow_callback,
542
35
    const v8::MemorySpan<const v8::CFunction>& methods) {
543
35
  Local<v8::FunctionTemplate> t = FunctionTemplate::NewWithCFunctionOverloads(
544
35
      isolate,
545
35
      slow_callback,
546
35
      Local<Value>(),
547
35
      Local<v8::Signature>(),
548
35
      0,
549
35
      v8::ConstructorBehavior::kThrow,
550
35
      v8::SideEffectType::kHasNoSideEffect,
551
35
      methods);
552
553
  // kInternalized strings are created in the old space.
554
35
  const v8::NewStringType type = v8::NewStringType::kInternalized;
555
35
  Local<v8::String> name_string =
556
35
      v8::String::NewFromUtf8(isolate, name.data(), type, name.size())
557
35
          .ToLocalChecked();
558
35
  that->Set(name_string, t);
559
35
}
560
561
void SetMethodNoSideEffect(Local<v8::Context> context,
562
                           Local<v8::Object> that,
563
                           const std::string_view name,
564
1.33k
                           v8::FunctionCallback callback) {
565
1.33k
  Isolate* isolate = Isolate::GetCurrent();
566
1.33k
  Local<v8::Function> function =
567
1.33k
      NewFunctionTemplate(isolate,
568
1.33k
                          callback,
569
1.33k
                          Local<v8::Signature>(),
570
1.33k
                          v8::ConstructorBehavior::kThrow,
571
1.33k
                          v8::SideEffectType::kHasNoSideEffect)
572
1.33k
          ->GetFunction(context)
573
1.33k
          .ToLocalChecked();
574
  // kInternalized strings are created in the old space.
575
1.33k
  const v8::NewStringType type = v8::NewStringType::kInternalized;
576
1.33k
  Local<v8::String> name_string =
577
1.33k
      v8::String::NewFromUtf8(isolate, name.data(), type, name.size())
578
1.33k
          .ToLocalChecked();
579
1.33k
  that->Set(context, name_string, function).Check();
580
1.33k
  function->SetName(name_string);  // NODE_SET_METHOD() compatibility.
581
1.33k
}
582
583
void SetMethodNoSideEffect(Isolate* isolate,
584
                           Local<v8::Template> that,
585
                           const std::string_view name,
586
420
                           v8::FunctionCallback callback) {
587
420
  Local<v8::FunctionTemplate> t =
588
420
      NewFunctionTemplate(isolate,
589
420
                          callback,
590
420
                          Local<v8::Signature>(),
591
420
                          v8::ConstructorBehavior::kThrow,
592
420
                          v8::SideEffectType::kHasNoSideEffect);
593
  // kInternalized strings are created in the old space.
594
420
  const v8::NewStringType type = v8::NewStringType::kInternalized;
595
420
  Local<v8::String> name_string =
596
420
      v8::String::NewFromUtf8(isolate, name.data(), type, name.size())
597
420
          .ToLocalChecked();
598
420
  that->Set(name_string, t);
599
420
}
600
601
void SetProtoDispose(v8::Isolate* isolate,
602
                     v8::Local<v8::FunctionTemplate> that,
603
0
                     v8::FunctionCallback callback) {
604
0
  Local<v8::Signature> signature = v8::Signature::New(isolate, that);
605
0
  Local<v8::FunctionTemplate> t =
606
0
      NewFunctionTemplate(isolate,
607
0
                          callback,
608
0
                          signature,
609
0
                          v8::ConstructorBehavior::kThrow,
610
0
                          v8::SideEffectType::kHasSideEffect);
611
0
  that->PrototypeTemplate()->Set(v8::Symbol::GetDispose(isolate), t);
612
0
}
613
614
void SetProtoAsyncDispose(v8::Isolate* isolate,
615
                          v8::Local<v8::FunctionTemplate> that,
616
0
                          v8::FunctionCallback callback) {
617
0
  Local<v8::Signature> signature = v8::Signature::New(isolate, that);
618
0
  Local<v8::FunctionTemplate> t =
619
0
      NewFunctionTemplate(isolate,
620
0
                          callback,
621
0
                          signature,
622
0
                          v8::ConstructorBehavior::kThrow,
623
0
                          v8::SideEffectType::kHasSideEffect);
624
0
  that->PrototypeTemplate()->Set(v8::Symbol::GetAsyncDispose(isolate), t);
625
0
}
626
627
void SetProtoMethod(v8::Isolate* isolate,
628
                    Local<v8::FunctionTemplate> that,
629
                    const std::string_view name,
630
2.45k
                    v8::FunctionCallback callback) {
631
2.45k
  Local<v8::Signature> signature = v8::Signature::New(isolate, that);
632
2.45k
  Local<v8::FunctionTemplate> t =
633
2.45k
      NewFunctionTemplate(isolate,
634
2.45k
                          callback,
635
2.45k
                          signature,
636
2.45k
                          v8::ConstructorBehavior::kThrow,
637
2.45k
                          v8::SideEffectType::kHasSideEffect);
638
  // kInternalized strings are created in the old space.
639
2.45k
  const v8::NewStringType type = v8::NewStringType::kInternalized;
640
2.45k
  Local<v8::String> name_string =
641
2.45k
      v8::String::NewFromUtf8(isolate, name.data(), type, name.size())
642
2.45k
          .ToLocalChecked();
643
2.45k
  that->PrototypeTemplate()->Set(name_string, t);
644
2.45k
  t->SetClassName(name_string);  // NODE_SET_PROTOTYPE_METHOD() compatibility.
645
2.45k
}
646
647
void SetProtoMethodNoSideEffect(v8::Isolate* isolate,
648
                                Local<v8::FunctionTemplate> that,
649
                                const std::string_view name,
650
490
                                v8::FunctionCallback callback) {
651
490
  Local<v8::Signature> signature = v8::Signature::New(isolate, that);
652
490
  Local<v8::FunctionTemplate> t =
653
490
      NewFunctionTemplate(isolate,
654
490
                          callback,
655
490
                          signature,
656
490
                          v8::ConstructorBehavior::kThrow,
657
490
                          v8::SideEffectType::kHasNoSideEffect);
658
  // kInternalized strings are created in the old space.
659
490
  const v8::NewStringType type = v8::NewStringType::kInternalized;
660
490
  Local<v8::String> name_string =
661
490
      v8::String::NewFromUtf8(isolate, name.data(), type, name.size())
662
490
          .ToLocalChecked();
663
490
  that->PrototypeTemplate()->Set(name_string, t);
664
490
  t->SetClassName(name_string);  // NODE_SET_PROTOTYPE_METHOD() compatibility.
665
490
}
666
667
void SetInstanceMethod(v8::Isolate* isolate,
668
                       Local<v8::FunctionTemplate> that,
669
                       const std::string_view name,
670
0
                       v8::FunctionCallback callback) {
671
0
  Local<v8::Signature> signature = v8::Signature::New(isolate, that);
672
0
  Local<v8::FunctionTemplate> t =
673
0
      NewFunctionTemplate(isolate,
674
0
                          callback,
675
0
                          signature,
676
0
                          v8::ConstructorBehavior::kThrow,
677
0
                          v8::SideEffectType::kHasSideEffect);
678
  // kInternalized strings are created in the old space.
679
0
  const v8::NewStringType type = v8::NewStringType::kInternalized;
680
0
  Local<v8::String> name_string =
681
0
      v8::String::NewFromUtf8(isolate, name.data(), type, name.size())
682
0
          .ToLocalChecked();
683
0
  that->InstanceTemplate()->Set(name_string, t);
684
0
  t->SetClassName(name_string);
685
0
}
686
687
void SetConstructorFunction(Local<v8::Context> context,
688
                            Local<v8::Object> that,
689
                            const char* name,
690
                            Local<v8::FunctionTemplate> tmpl,
691
70
                            SetConstructorFunctionFlag flag) {
692
70
  Isolate* isolate = Isolate::GetCurrent();
693
70
  SetConstructorFunction(
694
70
      context, that, OneByteString(isolate, name), tmpl, flag);
695
70
}
696
697
void SetConstructorFunction(Local<Context> context,
698
                            Local<Object> that,
699
                            Local<String> name,
700
                            Local<FunctionTemplate> tmpl,
701
140
                            SetConstructorFunctionFlag flag) {
702
140
  if (flag == SetConstructorFunctionFlag::SET_CLASS_NAME) [[likely]] {
703
140
    tmpl->SetClassName(name);
704
140
  }
705
140
  that->Set(context, name, tmpl->GetFunction(context).ToLocalChecked()).Check();
706
140
}
707
708
void SetConstructorFunction(Isolate* isolate,
709
                            Local<Template> that,
710
                            const char* name,
711
                            Local<FunctionTemplate> tmpl,
712
350
                            SetConstructorFunctionFlag flag) {
713
350
  SetConstructorFunction(
714
350
      isolate, that, OneByteString(isolate, name), tmpl, flag);
715
350
}
716
717
void SetConstructorFunction(Isolate* isolate,
718
                            Local<Template> that,
719
                            Local<String> name,
720
                            Local<FunctionTemplate> tmpl,
721
385
                            SetConstructorFunctionFlag flag) {
722
385
  if (flag == SetConstructorFunctionFlag::SET_CLASS_NAME) [[likely]] {
723
350
    tmpl->SetClassName(name);
724
350
  }
725
385
  that->Set(name, tmpl);
726
385
}
727
728
2.59k
Local<String> UnionBytes::ToStringChecked(Isolate* isolate) const {
729
2.59k
  if (is_one_byte()) {
730
2.52k
    return String::NewExternalOneByte(isolate, one_byte_resource_)
731
2.52k
        .ToLocalChecked();
732
2.52k
  } else {
733
70
    return String::NewExternalTwoByte(isolate, two_byte_resource_)
734
70
        .ToLocalChecked();
735
70
  }
736
2.59k
}
737
738
RAIIIsolateWithoutEntering::RAIIIsolateWithoutEntering(const SnapshotData* data)
739
0
    : allocator_{ArrayBuffer::Allocator::NewDefaultAllocator()} {
740
0
  isolate_ = Isolate::Allocate();
741
0
  CHECK_NOT_NULL(isolate_);
742
0
  per_process::v8_platform.Platform()->RegisterIsolate(isolate_,
743
0
                                                       uv_default_loop());
744
0
  Isolate::CreateParams params;
745
0
  if (data != nullptr) {
746
0
    SnapshotBuilder::InitializeIsolateParams(data, &params);
747
0
  }
748
0
  params.array_buffer_allocator = allocator_.get();
749
0
  params.cpp_heap = v8::CppHeap::Create(per_process::v8_platform.Platform(),
750
0
                                        v8::CppHeapCreateParams{{}})
751
0
                        .release();
752
0
  Isolate::Initialize(isolate_, params);
753
0
}
754
755
0
RAIIIsolateWithoutEntering::~RAIIIsolateWithoutEntering() {
756
0
  per_process::v8_platform.Platform()->DisposeIsolate(isolate_);
757
0
}
758
759
RAIIIsolate::RAIIIsolate(const SnapshotData* data)
760
0
    : isolate_{data}, isolate_scope_{isolate_.get()} {}
761
762
0
RAIIIsolate::~RAIIIsolate() {}
763
764
// Returns a string representation of the input value, including type.
765
// JavaScript implementation is available in lib/internal/errors.js
766
std::string DetermineSpecificErrorType(Environment* env,
767
0
                                       v8::Local<v8::Value> input) {
768
0
  if (input->IsFunction()) {
769
0
    return "function";
770
0
  } else if (input->IsString()) {
771
0
    auto value = Utf8Value(env->isolate(), input).ToString();
772
0
    if (value.size() > 28) {
773
0
      value = value.substr(0, 25) + "...";
774
0
    }
775
0
    if (value.find('\'') == std::string::npos) {
776
0
      return SPrintF("type string ('%s')", value);
777
0
    }
778
779
    // Stringify the input value.
780
0
    Local<String> stringified =
781
0
        v8::JSON::Stringify(env->context(), input).ToLocalChecked();
782
0
    Utf8Value stringified_value(env->isolate(), stringified);
783
0
    return SPrintF("type string (%s)", stringified_value.out());
784
0
  } else if (input->IsObject()) {
785
0
    v8::Local<v8::String> constructor_name =
786
0
        input.As<v8::Object>()->GetConstructorName();
787
0
    Utf8Value name(env->isolate(), constructor_name);
788
0
    return SPrintF("an instance of %s", name.out());
789
0
  } else if (input->IsSymbol()) {
790
0
    v8::MaybeLocal<v8::String> str =
791
0
        input.As<v8::Symbol>()->ToDetailString(env->context());
792
0
    v8::Local<v8::String> js_str;
793
0
    if (!str.ToLocal(&js_str)) {
794
0
      return "Symbol";
795
0
    }
796
0
    Utf8Value name(env->isolate(), js_str);
797
    // Symbol(xxx)
798
0
    return name.out();
799
0
  }
800
801
0
  Utf8Value utf8_value(env->isolate(),
802
0
                       input->ToString(env->context()).ToLocalChecked());
803
804
0
  if (input->IsNumber() || input->IsInt32() || input->IsUint32()) {
805
0
    auto value = input.As<v8::Number>()->Value();
806
0
    if (std::isnan(value)) {
807
0
      return "type number (NaN)";
808
0
    } else if (std::isinf(value)) {
809
0
      return "type number (Infinity)";
810
0
    }
811
0
    return SPrintF("type number (%s)", utf8_value.out());
812
0
  } else if (input->IsBigInt() || input->IsBoolean() || input->IsSymbol()) {
813
0
    Utf8Value type(env->isolate(), input->TypeOf(env->isolate()));
814
0
    return SPrintF("type %s (%s)", type.out(), utf8_value.out());
815
0
  }
816
817
  // For example: null, undefined
818
0
  return utf8_value.ToString();
819
0
}
820
821
v8::Maybe<int32_t> GetValidatedFd(Environment* env,
822
0
                                  v8::Local<v8::Value> input) {
823
0
  if (!input->IsInt32() && !input->IsNumber()) {
824
0
    std::string error_type = node::DetermineSpecificErrorType(env, input);
825
0
    THROW_ERR_INVALID_ARG_TYPE(env,
826
0
                               "The \"fd\" argument must be of type "
827
0
                               "number. Received %s",
828
0
                               error_type.c_str());
829
0
    return v8::Nothing<int32_t>();
830
0
  }
831
832
0
  const double fd = input.As<v8::Number>()->Value();
833
0
  const bool is_out_of_range = fd < 0 || fd > INT32_MAX;
834
835
0
  if (is_out_of_range || !IsSafeJsInt(input)) {
836
0
    Local<String> str;
837
0
    if (!input->ToDetailString(env->context()).ToLocal(&str)) {
838
0
      return v8::Nothing<int32_t>();
839
0
    }
840
0
    Utf8Value utf8_value(env->isolate(), str);
841
0
    if (is_out_of_range && !std::isinf(fd)) {
842
0
      THROW_ERR_OUT_OF_RANGE(env,
843
0
                             "The value of \"fd\" is out of range. "
844
0
                             "It must be >= 0 && <= %s. Received %s",
845
0
                             std::to_string(INT32_MAX),
846
0
                             utf8_value.out());
847
0
    } else {
848
0
      THROW_ERR_OUT_OF_RANGE(
849
0
          env,
850
0
          "The value of \"fd\" is out of range. It must be an integer. "
851
0
          "Received %s",
852
0
          utf8_value.out());
853
0
    }
854
0
    return v8::Nothing<int32_t>();
855
0
  }
856
857
0
  return v8::Just(static_cast<int32_t>(fd));
858
0
}
859
860
v8::Maybe<int> GetValidFileMode(Environment* env,
861
                                v8::Local<v8::Value> input,
862
0
                                uv_fs_type type) {
863
  // Allow only int32 or null/undefined values.
864
0
  if (input->IsNumber()) {
865
    // We cast the input to v8::Number to avoid overflows.
866
0
    auto num = input.As<v8::Number>()->Value();
867
868
    // Handle infinity and NaN values
869
0
    if (std::isinf(num) || std::isnan(num)) {
870
0
      THROW_ERR_OUT_OF_RANGE(env, "mode is out of range");
871
0
      return v8::Nothing<int>();
872
0
    }
873
0
  } else if (!input->IsNullOrUndefined()) {
874
0
    THROW_ERR_INVALID_ARG_TYPE(env, "mode must be int32 or null/undefined");
875
0
    return v8::Nothing<int>();
876
0
  }
877
878
0
  int min = kMinimumAccessMode;
879
0
  int max = kMaximumAccessMode;
880
0
  int def = F_OK;
881
882
0
  CHECK(type == UV_FS_ACCESS || type == UV_FS_COPYFILE);
883
884
0
  if (type == UV_FS_COPYFILE) {
885
0
    min = kMinimumCopyMode;
886
0
    max = kMaximumCopyMode;
887
0
    def = input->IsNullOrUndefined() ? kDefaultCopyMode
888
0
                                     : input.As<v8::Int32>()->Value();
889
0
  }
890
891
0
  if (input->IsNullOrUndefined()) {
892
0
    return v8::Just(def);
893
0
  }
894
895
0
  const int mode = input.As<v8::Int32>()->Value();
896
0
  if (mode < min || mode > max) {
897
0
    THROW_ERR_OUT_OF_RANGE(
898
0
        env, "mode is out of range: >= %d && <= %d", min, max);
899
0
    return v8::Nothing<int>();
900
0
  }
901
902
0
  return v8::Just(mode);
903
0
}
904
905
}  // namespace node