GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_util.cc Lines: 236 262 90.1 %
Date: 2022-09-02 04:23:42 Branches: 90 147 61.2 %

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::ONLY_CONFIGURABLE;
27
using v8::ONLY_ENUMERABLE;
28
using v8::ONLY_WRITABLE;
29
using v8::Private;
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
144178
static void GetOwnNonIndexProperties(
52
    const FunctionCallbackInfo<Value>& args) {
53
144178
  Environment* env = Environment::GetCurrent(args);
54
144178
  Local<Context> context = env->context();
55
56
144178
  CHECK(args[0]->IsObject());
57
144178
  CHECK(args[1]->IsUint32());
58
59
288356
  Local<Object> object = args[0].As<Object>();
60
61
  Local<Array> properties;
62
63
  PropertyFilter filter =
64
288356
    static_cast<PropertyFilter>(args[1].As<Uint32>()->Value());
65
66
144178
  if (!object->GetPropertyNames(
67
        context, KeyCollectionMode::kOwnOnly,
68
        filter,
69
144178
        IndexFilter::kSkipIndices)
70
144178
          .ToLocal(&properties)) {
71
2
    return;
72
  }
73
288352
  args.GetReturnValue().Set(properties);
74
}
75
76
2263
static void GetConstructorName(
77
    const FunctionCallbackInfo<Value>& args) {
78
2263
  CHECK(args[0]->IsObject());
79
80
4526
  Local<Object> object = args[0].As<Object>();
81
2263
  Local<String> name = object->GetConstructorName();
82
83
2263
  args.GetReturnValue().Set(name);
84
2263
}
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
1240
static void GetPromiseDetails(const FunctionCallbackInfo<Value>& args) {
99
  // Return undefined if it's not a Promise.
100
1240
  if (!args[0]->IsPromise())
101
1
    return;
102
103
1239
  auto isolate = args.GetIsolate();
104
105
2478
  Local<Promise> promise = args[0].As<Promise>();
106
107
1239
  int state = promise->State();
108
3717
  Local<Value> values[2] = { Integer::New(isolate, state) };
109
1239
  size_t number_of_values = 1;
110
1239
  if (state != Promise::PromiseState::kPending)
111
1035
    values[number_of_values++] = promise->Result();
112
1239
  Local<Array> ret = Array::New(isolate, values, number_of_values);
113
2478
  args.GetReturnValue().Set(ret);
114
}
115
116
275794
static void GetProxyDetails(const FunctionCallbackInfo<Value>& args) {
117
  // Return undefined if it's not a proxy.
118
275794
  if (!args[0]->IsProxy())
119
275676
    return;
120
121
236
  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

235
  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
72
    Local<Value> ret = proxy->GetTarget();
136
137
144
    args.GetReturnValue().Set(ret);
138
  }
139
}
140
141
124
static void PreviewEntries(const FunctionCallbackInfo<Value>& args) {
142
124
  if (!args[0]->IsObject())
143
    return;
144
145
124
  Environment* env = Environment::GetCurrent(args);
146
  bool is_key_value;
147
  Local<Array> entries;
148
372
  if (!args[0].As<Object>()->PreviewEntries(&is_key_value).ToLocal(&entries))
149
    return;
150
  // Fast path for WeakMap and WeakSet.
151
124
  if (args.Length() == 1)
152
16
    return args.GetReturnValue().Set(entries);
153
154
  Local<Value> ret[] = {
155
    entries,
156
    Boolean::New(env->isolate(), is_key_value)
157
232
  };
158
116
  return args.GetReturnValue().Set(
159
116
      Array::New(env->isolate(), ret, arraysize(ret)));
160
}
161
162
6297
inline Local<Private> IndexToPrivateSymbol(Environment* env, uint32_t index) {
163
#define V(name, _) &Environment::name,
164
  static Local<Private> (Environment::*const methods[])() const = {
165
    PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
166
  };
167
#undef V
168
6297
  CHECK_LT(index, arraysize(methods));
169
6297
  return (env->*methods[index])();
170
}
171
172
953
static void GetHiddenValue(const FunctionCallbackInfo<Value>& args) {
173
953
  Environment* env = Environment::GetCurrent(args);
174
175
953
  CHECK(args[0]->IsObject());
176
953
  CHECK(args[1]->IsUint32());
177
178
1906
  Local<Object> obj = args[0].As<Object>();
179
1906
  uint32_t index = args[1].As<Uint32>()->Value();
180
953
  Local<Private> private_symbol = IndexToPrivateSymbol(env, index);
181
  Local<Value> ret;
182
1906
  if (obj->GetPrivate(env->context(), private_symbol).ToLocal(&ret))
183
1906
    args.GetReturnValue().Set(ret);
184
953
}
185
186
5344
static void SetHiddenValue(const FunctionCallbackInfo<Value>& args) {
187
5344
  Environment* env = Environment::GetCurrent(args);
188
189
5344
  CHECK(args[0]->IsObject());
190
5344
  CHECK(args[1]->IsUint32());
191
192
10688
  Local<Object> obj = args[0].As<Object>();
193
10688
  uint32_t index = args[1].As<Uint32>()->Value();
194
5344
  Local<Private> private_symbol = IndexToPrivateSymbol(env, index);
195
  bool ret;
196

16032
  if (obj->SetPrivate(env->context(), private_symbol, args[2]).To(&ret))
197
10688
    args.GetReturnValue().Set(ret);
198
5344
}
199
200
10
static void Sleep(const FunctionCallbackInfo<Value>& args) {
201
10
  CHECK(args[0]->IsUint32());
202
20
  uint32_t msec = args[0].As<Uint32>()->Value();
203
10
  uv_sleep(msec);
204
10
}
205
206
56
void ArrayBufferViewHasBuffer(const FunctionCallbackInfo<Value>& args) {
207
56
  CHECK(args[0]->IsArrayBufferView());
208

168
  args.GetReturnValue().Set(args[0].As<ArrayBufferView>()->HasBuffer());
209
56
}
210
211
31844
WeakReference::WeakReference(Environment* env,
212
                             Local<Object> object,
213
31844
                             Local<Object> target)
214
31844
    : WeakReference(env, object, target, 0) {}
215
216
31844
WeakReference::WeakReference(Environment* env,
217
                             Local<Object> object,
218
                             Local<Object> target,
219
31844
                             uint64_t reference_count)
220
    : SnapshotableObject(env, object, type_int),
221
31844
      reference_count_(reference_count) {
222
31844
  MakeWeak();
223
31844
  if (!target.IsEmpty()) {
224
31844
    target_.Reset(env->isolate(), target);
225
31844
    if (reference_count_ == 0) {
226
31844
      target_.SetWeak();
227
    }
228
  }
229
31844
}
230
231
bool WeakReference::PrepareForSerialization(Local<Context> context,
232
                                            v8::SnapshotCreator* creator) {
233
  if (target_.IsEmpty()) {
234
    target_index_ = 0;
235
    return true;
236
  }
237
238
  // Users can still hold strong references to target in addition to the
239
  // reference that we manage here, and they could expect that the referenced
240
  // object remains the same as long as that external strong reference
241
  // is alive. Since we have no way to know if there is any other reference
242
  // keeping the target alive, the best we can do to maintain consistency is to
243
  // simply save a reference to the target in the snapshot (effectively making
244
  // it strong) during serialization, and restore it during deserialization.
245
  // If there's no known counted reference from our side, we'll make the
246
  // reference here weak upon deserialization so that it can be GC'ed if users
247
  // do not hold additional references to it.
248
  Local<Object> target = target_.Get(context->GetIsolate());
249
  target_index_ = creator->AddData(context, target);
250
  DCHECK_NE(target_index_, 0);
251
  target_.Reset();
252
  return true;
253
}
254
255
InternalFieldInfoBase* WeakReference::Serialize(int index) {
256
  DCHECK_EQ(index, BaseObject::kEmbedderType);
257
  InternalFieldInfo* info =
258
      InternalFieldInfoBase::New<InternalFieldInfo>(type());
259
  info->target = target_index_;
260
  info->reference_count = reference_count_;
261
  return info;
262
}
263
264
void WeakReference::Deserialize(Local<Context> context,
265
                                Local<Object> holder,
266
                                int index,
267
                                InternalFieldInfoBase* info) {
268
  DCHECK_EQ(index, BaseObject::kEmbedderType);
269
  HandleScope scope(context->GetIsolate());
270
271
  InternalFieldInfo* weak_info = reinterpret_cast<InternalFieldInfo*>(info);
272
  Local<Object> target;
273
  if (weak_info->target != 0) {
274
    target = context->GetDataFromSnapshotOnce<Object>(weak_info->target)
275
                 .ToLocalChecked();
276
  }
277
  new WeakReference(Environment::GetCurrent(context),
278
                    holder,
279
                    target,
280
                    weak_info->reference_count);
281
}
282
283
31844
void WeakReference::New(const FunctionCallbackInfo<Value>& args) {
284
31844
  Environment* env = Environment::GetCurrent(args);
285
31844
  CHECK(args.IsConstructCall());
286
31844
  CHECK(args[0]->IsObject());
287
95532
  new WeakReference(env, args.This(), args[0].As<Object>());
288
31844
}
289
290
10609
void WeakReference::Get(const FunctionCallbackInfo<Value>& args) {
291
10609
  WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
292
10609
  Isolate* isolate = args.GetIsolate();
293
10609
  if (!weak_ref->target_.IsEmpty())
294
21216
    args.GetReturnValue().Set(weak_ref->target_.Get(isolate));
295
10609
}
296
297
5309
void WeakReference::IncRef(const FunctionCallbackInfo<Value>& args) {
298
5309
  WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
299
5309
  weak_ref->reference_count_++;
300
5309
  if (weak_ref->target_.IsEmpty()) return;
301
5309
  if (weak_ref->reference_count_ == 1) weak_ref->target_.ClearWeak();
302
}
303
304
5294
void WeakReference::DecRef(const FunctionCallbackInfo<Value>& args) {
305
5294
  WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
306
5294
  CHECK_GE(weak_ref->reference_count_, 1);
307
5294
  weak_ref->reference_count_--;
308
5294
  if (weak_ref->target_.IsEmpty()) return;
309
5294
  if (weak_ref->reference_count_ == 0) weak_ref->target_.SetWeak();
310
}
311
312
5488
static void GuessHandleType(const FunctionCallbackInfo<Value>& args) {
313
5488
  Environment* env = Environment::GetCurrent(args);
314
  int fd;
315
10976
  if (!args[0]->Int32Value(env->context()).To(&fd)) return;
316
5488
  CHECK_GE(fd, 0);
317
318
5488
  uv_handle_type t = uv_guess_handle(fd);
319
5488
  const char* type = nullptr;
320
321

5488
  switch (t) {
322
4
    case UV_TCP:
323
4
      type = "TCP";
324
4
      break;
325
36
    case UV_TTY:
326
36
      type = "TTY";
327
36
      break;
328
6
    case UV_UDP:
329
6
      type = "UDP";
330
6
      break;
331
2678
    case UV_FILE:
332
2678
      type = "FILE";
333
2678
      break;
334
2759
    case UV_NAMED_PIPE:
335
2759
      type = "PIPE";
336
2759
      break;
337
5
    case UV_UNKNOWN_HANDLE:
338
5
      type = "UNKNOWN";
339
5
      break;
340
    default:
341
      ABORT();
342
  }
343
344
10976
  args.GetReturnValue().Set(OneByteString(env->isolate(), type));
345
}
346
347
17
static void ToUSVString(const FunctionCallbackInfo<Value>& args) {
348
17
  Environment* env = Environment::GetCurrent(args);
349
17
  CHECK_GE(args.Length(), 2);
350
34
  CHECK(args[0]->IsString());
351
17
  CHECK(args[1]->IsNumber());
352
353
17
  TwoByteValue value(env->isolate(), args[0]);
354
355
17
  int64_t start = args[1]->IntegerValue(env->context()).FromJust();
356
17
  CHECK_GE(start, 0);
357
358
49
  for (size_t i = start; i < value.length(); i++) {
359
32
    char16_t c = value[i];
360
32
    if (!IsUnicodeSurrogate(c)) {
361
13
      continue;
362

19
    } else if (IsUnicodeSurrogateTrail(c) || i == value.length() - 1) {
363
16
      value[i] = kUnicodeReplacementCharacter;
364
    } else {
365
3
      char16_t d = value[i + 1];
366
3
      if (IsUnicodeTrail(d)) {
367
        i++;
368
      } else {
369
3
        value[i] = kUnicodeReplacementCharacter;
370
      }
371
    }
372
  }
373
374
51
  args.GetReturnValue().Set(
375
17
      String::NewFromTwoByte(env->isolate(),
376
17
                             *value,
377
                             v8::NewStringType::kNormal,
378
17
                             value.length()).ToLocalChecked());
379
17
}
380
381
5365
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
382
5365
  registry->Register(GetHiddenValue);
383
5365
  registry->Register(SetHiddenValue);
384
5365
  registry->Register(GetPromiseDetails);
385
5365
  registry->Register(GetProxyDetails);
386
5365
  registry->Register(PreviewEntries);
387
5365
  registry->Register(GetOwnNonIndexProperties);
388
5365
  registry->Register(GetConstructorName);
389
5365
  registry->Register(GetExternalValue);
390
5365
  registry->Register(Sleep);
391
5365
  registry->Register(ArrayBufferViewHasBuffer);
392
5365
  registry->Register(WeakReference::New);
393
5365
  registry->Register(WeakReference::Get);
394
5365
  registry->Register(WeakReference::IncRef);
395
5365
  registry->Register(WeakReference::DecRef);
396
5365
  registry->Register(GuessHandleType);
397
5365
  registry->Register(ToUSVString);
398
5365
}
399
400
774
void Initialize(Local<Object> target,
401
                Local<Value> unused,
402
                Local<Context> context,
403
                void* priv) {
404
774
  Environment* env = Environment::GetCurrent(context);
405
774
  Isolate* isolate = env->isolate();
406
407
#define V(name, _)                                                            \
408
  target->Set(context,                                                        \
409
              FIXED_ONE_BYTE_STRING(env->isolate(), #name),                   \
410
              Integer::NewFromUnsigned(env->isolate(), index++)).Check();
411
  {
412
774
    uint32_t index = 0;
413
21672
    PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
414
  }
415
#undef V
416
417
#define V(name)                                                               \
418
  target->Set(context,                                                        \
419
              FIXED_ONE_BYTE_STRING(env->isolate(), #name),                   \
420
              Integer::New(env->isolate(), Promise::PromiseState::name))      \
421
    .FromJust()
422
3096
  V(kPending);
423
3096
  V(kFulfilled);
424
2322
  V(kRejected);
425
#undef V
426
427
774
  SetMethodNoSideEffect(context, target, "getHiddenValue", GetHiddenValue);
428
774
  SetMethod(context, target, "setHiddenValue", SetHiddenValue);
429
774
  SetMethodNoSideEffect(
430
      context, target, "getPromiseDetails", GetPromiseDetails);
431
774
  SetMethodNoSideEffect(context, target, "getProxyDetails", GetProxyDetails);
432
774
  SetMethodNoSideEffect(context, target, "previewEntries", PreviewEntries);
433
774
  SetMethodNoSideEffect(
434
      context, target, "getOwnNonIndexProperties", GetOwnNonIndexProperties);
435
774
  SetMethodNoSideEffect(
436
      context, target, "getConstructorName", GetConstructorName);
437
774
  SetMethodNoSideEffect(context, target, "getExternalValue", GetExternalValue);
438
774
  SetMethod(context, target, "sleep", Sleep);
439
440
774
  SetMethod(
441
      context, target, "arrayBufferViewHasBuffer", ArrayBufferViewHasBuffer);
442
774
  Local<Object> constants = Object::New(env->isolate());
443
2322
  NODE_DEFINE_CONSTANT(constants, ALL_PROPERTIES);
444
2322
  NODE_DEFINE_CONSTANT(constants, ONLY_WRITABLE);
445
2322
  NODE_DEFINE_CONSTANT(constants, ONLY_ENUMERABLE);
446
2322
  NODE_DEFINE_CONSTANT(constants, ONLY_CONFIGURABLE);
447
2322
  NODE_DEFINE_CONSTANT(constants, SKIP_STRINGS);
448
2322
  NODE_DEFINE_CONSTANT(constants, SKIP_SYMBOLS);
449
774
  target->Set(context,
450
              FIXED_ONE_BYTE_STRING(env->isolate(), "propertyFilter"),
451
1548
              constants).Check();
452
453
  Local<String> should_abort_on_uncaught_toggle =
454
774
      FIXED_ONE_BYTE_STRING(env->isolate(), "shouldAbortOnUncaughtToggle");
455
2322
  CHECK(target
456
            ->Set(context,
457
                  should_abort_on_uncaught_toggle,
458
                  env->should_abort_on_uncaught_toggle().GetJSArray())
459
            .FromJust());
460
461
  Local<FunctionTemplate> weak_ref =
462
774
      NewFunctionTemplate(isolate, WeakReference::New);
463
1548
  weak_ref->InstanceTemplate()->SetInternalFieldCount(
464
      WeakReference::kInternalFieldCount);
465
774
  weak_ref->Inherit(BaseObject::GetConstructorTemplate(env));
466
774
  SetProtoMethod(isolate, weak_ref, "get", WeakReference::Get);
467
774
  SetProtoMethod(isolate, weak_ref, "incRef", WeakReference::IncRef);
468
774
  SetProtoMethod(isolate, weak_ref, "decRef", WeakReference::DecRef);
469
774
  SetConstructorFunction(context, target, "WeakReference", weak_ref);
470
471
774
  SetMethod(context, target, "guessHandleType", GuessHandleType);
472
473
774
  SetMethodNoSideEffect(context, target, "toUSVString", ToUSVString);
474
774
}
475
476
}  // namespace util
477
}  // namespace node
478
479
5427
NODE_MODULE_CONTEXT_AWARE_INTERNAL(util, node::util::Initialize)
480
5365
NODE_MODULE_EXTERNAL_REFERENCE(util, node::util::RegisterExternalReferences)