GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_util.cc Lines: 214 240 89.2 %
Date: 2022-11-20 04:28:36 Branches: 78 123 63.4 %

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::Promise;
30
using v8::PropertyFilter;
31
using v8::Proxy;
32
using v8::SKIP_STRINGS;
33
using v8::SKIP_SYMBOLS;
34
using v8::String;
35
using v8::Uint32;
36
using v8::Value;
37
38
// Used in ToUSVString().
39
constexpr char16_t kUnicodeReplacementCharacter = 0xFFFD;
40
41
// If a UTF-16 character is a low/trailing surrogate.
42
3
CHAR_TEST(16, IsUnicodeTrail, (ch & 0xFC00) == 0xDC00)
43
44
// If a UTF-16 character is a surrogate.
45
32
CHAR_TEST(16, IsUnicodeSurrogate, (ch & 0xF800) == 0xD800)
46
47
// If a UTF-16 surrogate is a low/trailing one.
48
19
CHAR_TEST(16, IsUnicodeSurrogateTrail, (ch & 0x400) != 0)
49
50
144077
static void GetOwnNonIndexProperties(
51
    const FunctionCallbackInfo<Value>& args) {
52
144077
  Environment* env = Environment::GetCurrent(args);
53
144077
  Local<Context> context = env->context();
54
55
144077
  CHECK(args[0]->IsObject());
56
144077
  CHECK(args[1]->IsUint32());
57
58
288154
  Local<Object> object = args[0].As<Object>();
59
60
  Local<Array> properties;
61
62
  PropertyFilter filter =
63
288154
    static_cast<PropertyFilter>(args[1].As<Uint32>()->Value());
64
65
144077
  if (!object->GetPropertyNames(
66
        context, KeyCollectionMode::kOwnOnly,
67
        filter,
68
144077
        IndexFilter::kSkipIndices)
69
144077
          .ToLocal(&properties)) {
70
2
    return;
71
  }
72
288150
  args.GetReturnValue().Set(properties);
73
}
74
75
2276
static void GetConstructorName(
76
    const FunctionCallbackInfo<Value>& args) {
77
2276
  CHECK(args[0]->IsObject());
78
79
4552
  Local<Object> object = args[0].As<Object>();
80
2276
  Local<String> name = object->GetConstructorName();
81
82
2276
  args.GetReturnValue().Set(name);
83
2276
}
84
85
44
static void GetExternalValue(
86
    const FunctionCallbackInfo<Value>& args) {
87
44
  CHECK(args[0]->IsExternal());
88
44
  Isolate* isolate = args.GetIsolate();
89
88
  Local<External> external = args[0].As<External>();
90
91
44
  void* ptr = external->Value();
92
44
  uint64_t value = reinterpret_cast<uint64_t>(ptr);
93
44
  Local<BigInt> ret = BigInt::NewFromUnsigned(isolate, value);
94
44
  args.GetReturnValue().Set(ret);
95
44
}
96
97
1245
static void GetPromiseDetails(const FunctionCallbackInfo<Value>& args) {
98
  // Return undefined if it's not a Promise.
99
1245
  if (!args[0]->IsPromise())
100
1
    return;
101
102
1244
  auto isolate = args.GetIsolate();
103
104
2488
  Local<Promise> promise = args[0].As<Promise>();
105
106
1244
  int state = promise->State();
107
3732
  Local<Value> values[2] = { Integer::New(isolate, state) };
108
1244
  size_t number_of_values = 1;
109
1244
  if (state != Promise::PromiseState::kPending)
110
1041
    values[number_of_values++] = promise->Result();
111
1244
  Local<Array> ret = Array::New(isolate, values, number_of_values);
112
2488
  args.GetReturnValue().Set(ret);
113
}
114
115
276381
static void GetProxyDetails(const FunctionCallbackInfo<Value>& args) {
116
  // Return undefined if it's not a proxy.
117
276381
  if (!args[0]->IsProxy())
118
276265
    return;
119
120
232
  Local<Proxy> proxy = args[0].As<Proxy>();
121
122
  // TODO(BridgeAR): Remove the length check as soon as we prohibit access to
123
  // the util binding layer. It's accessed in the wild and `esm` would break in
124
  // case the check is removed.
125

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

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

8569
  switch (t) {
283
4
    case UV_TCP:
284
4
      type = "TCP";
285
4
      break;
286
60
    case UV_TTY:
287
60
      type = "TTY";
288
60
      break;
289
6
    case UV_UDP:
290
6
      type = "UDP";
291
6
      break;
292
4934
    case UV_FILE:
293
4934
      type = "FILE";
294
4934
      break;
295
3560
    case UV_NAMED_PIPE:
296
3560
      type = "PIPE";
297
3560
      break;
298
5
    case UV_UNKNOWN_HANDLE:
299
5
      type = "UNKNOWN";
300
5
      break;
301
    default:
302
      ABORT();
303
  }
304
305
17138
  args.GetReturnValue().Set(OneByteString(env->isolate(), type));
306
}
307
308
17
static void ToUSVString(const FunctionCallbackInfo<Value>& args) {
309
17
  Environment* env = Environment::GetCurrent(args);
310
17
  CHECK_GE(args.Length(), 2);
311
34
  CHECK(args[0]->IsString());
312
17
  CHECK(args[1]->IsNumber());
313
314
17
  TwoByteValue value(env->isolate(), args[0]);
315
316
17
  int64_t start = args[1]->IntegerValue(env->context()).FromJust();
317
17
  CHECK_GE(start, 0);
318
319
49
  for (size_t i = start; i < value.length(); i++) {
320
32
    char16_t c = value[i];
321
32
    if (!IsUnicodeSurrogate(c)) {
322
13
      continue;
323

19
    } else if (IsUnicodeSurrogateTrail(c) || i == value.length() - 1) {
324
16
      value[i] = kUnicodeReplacementCharacter;
325
    } else {
326
3
      char16_t d = value[i + 1];
327
3
      if (IsUnicodeTrail(d)) {
328
        i++;
329
      } else {
330
3
        value[i] = kUnicodeReplacementCharacter;
331
      }
332
    }
333
  }
334
335
51
  args.GetReturnValue().Set(
336
17
      String::NewFromTwoByte(env->isolate(),
337
17
                             *value,
338
                             v8::NewStringType::kNormal,
339
17
                             value.length()).ToLocalChecked());
340
17
}
341
342
5619
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
343
5619
  registry->Register(GetPromiseDetails);
344
5619
  registry->Register(GetProxyDetails);
345
5619
  registry->Register(PreviewEntries);
346
5619
  registry->Register(GetOwnNonIndexProperties);
347
5619
  registry->Register(GetConstructorName);
348
5619
  registry->Register(GetExternalValue);
349
5619
  registry->Register(Sleep);
350
5619
  registry->Register(ArrayBufferViewHasBuffer);
351
5619
  registry->Register(WeakReference::New);
352
5619
  registry->Register(WeakReference::Get);
353
5619
  registry->Register(WeakReference::IncRef);
354
5619
  registry->Register(WeakReference::DecRef);
355
5619
  registry->Register(GuessHandleType);
356
5619
  registry->Register(ToUSVString);
357
5619
}
358
359
792
void Initialize(Local<Object> target,
360
                Local<Value> unused,
361
                Local<Context> context,
362
                void* priv) {
363
792
  Environment* env = Environment::GetCurrent(context);
364
792
  Isolate* isolate = env->isolate();
365
366
  {
367
792
    Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
368
#define V(PropertyName, _)                                                     \
369
  tmpl->Set(FIXED_ONE_BYTE_STRING(env->isolate(), #PropertyName),              \
370
            env->PropertyName());
371
372
11880
    PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
373
#undef V
374
375
    target
376
792
        ->Set(context,
377
              FIXED_ONE_BYTE_STRING(isolate, "privateSymbols"),
378
3168
              tmpl->NewInstance(context).ToLocalChecked())
379
        .Check();
380
  }
381
382
#define V(name)                                                               \
383
  target->Set(context,                                                        \
384
              FIXED_ONE_BYTE_STRING(env->isolate(), #name),                   \
385
              Integer::New(env->isolate(), Promise::PromiseState::name))      \
386
    .FromJust()
387
3168
  V(kPending);
388
3168
  V(kFulfilled);
389
3168
  V(kRejected);
390
#undef V
391
392
#define V(name)                                                                \
393
  target                                                                       \
394
      ->Set(context,                                                           \
395
            FIXED_ONE_BYTE_STRING(env->isolate(), #name),                      \
396
            Integer::New(env->isolate(), Environment::ExitInfoField::name))    \
397
      .FromJust()
398
3168
  V(kExiting);
399
3168
  V(kExitCode);
400
2376
  V(kHasExitCode);
401
#undef V
402
403
792
  SetMethodNoSideEffect(
404
      context, target, "getPromiseDetails", GetPromiseDetails);
405
792
  SetMethodNoSideEffect(context, target, "getProxyDetails", GetProxyDetails);
406
792
  SetMethodNoSideEffect(context, target, "previewEntries", PreviewEntries);
407
792
  SetMethodNoSideEffect(
408
      context, target, "getOwnNonIndexProperties", GetOwnNonIndexProperties);
409
792
  SetMethodNoSideEffect(
410
      context, target, "getConstructorName", GetConstructorName);
411
792
  SetMethodNoSideEffect(context, target, "getExternalValue", GetExternalValue);
412
792
  SetMethod(context, target, "sleep", Sleep);
413
414
792
  SetMethod(
415
      context, target, "arrayBufferViewHasBuffer", ArrayBufferViewHasBuffer);
416
792
  Local<Object> constants = Object::New(env->isolate());
417
2376
  NODE_DEFINE_CONSTANT(constants, ALL_PROPERTIES);
418
2376
  NODE_DEFINE_CONSTANT(constants, ONLY_WRITABLE);
419
2376
  NODE_DEFINE_CONSTANT(constants, ONLY_ENUMERABLE);
420
2376
  NODE_DEFINE_CONSTANT(constants, ONLY_CONFIGURABLE);
421
2376
  NODE_DEFINE_CONSTANT(constants, SKIP_STRINGS);
422
2376
  NODE_DEFINE_CONSTANT(constants, SKIP_SYMBOLS);
423
792
  target->Set(context,
424
              FIXED_ONE_BYTE_STRING(env->isolate(), "propertyFilter"),
425
1584
              constants).Check();
426
427
  Local<String> should_abort_on_uncaught_toggle =
428
792
      FIXED_ONE_BYTE_STRING(env->isolate(), "shouldAbortOnUncaughtToggle");
429
2376
  CHECK(target
430
            ->Set(context,
431
                  should_abort_on_uncaught_toggle,
432
                  env->should_abort_on_uncaught_toggle().GetJSArray())
433
            .FromJust());
434
435
  Local<FunctionTemplate> weak_ref =
436
792
      NewFunctionTemplate(isolate, WeakReference::New);
437
1584
  weak_ref->InstanceTemplate()->SetInternalFieldCount(
438
      WeakReference::kInternalFieldCount);
439
792
  weak_ref->Inherit(BaseObject::GetConstructorTemplate(env));
440
792
  SetProtoMethod(isolate, weak_ref, "get", WeakReference::Get);
441
792
  SetProtoMethod(isolate, weak_ref, "incRef", WeakReference::IncRef);
442
792
  SetProtoMethod(isolate, weak_ref, "decRef", WeakReference::DecRef);
443
792
  SetConstructorFunction(context, target, "WeakReference", weak_ref);
444
445
792
  SetMethod(context, target, "guessHandleType", GuessHandleType);
446
447
792
  SetMethodNoSideEffect(context, target, "toUSVString", ToUSVString);
448
792
}
449
450
}  // namespace util
451
}  // namespace node
452
453
5690
NODE_MODULE_CONTEXT_AWARE_INTERNAL(util, node::util::Initialize)
454
5619
NODE_MODULE_EXTERNAL_REFERENCE(util, node::util::RegisterExternalReferences)