GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_util.cc Lines: 228 255 89.4 %
Date: 2022-12-31 04:22:30 Branches: 82 131 62.6 %

Line Branch Exec Source
1
#include "node_util.h"
2
#include "base_object-inl.h"
3
#include "node_errors.h"
4
#include "node_external_reference.h"
5
#include "util-inl.h"
6
7
namespace node {
8
namespace util {
9
10
using v8::ALL_PROPERTIES;
11
using v8::Array;
12
using v8::ArrayBufferView;
13
using v8::BigInt;
14
using v8::Boolean;
15
using v8::Context;
16
using v8::External;
17
using v8::FunctionCallbackInfo;
18
using v8::FunctionTemplate;
19
using v8::HandleScope;
20
using v8::IndexFilter;
21
using v8::Integer;
22
using v8::Isolate;
23
using v8::KeyCollectionMode;
24
using v8::Local;
25
using v8::Object;
26
using v8::ObjectTemplate;
27
using v8::ONLY_CONFIGURABLE;
28
using v8::ONLY_ENUMERABLE;
29
using v8::ONLY_WRITABLE;
30
using v8::Promise;
31
using v8::PropertyFilter;
32
using v8::Proxy;
33
using v8::SKIP_STRINGS;
34
using v8::SKIP_SYMBOLS;
35
using v8::String;
36
using v8::Uint32;
37
using v8::Value;
38
39
// Used in ToUSVString().
40
constexpr char16_t kUnicodeReplacementCharacter = 0xFFFD;
41
42
// If a UTF-16 character is a low/trailing surrogate.
43
3
CHAR_TEST(16, IsUnicodeTrail, (ch & 0xFC00) == 0xDC00)
44
45
// If a UTF-16 character is a surrogate.
46
32
CHAR_TEST(16, IsUnicodeSurrogate, (ch & 0xF800) == 0xD800)
47
48
// If a UTF-16 surrogate is a low/trailing one.
49
19
CHAR_TEST(16, IsUnicodeSurrogateTrail, (ch & 0x400) != 0)
50
51
144271
static void GetOwnNonIndexProperties(
52
    const FunctionCallbackInfo<Value>& args) {
53
144271
  Environment* env = Environment::GetCurrent(args);
54
144271
  Local<Context> context = env->context();
55
56
144271
  CHECK(args[0]->IsObject());
57
144271
  CHECK(args[1]->IsUint32());
58
59
288542
  Local<Object> object = args[0].As<Object>();
60
61
  Local<Array> properties;
62
63
  PropertyFilter filter =
64
288542
    static_cast<PropertyFilter>(args[1].As<Uint32>()->Value());
65
66
144271
  if (!object->GetPropertyNames(
67
        context, KeyCollectionMode::kOwnOnly,
68
        filter,
69
144271
        IndexFilter::kSkipIndices)
70
144271
          .ToLocal(&properties)) {
71
2
    return;
72
  }
73
288538
  args.GetReturnValue().Set(properties);
74
}
75
76
2279
static void GetConstructorName(
77
    const FunctionCallbackInfo<Value>& args) {
78
2279
  CHECK(args[0]->IsObject());
79
80
4558
  Local<Object> object = args[0].As<Object>();
81
2279
  Local<String> name = object->GetConstructorName();
82
83
2279
  args.GetReturnValue().Set(name);
84
2279
}
85
86
44
static void GetExternalValue(
87
    const FunctionCallbackInfo<Value>& args) {
88
44
  CHECK(args[0]->IsExternal());
89
44
  Isolate* isolate = args.GetIsolate();
90
88
  Local<External> external = args[0].As<External>();
91
92
44
  void* ptr = external->Value();
93
44
  uint64_t value = reinterpret_cast<uint64_t>(ptr);
94
44
  Local<BigInt> ret = BigInt::NewFromUnsigned(isolate, value);
95
44
  args.GetReturnValue().Set(ret);
96
44
}
97
98
1245
static void GetPromiseDetails(const FunctionCallbackInfo<Value>& args) {
99
  // Return undefined if it's not a Promise.
100
1245
  if (!args[0]->IsPromise())
101
1
    return;
102
103
1244
  auto isolate = args.GetIsolate();
104
105
2488
  Local<Promise> promise = args[0].As<Promise>();
106
107
1244
  int state = promise->State();
108
3732
  Local<Value> values[2] = { Integer::New(isolate, state) };
109
1244
  size_t number_of_values = 1;
110
1244
  if (state != Promise::PromiseState::kPending)
111
1041
    values[number_of_values++] = promise->Result();
112
1244
  Local<Array> ret = Array::New(isolate, values, number_of_values);
113
2488
  args.GetReturnValue().Set(ret);
114
}
115
116
276628
static void GetProxyDetails(const FunctionCallbackInfo<Value>& args) {
117
  // Return undefined if it's not a proxy.
118
276628
  if (!args[0]->IsProxy())
119
276512
    return;
120
121
232
  Local<Proxy> proxy = args[0].As<Proxy>();
122
123
  // TODO(BridgeAR): Remove the length check as soon as we prohibit access to
124
  // the util binding layer. It's accessed in the wild and `esm` would break in
125
  // case the check is removed.
126

231
  if (args.Length() == 1 || args[1]->IsTrue()) {
127
    Local<Value> ret[] = {
128
46
      proxy->GetTarget(),
129
46
      proxy->GetHandler()
130
138
    };
131
132
138
    args.GetReturnValue().Set(
133
        Array::New(args.GetIsolate(), ret, arraysize(ret)));
134
  } else {
135
70
    Local<Value> ret = proxy->GetTarget();
136
137
140
    args.GetReturnValue().Set(ret);
138
  }
139
}
140
141
9
static void IsArrayBufferDetached(const FunctionCallbackInfo<Value>& args) {
142
9
  if (args[0]->IsArrayBuffer()) {
143
18
    auto buffer = args[0].As<v8::ArrayBuffer>();
144
9
    args.GetReturnValue().Set(buffer->WasDetached());
145
9
    return;
146
  }
147
  args.GetReturnValue().Set(false);
148
}
149
150
124
static void PreviewEntries(const FunctionCallbackInfo<Value>& args) {
151
124
  if (!args[0]->IsObject())
152
    return;
153
154
124
  Environment* env = Environment::GetCurrent(args);
155
  bool is_key_value;
156
  Local<Array> entries;
157
372
  if (!args[0].As<Object>()->PreviewEntries(&is_key_value).ToLocal(&entries))
158
    return;
159
  // Fast path for WeakMap and WeakSet.
160
124
  if (args.Length() == 1)
161
16
    return args.GetReturnValue().Set(entries);
162
163
  Local<Value> ret[] = {
164
    entries,
165
    Boolean::New(env->isolate(), is_key_value)
166
232
  };
167
116
  return args.GetReturnValue().Set(
168
116
      Array::New(env->isolate(), ret, arraysize(ret)));
169
}
170
171
10
static void Sleep(const FunctionCallbackInfo<Value>& args) {
172
10
  CHECK(args[0]->IsUint32());
173
20
  uint32_t msec = args[0].As<Uint32>()->Value();
174
10
  uv_sleep(msec);
175
10
}
176
177
56
void ArrayBufferViewHasBuffer(const FunctionCallbackInfo<Value>& args) {
178
112
  CHECK(args[0]->IsArrayBufferView());
179

168
  args.GetReturnValue().Set(args[0].As<ArrayBufferView>()->HasBuffer());
180
56
}
181
182
32884
WeakReference::WeakReference(Environment* env,
183
                             Local<Object> object,
184
32884
                             Local<Object> target)
185
32884
    : WeakReference(env, object, target, 0) {}
186
187
32884
WeakReference::WeakReference(Environment* env,
188
                             Local<Object> object,
189
                             Local<Object> target,
190
32884
                             uint64_t reference_count)
191
    : SnapshotableObject(env, object, type_int),
192
32884
      reference_count_(reference_count) {
193
32884
  MakeWeak();
194
32884
  if (!target.IsEmpty()) {
195
32884
    target_.Reset(env->isolate(), target);
196
32884
    if (reference_count_ == 0) {
197
32884
      target_.SetWeak();
198
    }
199
  }
200
32884
}
201
202
bool WeakReference::PrepareForSerialization(Local<Context> context,
203
                                            v8::SnapshotCreator* creator) {
204
  if (target_.IsEmpty()) {
205
    target_index_ = 0;
206
    return true;
207
  }
208
209
  // Users can still hold strong references to target in addition to the
210
  // reference that we manage here, and they could expect that the referenced
211
  // object remains the same as long as that external strong reference
212
  // is alive. Since we have no way to know if there is any other reference
213
  // keeping the target alive, the best we can do to maintain consistency is to
214
  // simply save a reference to the target in the snapshot (effectively making
215
  // it strong) during serialization, and restore it during deserialization.
216
  // If there's no known counted reference from our side, we'll make the
217
  // reference here weak upon deserialization so that it can be GC'ed if users
218
  // do not hold additional references to it.
219
  Local<Object> target = target_.Get(context->GetIsolate());
220
  target_index_ = creator->AddData(context, target);
221
  DCHECK_NE(target_index_, 0);
222
  target_.Reset();
223
  return true;
224
}
225
226
InternalFieldInfoBase* WeakReference::Serialize(int index) {
227
  DCHECK_EQ(index, BaseObject::kEmbedderType);
228
  InternalFieldInfo* info =
229
      InternalFieldInfoBase::New<InternalFieldInfo>(type());
230
  info->target = target_index_;
231
  info->reference_count = reference_count_;
232
  return info;
233
}
234
235
void WeakReference::Deserialize(Local<Context> context,
236
                                Local<Object> holder,
237
                                int index,
238
                                InternalFieldInfoBase* info) {
239
  DCHECK_EQ(index, BaseObject::kEmbedderType);
240
  HandleScope scope(context->GetIsolate());
241
242
  InternalFieldInfo* weak_info = reinterpret_cast<InternalFieldInfo*>(info);
243
  Local<Object> target;
244
  if (weak_info->target != 0) {
245
    target = context->GetDataFromSnapshotOnce<Object>(weak_info->target)
246
                 .ToLocalChecked();
247
  }
248
  new WeakReference(Environment::GetCurrent(context),
249
                    holder,
250
                    target,
251
                    weak_info->reference_count);
252
}
253
254
32884
void WeakReference::New(const FunctionCallbackInfo<Value>& args) {
255
32884
  Environment* env = Environment::GetCurrent(args);
256
32884
  CHECK(args.IsConstructCall());
257
32884
  CHECK(args[0]->IsObject());
258
98652
  new WeakReference(env, args.This(), args[0].As<Object>());
259
32884
}
260
261
10514
void WeakReference::Get(const FunctionCallbackInfo<Value>& args) {
262
10514
  WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
263
10514
  Isolate* isolate = args.GetIsolate();
264
10514
  if (!weak_ref->target_.IsEmpty())
265
21026
    args.GetReturnValue().Set(weak_ref->target_.Get(isolate));
266
10514
}
267
268
1001
void WeakReference::GetRef(const FunctionCallbackInfo<Value>& args) {
269
1001
  WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
270
1001
  Isolate* isolate = args.GetIsolate();
271
3003
  args.GetReturnValue().Set(
272
1001
      v8::Number::New(isolate, weak_ref->reference_count_));
273
1001
}
274
275
5762
void WeakReference::IncRef(const FunctionCallbackInfo<Value>& args) {
276
5762
  WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
277
5762
  weak_ref->reference_count_++;
278
5762
  if (weak_ref->target_.IsEmpty()) return;
279
5762
  if (weak_ref->reference_count_ == 1) weak_ref->target_.ClearWeak();
280
}
281
282
5747
void WeakReference::DecRef(const FunctionCallbackInfo<Value>& args) {
283
5747
  WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
284
5747
  CHECK_GE(weak_ref->reference_count_, 1);
285
5747
  weak_ref->reference_count_--;
286
5747
  if (weak_ref->target_.IsEmpty()) return;
287
5747
  if (weak_ref->reference_count_ == 0) weak_ref->target_.SetWeak();
288
}
289
290
8911
static void GuessHandleType(const FunctionCallbackInfo<Value>& args) {
291
8911
  Environment* env = Environment::GetCurrent(args);
292
  int fd;
293
17822
  if (!args[0]->Int32Value(env->context()).To(&fd)) return;
294
8911
  CHECK_GE(fd, 0);
295
296
8911
  uv_handle_type t = uv_guess_handle(fd);
297
8911
  const char* type = nullptr;
298
299

8911
  switch (t) {
300
4
    case UV_TCP:
301
4
      type = "TCP";
302
4
      break;
303
60
    case UV_TTY:
304
60
      type = "TTY";
305
60
      break;
306
6
    case UV_UDP:
307
6
      type = "UDP";
308
6
      break;
309
4980
    case UV_FILE:
310
4980
      type = "FILE";
311
4980
      break;
312
3856
    case UV_NAMED_PIPE:
313
3856
      type = "PIPE";
314
3856
      break;
315
5
    case UV_UNKNOWN_HANDLE:
316
5
      type = "UNKNOWN";
317
5
      break;
318
    default:
319
      ABORT();
320
  }
321
322
17822
  args.GetReturnValue().Set(OneByteString(env->isolate(), type));
323
}
324
325
17
static void ToUSVString(const FunctionCallbackInfo<Value>& args) {
326
17
  Environment* env = Environment::GetCurrent(args);
327
17
  CHECK_GE(args.Length(), 2);
328
34
  CHECK(args[0]->IsString());
329
17
  CHECK(args[1]->IsNumber());
330
331
17
  TwoByteValue value(env->isolate(), args[0]);
332
333
17
  int64_t start = args[1]->IntegerValue(env->context()).FromJust();
334
17
  CHECK_GE(start, 0);
335
336
49
  for (size_t i = start; i < value.length(); i++) {
337
32
    char16_t c = value[i];
338
32
    if (!IsUnicodeSurrogate(c)) {
339
13
      continue;
340

19
    } else if (IsUnicodeSurrogateTrail(c) || i == value.length() - 1) {
341
16
      value[i] = kUnicodeReplacementCharacter;
342
    } else {
343
3
      char16_t d = value[i + 1];
344
3
      if (IsUnicodeTrail(d)) {
345
        i++;
346
      } else {
347
3
        value[i] = kUnicodeReplacementCharacter;
348
      }
349
    }
350
  }
351
352
51
  args.GetReturnValue().Set(
353
17
      String::NewFromTwoByte(env->isolate(),
354
17
                             *value,
355
                             v8::NewStringType::kNormal,
356
17
                             value.length()).ToLocalChecked());
357
17
}
358
359
5718
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
360
5718
  registry->Register(GetPromiseDetails);
361
5718
  registry->Register(GetProxyDetails);
362
5718
  registry->Register(IsArrayBufferDetached);
363
5718
  registry->Register(PreviewEntries);
364
5718
  registry->Register(GetOwnNonIndexProperties);
365
5718
  registry->Register(GetConstructorName);
366
5718
  registry->Register(GetExternalValue);
367
5718
  registry->Register(Sleep);
368
5718
  registry->Register(ArrayBufferViewHasBuffer);
369
5718
  registry->Register(WeakReference::New);
370
5718
  registry->Register(WeakReference::Get);
371
5718
  registry->Register(WeakReference::GetRef);
372
5718
  registry->Register(WeakReference::IncRef);
373
5718
  registry->Register(WeakReference::DecRef);
374
5718
  registry->Register(GuessHandleType);
375
5718
  registry->Register(ToUSVString);
376
5718
}
377
378
827
void Initialize(Local<Object> target,
379
                Local<Value> unused,
380
                Local<Context> context,
381
                void* priv) {
382
827
  Environment* env = Environment::GetCurrent(context);
383
827
  Isolate* isolate = env->isolate();
384
385
  {
386
827
    Local<ObjectTemplate> tmpl = ObjectTemplate::New(isolate);
387
#define V(PropertyName, _)                                                     \
388
  tmpl->Set(FIXED_ONE_BYTE_STRING(env->isolate(), #PropertyName),              \
389
            env->PropertyName());
390
391
12405
    PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
392
#undef V
393
394
    target
395
827
        ->Set(context,
396
              FIXED_ONE_BYTE_STRING(isolate, "privateSymbols"),
397
2481
              tmpl->NewInstance(context).ToLocalChecked())
398
        .Check();
399
  }
400
401
  {
402
827
    Local<Object> constants = Object::New(isolate);
403
#define V(name)                                                                \
404
  constants                                                                    \
405
      ->Set(context,                                                           \
406
            FIXED_ONE_BYTE_STRING(isolate, #name),                             \
407
            Integer::New(isolate, Promise::PromiseState::name))                \
408
      .Check();
409
410
3308
    V(kPending);
411
3308
    V(kFulfilled);
412
3308
    V(kRejected);
413
#undef V
414
415
#define V(name)                                                                \
416
  constants                                                                    \
417
      ->Set(context,                                                           \
418
            FIXED_ONE_BYTE_STRING(isolate, #name),                             \
419
            Integer::New(isolate, Environment::ExitInfoField::name))           \
420
      .Check();
421
422
3308
    V(kExiting);
423
3308
    V(kExitCode);
424
3308
    V(kHasExitCode);
425
#undef V
426
427
#define V(name)                                                                \
428
  constants                                                                    \
429
      ->Set(context,                                                           \
430
            FIXED_ONE_BYTE_STRING(isolate, #name),                             \
431
            Integer::New(isolate, PropertyFilter::name))                       \
432
      .Check();
433
434
3308
    V(ALL_PROPERTIES);
435
3308
    V(ONLY_WRITABLE);
436
3308
    V(ONLY_ENUMERABLE);
437
3308
    V(ONLY_CONFIGURABLE);
438
3308
    V(SKIP_STRINGS);
439
3308
    V(SKIP_SYMBOLS);
440
#undef V
441
442
1654
    target->Set(context, env->constants_string(), constants).Check();
443
  }
444
445
827
  SetMethodNoSideEffect(
446
      context, target, "getPromiseDetails", GetPromiseDetails);
447
827
  SetMethodNoSideEffect(context, target, "getProxyDetails", GetProxyDetails);
448
827
  SetMethodNoSideEffect(
449
      context, target, "isArrayBufferDetached", IsArrayBufferDetached);
450
827
  SetMethodNoSideEffect(context, target, "previewEntries", PreviewEntries);
451
827
  SetMethodNoSideEffect(
452
      context, target, "getOwnNonIndexProperties", GetOwnNonIndexProperties);
453
827
  SetMethodNoSideEffect(
454
      context, target, "getConstructorName", GetConstructorName);
455
827
  SetMethodNoSideEffect(context, target, "getExternalValue", GetExternalValue);
456
827
  SetMethod(context, target, "sleep", Sleep);
457
458
827
  SetMethod(
459
      context, target, "arrayBufferViewHasBuffer", ArrayBufferViewHasBuffer);
460
461
  Local<String> should_abort_on_uncaught_toggle =
462
827
      FIXED_ONE_BYTE_STRING(env->isolate(), "shouldAbortOnUncaughtToggle");
463
2481
  CHECK(target
464
            ->Set(context,
465
                  should_abort_on_uncaught_toggle,
466
                  env->should_abort_on_uncaught_toggle().GetJSArray())
467
            .FromJust());
468
469
  Local<FunctionTemplate> weak_ref =
470
827
      NewFunctionTemplate(isolate, WeakReference::New);
471
1654
  weak_ref->InstanceTemplate()->SetInternalFieldCount(
472
      WeakReference::kInternalFieldCount);
473
827
  weak_ref->Inherit(BaseObject::GetConstructorTemplate(env));
474
827
  SetProtoMethod(isolate, weak_ref, "get", WeakReference::Get);
475
827
  SetProtoMethod(isolate, weak_ref, "getRef", WeakReference::GetRef);
476
827
  SetProtoMethod(isolate, weak_ref, "incRef", WeakReference::IncRef);
477
827
  SetProtoMethod(isolate, weak_ref, "decRef", WeakReference::DecRef);
478
827
  SetConstructorFunction(context, target, "WeakReference", weak_ref);
479
480
827
  SetMethod(context, target, "guessHandleType", GuessHandleType);
481
482
827
  SetMethodNoSideEffect(context, target, "toUSVString", ToUSVString);
483
827
}
484
485
}  // namespace util
486
}  // namespace node
487
488
5789
NODE_BINDING_CONTEXT_AWARE_INTERNAL(util, node::util::Initialize)
489
5718
NODE_BINDING_EXTERNAL_REFERENCE(util, node::util::RegisterExternalReferences)