GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_util.cc Lines: 236 262 90.1 %
Date: 2022-10-07 04:22:37 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
144492
static void GetOwnNonIndexProperties(
52
    const FunctionCallbackInfo<Value>& args) {
53
144492
  Environment* env = Environment::GetCurrent(args);
54
144492
  Local<Context> context = env->context();
55
56
144492
  CHECK(args[0]->IsObject());
57
144492
  CHECK(args[1]->IsUint32());
58
59
288984
  Local<Object> object = args[0].As<Object>();
60
61
  Local<Array> properties;
62
63
  PropertyFilter filter =
64
288984
    static_cast<PropertyFilter>(args[1].As<Uint32>()->Value());
65
66
144492
  if (!object->GetPropertyNames(
67
        context, KeyCollectionMode::kOwnOnly,
68
        filter,
69
144492
        IndexFilter::kSkipIndices)
70
144492
          .ToLocal(&properties)) {
71
2
    return;
72
  }
73
288980
  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
1246
static void GetPromiseDetails(const FunctionCallbackInfo<Value>& args) {
99
  // Return undefined if it's not a Promise.
100
1246
  if (!args[0]->IsPromise())
101
1
    return;
102
103
1245
  auto isolate = args.GetIsolate();
104
105
2490
  Local<Promise> promise = args[0].As<Promise>();
106
107
1245
  int state = promise->State();
108
3735
  Local<Value> values[2] = { Integer::New(isolate, state) };
109
1245
  size_t number_of_values = 1;
110
1245
  if (state != Promise::PromiseState::kPending)
111
1041
    values[number_of_values++] = promise->Result();
112
1245
  Local<Array> ret = Array::New(isolate, values, number_of_values);
113
2490
  args.GetReturnValue().Set(ret);
114
}
115
116
276407
static void GetProxyDetails(const FunctionCallbackInfo<Value>& args) {
117
  // Return undefined if it's not a proxy.
118
276407
  if (!args[0]->IsProxy())
119
276291
    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
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
6397
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
6397
  CHECK_LT(index, arraysize(methods));
169
6397
  return (env->*methods[index])();
170
}
171
172
968
static void GetHiddenValue(const FunctionCallbackInfo<Value>& args) {
173
968
  Environment* env = Environment::GetCurrent(args);
174
175
968
  CHECK(args[0]->IsObject());
176
968
  CHECK(args[1]->IsUint32());
177
178
1936
  Local<Object> obj = args[0].As<Object>();
179
1936
  uint32_t index = args[1].As<Uint32>()->Value();
180
968
  Local<Private> private_symbol = IndexToPrivateSymbol(env, index);
181
  Local<Value> ret;
182
1936
  if (obj->GetPrivate(env->context(), private_symbol).ToLocal(&ret))
183
1936
    args.GetReturnValue().Set(ret);
184
968
}
185
186
5429
static void SetHiddenValue(const FunctionCallbackInfo<Value>& args) {
187
5429
  Environment* env = Environment::GetCurrent(args);
188
189
5429
  CHECK(args[0]->IsObject());
190
5429
  CHECK(args[1]->IsUint32());
191
192
10858
  Local<Object> obj = args[0].As<Object>();
193
10858
  uint32_t index = args[1].As<Uint32>()->Value();
194
5429
  Local<Private> private_symbol = IndexToPrivateSymbol(env, index);
195
  bool ret;
196

16287
  if (obj->SetPrivate(env->context(), private_symbol, args[2]).To(&ret))
197
10858
    args.GetReturnValue().Set(ret);
198
5429
}
199
200
9
static void Sleep(const FunctionCallbackInfo<Value>& args) {
201
9
  CHECK(args[0]->IsUint32());
202
18
  uint32_t msec = args[0].As<Uint32>()->Value();
203
9
  uv_sleep(msec);
204
9
}
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
32481
WeakReference::WeakReference(Environment* env,
212
                             Local<Object> object,
213
32481
                             Local<Object> target)
214
32481
    : WeakReference(env, object, target, 0) {}
215
216
32481
WeakReference::WeakReference(Environment* env,
217
                             Local<Object> object,
218
                             Local<Object> target,
219
32481
                             uint64_t reference_count)
220
    : SnapshotableObject(env, object, type_int),
221
32481
      reference_count_(reference_count) {
222
32481
  MakeWeak();
223
32481
  if (!target.IsEmpty()) {
224
32481
    target_.Reset(env->isolate(), target);
225
32481
    if (reference_count_ == 0) {
226
32481
      target_.SetWeak();
227
    }
228
  }
229
32481
}
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
32481
void WeakReference::New(const FunctionCallbackInfo<Value>& args) {
284
32481
  Environment* env = Environment::GetCurrent(args);
285
32481
  CHECK(args.IsConstructCall());
286
32481
  CHECK(args[0]->IsObject());
287
97443
  new WeakReference(env, args.This(), args[0].As<Object>());
288
32481
}
289
290
10923
void WeakReference::Get(const FunctionCallbackInfo<Value>& args) {
291
10923
  WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
292
10923
  Isolate* isolate = args.GetIsolate();
293
10923
  if (!weak_ref->target_.IsEmpty())
294
21844
    args.GetReturnValue().Set(weak_ref->target_.Get(isolate));
295
10923
}
296
297
5466
void WeakReference::IncRef(const FunctionCallbackInfo<Value>& args) {
298
5466
  WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
299
5466
  weak_ref->reference_count_++;
300
5466
  if (weak_ref->target_.IsEmpty()) return;
301
5466
  if (weak_ref->reference_count_ == 1) weak_ref->target_.ClearWeak();
302
}
303
304
5451
void WeakReference::DecRef(const FunctionCallbackInfo<Value>& args) {
305
5451
  WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
306
5451
  CHECK_GE(weak_ref->reference_count_, 1);
307
5451
  weak_ref->reference_count_--;
308
5451
  if (weak_ref->target_.IsEmpty()) return;
309
5451
  if (weak_ref->reference_count_ == 0) weak_ref->target_.SetWeak();
310
}
311
312
8381
static void GuessHandleType(const FunctionCallbackInfo<Value>& args) {
313
8381
  Environment* env = Environment::GetCurrent(args);
314
  int fd;
315
16762
  if (!args[0]->Int32Value(env->context()).To(&fd)) return;
316
8381
  CHECK_GE(fd, 0);
317
318
8381
  uv_handle_type t = uv_guess_handle(fd);
319
8381
  const char* type = nullptr;
320
321

8381
  switch (t) {
322
4
    case UV_TCP:
323
4
      type = "TCP";
324
4
      break;
325
60
    case UV_TTY:
326
60
      type = "TTY";
327
60
      break;
328
6
    case UV_UDP:
329
6
      type = "UDP";
330
6
      break;
331
4885
    case UV_FILE:
332
4885
      type = "FILE";
333
4885
      break;
334
3421
    case UV_NAMED_PIPE:
335
3421
      type = "PIPE";
336
3421
      break;
337
5
    case UV_UNKNOWN_HANDLE:
338
5
      type = "UNKNOWN";
339
5
      break;
340
    default:
341
      ABORT();
342
  }
343
344
16762
  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
5524
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
382
5524
  registry->Register(GetHiddenValue);
383
5524
  registry->Register(SetHiddenValue);
384
5524
  registry->Register(GetPromiseDetails);
385
5524
  registry->Register(GetProxyDetails);
386
5524
  registry->Register(PreviewEntries);
387
5524
  registry->Register(GetOwnNonIndexProperties);
388
5524
  registry->Register(GetConstructorName);
389
5524
  registry->Register(GetExternalValue);
390
5524
  registry->Register(Sleep);
391
5524
  registry->Register(ArrayBufferViewHasBuffer);
392
5524
  registry->Register(WeakReference::New);
393
5524
  registry->Register(WeakReference::Get);
394
5524
  registry->Register(WeakReference::IncRef);
395
5524
  registry->Register(WeakReference::DecRef);
396
5524
  registry->Register(GuessHandleType);
397
5524
  registry->Register(ToUSVString);
398
5524
}
399
400
787
void Initialize(Local<Object> target,
401
                Local<Value> unused,
402
                Local<Context> context,
403
                void* priv) {
404
787
  Environment* env = Environment::GetCurrent(context);
405
787
  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
787
    uint32_t index = 0;
413
22036
    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
3148
  V(kPending);
423
3148
  V(kFulfilled);
424
2361
  V(kRejected);
425
#undef V
426
427
787
  SetMethodNoSideEffect(context, target, "getHiddenValue", GetHiddenValue);
428
787
  SetMethod(context, target, "setHiddenValue", SetHiddenValue);
429
787
  SetMethodNoSideEffect(
430
      context, target, "getPromiseDetails", GetPromiseDetails);
431
787
  SetMethodNoSideEffect(context, target, "getProxyDetails", GetProxyDetails);
432
787
  SetMethodNoSideEffect(context, target, "previewEntries", PreviewEntries);
433
787
  SetMethodNoSideEffect(
434
      context, target, "getOwnNonIndexProperties", GetOwnNonIndexProperties);
435
787
  SetMethodNoSideEffect(
436
      context, target, "getConstructorName", GetConstructorName);
437
787
  SetMethodNoSideEffect(context, target, "getExternalValue", GetExternalValue);
438
787
  SetMethod(context, target, "sleep", Sleep);
439
440
787
  SetMethod(
441
      context, target, "arrayBufferViewHasBuffer", ArrayBufferViewHasBuffer);
442
787
  Local<Object> constants = Object::New(env->isolate());
443
2361
  NODE_DEFINE_CONSTANT(constants, ALL_PROPERTIES);
444
2361
  NODE_DEFINE_CONSTANT(constants, ONLY_WRITABLE);
445
2361
  NODE_DEFINE_CONSTANT(constants, ONLY_ENUMERABLE);
446
2361
  NODE_DEFINE_CONSTANT(constants, ONLY_CONFIGURABLE);
447
2361
  NODE_DEFINE_CONSTANT(constants, SKIP_STRINGS);
448
2361
  NODE_DEFINE_CONSTANT(constants, SKIP_SYMBOLS);
449
787
  target->Set(context,
450
              FIXED_ONE_BYTE_STRING(env->isolate(), "propertyFilter"),
451
1574
              constants).Check();
452
453
  Local<String> should_abort_on_uncaught_toggle =
454
787
      FIXED_ONE_BYTE_STRING(env->isolate(), "shouldAbortOnUncaughtToggle");
455
2361
  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
787
      NewFunctionTemplate(isolate, WeakReference::New);
463
1574
  weak_ref->InstanceTemplate()->SetInternalFieldCount(
464
      WeakReference::kInternalFieldCount);
465
787
  weak_ref->Inherit(BaseObject::GetConstructorTemplate(env));
466
787
  SetProtoMethod(isolate, weak_ref, "get", WeakReference::Get);
467
787
  SetProtoMethod(isolate, weak_ref, "incRef", WeakReference::IncRef);
468
787
  SetProtoMethod(isolate, weak_ref, "decRef", WeakReference::DecRef);
469
787
  SetConstructorFunction(context, target, "WeakReference", weak_ref);
470
471
787
  SetMethod(context, target, "guessHandleType", GuessHandleType);
472
473
787
  SetMethodNoSideEffect(context, target, "toUSVString", ToUSVString);
474
787
}
475
476
}  // namespace util
477
}  // namespace node
478
479
5594
NODE_MODULE_CONTEXT_AWARE_INTERNAL(util, node::util::Initialize)
480
5524
NODE_MODULE_EXTERNAL_REFERENCE(util, node::util::RegisterExternalReferences)