GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_util.cc Lines: 238 243 97.9 %
Date: 2022-06-06 04:15:48 Branches: 93 143 65.0 %

Line Branch Exec Source
1
#include "base_object-inl.h"
2
#include "node_errors.h"
3
#include "node_external_reference.h"
4
#include "util-inl.h"
5
6
namespace node {
7
namespace util {
8
9
using v8::ALL_PROPERTIES;
10
using v8::Array;
11
using v8::ArrayBufferView;
12
using v8::BigInt;
13
using v8::Boolean;
14
using v8::Context;
15
using v8::External;
16
using v8::FunctionCallbackInfo;
17
using v8::FunctionTemplate;
18
using v8::Global;
19
using v8::IndexFilter;
20
using v8::Integer;
21
using v8::Isolate;
22
using v8::KeyCollectionMode;
23
using v8::Local;
24
using v8::Object;
25
using v8::ONLY_CONFIGURABLE;
26
using v8::ONLY_ENUMERABLE;
27
using v8::ONLY_WRITABLE;
28
using v8::Private;
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
144285
static void GetOwnNonIndexProperties(
51
    const FunctionCallbackInfo<Value>& args) {
52
144285
  Environment* env = Environment::GetCurrent(args);
53
144285
  Local<Context> context = env->context();
54
55
144285
  CHECK(args[0]->IsObject());
56
144285
  CHECK(args[1]->IsUint32());
57
58
288570
  Local<Object> object = args[0].As<Object>();
59
60
  Local<Array> properties;
61
62
  PropertyFilter filter =
63
288570
    static_cast<PropertyFilter>(args[1].As<Uint32>()->Value());
64
65
144285
  if (!object->GetPropertyNames(
66
        context, KeyCollectionMode::kOwnOnly,
67
        filter,
68
144285
        IndexFilter::kSkipIndices)
69
144285
          .ToLocal(&properties)) {
70
2
    return;
71
  }
72
288566
  args.GetReturnValue().Set(properties);
73
}
74
75
2192
static void GetConstructorName(
76
    const FunctionCallbackInfo<Value>& args) {
77
2192
  CHECK(args[0]->IsObject());
78
79
4384
  Local<Object> object = args[0].As<Object>();
80
2192
  Local<String> name = object->GetConstructorName();
81
82
2192
  args.GetReturnValue().Set(name);
83
2192
}
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
1233
static void GetPromiseDetails(const FunctionCallbackInfo<Value>& args) {
98
  // Return undefined if it's not a Promise.
99
1233
  if (!args[0]->IsPromise())
100
1
    return;
101
102
1232
  auto isolate = args.GetIsolate();
103
104
2464
  Local<Promise> promise = args[0].As<Promise>();
105
106
1232
  int state = promise->State();
107
3696
  Local<Value> values[2] = { Integer::New(isolate, state) };
108
1232
  size_t number_of_values = 1;
109
1232
  if (state != Promise::PromiseState::kPending)
110
1028
    values[number_of_values++] = promise->Result();
111
1232
  Local<Array> ret = Array::New(isolate, values, number_of_values);
112
2464
  args.GetReturnValue().Set(ret);
113
}
114
115
274421
static void GetProxyDetails(const FunctionCallbackInfo<Value>& args) {
116
  // Return undefined if it's not a proxy.
117
274421
  if (!args[0]->IsProxy())
118
274304
    return;
119
120
234
  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

233
  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
71
    Local<Value> ret = proxy->GetTarget();
135
136
142
    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
4972
inline Local<Private> IndexToPrivateSymbol(Environment* env, uint32_t index) {
162
#define V(name, _) &Environment::name,
163
  static Local<Private> (Environment::*const methods[])() const = {
164
    PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
165
  };
166
#undef V
167
4972
  CHECK_LT(index, arraysize(methods));
168
4972
  return (env->*methods[index])();
169
}
170
171
179
static void GetHiddenValue(const FunctionCallbackInfo<Value>& args) {
172
179
  Environment* env = Environment::GetCurrent(args);
173
174
179
  CHECK(args[0]->IsObject());
175
179
  CHECK(args[1]->IsUint32());
176
177
358
  Local<Object> obj = args[0].As<Object>();
178
537
  uint32_t index = args[1].As<Uint32>()->Value();
179
179
  Local<Private> private_symbol = IndexToPrivateSymbol(env, index);
180
  Local<Value> ret;
181
358
  if (obj->GetPrivate(env->context(), private_symbol).ToLocal(&ret))
182
358
    args.GetReturnValue().Set(ret);
183
179
}
184
185
4793
static void SetHiddenValue(const FunctionCallbackInfo<Value>& args) {
186
4793
  Environment* env = Environment::GetCurrent(args);
187
188
4793
  CHECK(args[0]->IsObject());
189
4793
  CHECK(args[1]->IsUint32());
190
191
9586
  Local<Object> obj = args[0].As<Object>();
192
9586
  uint32_t index = args[1].As<Uint32>()->Value();
193
4793
  Local<Private> private_symbol = IndexToPrivateSymbol(env, index);
194
  bool ret;
195

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

168
  args.GetReturnValue().Set(args[0].As<ArrayBufferView>()->HasBuffer());
208
56
}
209
210
class WeakReference : public BaseObject {
211
 public:
212
2517
  WeakReference(Environment* env, Local<Object> object, Local<Object> target)
213
2517
    : BaseObject(env, object) {
214
2517
    MakeWeak();
215
2517
    target_.Reset(env->isolate(), target);
216
2517
    target_.SetWeak();
217
2517
  }
218
219
2517
  static void New(const FunctionCallbackInfo<Value>& args) {
220
2517
    Environment* env = Environment::GetCurrent(args);
221
2517
    CHECK(args.IsConstructCall());
222
2517
    CHECK(args[0]->IsObject());
223
7551
    new WeakReference(env, args.This(), args[0].As<Object>());
224
2517
  }
225
226
8511
  static void Get(const FunctionCallbackInfo<Value>& args) {
227
8511
    WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
228
8511
    Isolate* isolate = args.GetIsolate();
229
8511
    if (!weak_ref->target_.IsEmpty())
230
17020
      args.GetReturnValue().Set(weak_ref->target_.Get(isolate));
231
8511
  }
232
233
4254
  static void IncRef(const FunctionCallbackInfo<Value>& args) {
234
4254
    WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
235
4254
    weak_ref->reference_count_++;
236
4254
    if (weak_ref->target_.IsEmpty()) return;
237
4254
    if (weak_ref->reference_count_ == 1) weak_ref->target_.ClearWeak();
238
  }
239
240
4251
  static void DecRef(const FunctionCallbackInfo<Value>& args) {
241
4251
    WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
242
4251
    CHECK_GE(weak_ref->reference_count_, 1);
243
4251
    weak_ref->reference_count_--;
244
4251
    if (weak_ref->target_.IsEmpty()) return;
245
4251
    if (weak_ref->reference_count_ == 0) weak_ref->target_.SetWeak();
246
  }
247
248
4
  SET_MEMORY_INFO_NAME(WeakReference)
249
4
  SET_SELF_SIZE(WeakReference)
250
4
  SET_NO_MEMORY_INFO()
251
252
 private:
253
  Global<Object> target_;
254
  uint64_t reference_count_ = 0;
255
};
256
257
5319
static void GuessHandleType(const FunctionCallbackInfo<Value>& args) {
258
5319
  Environment* env = Environment::GetCurrent(args);
259
  int fd;
260
10638
  if (!args[0]->Int32Value(env->context()).To(&fd)) return;
261
5319
  CHECK_GE(fd, 0);
262
263
5319
  uv_handle_type t = uv_guess_handle(fd);
264
5319
  const char* type = nullptr;
265
266

5319
  switch (t) {
267
4
    case UV_TCP:
268
4
      type = "TCP";
269
4
      break;
270
36
    case UV_TTY:
271
36
      type = "TTY";
272
36
      break;
273
6
    case UV_UDP:
274
6
      type = "UDP";
275
6
      break;
276
2511
    case UV_FILE:
277
2511
      type = "FILE";
278
2511
      break;
279
2757
    case UV_NAMED_PIPE:
280
2757
      type = "PIPE";
281
2757
      break;
282
5
    case UV_UNKNOWN_HANDLE:
283
5
      type = "UNKNOWN";
284
5
      break;
285
    default:
286
      ABORT();
287
  }
288
289
10638
  args.GetReturnValue().Set(OneByteString(env->isolate(), type));
290
}
291
292
10
static void IsConstructor(const FunctionCallbackInfo<Value>& args) {
293
10
  CHECK(args[0]->IsFunction());
294

30
  args.GetReturnValue().Set(args[0].As<v8::Function>()->IsConstructor());
295
10
}
296
297
17
static void ToUSVString(const FunctionCallbackInfo<Value>& args) {
298
17
  Environment* env = Environment::GetCurrent(args);
299
17
  CHECK_GE(args.Length(), 2);
300
34
  CHECK(args[0]->IsString());
301
17
  CHECK(args[1]->IsNumber());
302
303
17
  TwoByteValue value(env->isolate(), args[0]);
304
305
17
  int64_t start = args[1]->IntegerValue(env->context()).FromJust();
306
17
  CHECK_GE(start, 0);
307
308
49
  for (size_t i = start; i < value.length(); i++) {
309
32
    char16_t c = value[i];
310
32
    if (!IsUnicodeSurrogate(c)) {
311
13
      continue;
312

19
    } else if (IsUnicodeSurrogateTrail(c) || i == value.length() - 1) {
313
16
      value[i] = kUnicodeReplacementCharacter;
314
    } else {
315
3
      char16_t d = value[i + 1];
316
3
      if (IsUnicodeTrail(d)) {
317
        i++;
318
      } else {
319
3
        value[i] = kUnicodeReplacementCharacter;
320
      }
321
    }
322
  }
323
324
51
  args.GetReturnValue().Set(
325
17
      String::NewFromTwoByte(env->isolate(),
326
17
                             *value,
327
                             v8::NewStringType::kNormal,
328
17
                             value.length()).ToLocalChecked());
329
17
}
330
331
5206
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
332
5206
  registry->Register(GetHiddenValue);
333
5206
  registry->Register(SetHiddenValue);
334
5206
  registry->Register(GetPromiseDetails);
335
5206
  registry->Register(GetProxyDetails);
336
5206
  registry->Register(PreviewEntries);
337
5206
  registry->Register(GetOwnNonIndexProperties);
338
5206
  registry->Register(GetConstructorName);
339
5206
  registry->Register(GetExternalValue);
340
5206
  registry->Register(Sleep);
341
5206
  registry->Register(ArrayBufferViewHasBuffer);
342
5206
  registry->Register(WeakReference::New);
343
5206
  registry->Register(WeakReference::Get);
344
5206
  registry->Register(WeakReference::IncRef);
345
5206
  registry->Register(WeakReference::DecRef);
346
5206
  registry->Register(GuessHandleType);
347
5206
  registry->Register(IsConstructor);
348
5206
  registry->Register(ToUSVString);
349
5206
}
350
351
854
void Initialize(Local<Object> target,
352
                Local<Value> unused,
353
                Local<Context> context,
354
                void* priv) {
355
854
  Environment* env = Environment::GetCurrent(context);
356
357
#define V(name, _)                                                            \
358
  target->Set(context,                                                        \
359
              FIXED_ONE_BYTE_STRING(env->isolate(), #name),                   \
360
              Integer::NewFromUnsigned(env->isolate(), index++)).Check();
361
  {
362
854
    uint32_t index = 0;
363
21350
    PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
364
  }
365
#undef V
366
367
#define V(name)                                                               \
368
  target->Set(context,                                                        \
369
              FIXED_ONE_BYTE_STRING(env->isolate(), #name),                   \
370
              Integer::New(env->isolate(), Promise::PromiseState::name))      \
371
    .FromJust()
372
3416
  V(kPending);
373
3416
  V(kFulfilled);
374
2562
  V(kRejected);
375
#undef V
376
377
854
  env->SetMethodNoSideEffect(target, "getHiddenValue", GetHiddenValue);
378
854
  env->SetMethod(target, "setHiddenValue", SetHiddenValue);
379
854
  env->SetMethodNoSideEffect(target, "getPromiseDetails", GetPromiseDetails);
380
854
  env->SetMethodNoSideEffect(target, "getProxyDetails", GetProxyDetails);
381
854
  env->SetMethodNoSideEffect(target, "previewEntries", PreviewEntries);
382
854
  env->SetMethodNoSideEffect(target, "getOwnNonIndexProperties",
383
                                     GetOwnNonIndexProperties);
384
854
  env->SetMethodNoSideEffect(target, "getConstructorName", GetConstructorName);
385
854
  env->SetMethodNoSideEffect(target, "getExternalValue", GetExternalValue);
386
854
  env->SetMethod(target, "sleep", Sleep);
387
854
  env->SetMethodNoSideEffect(target, "isConstructor", IsConstructor);
388
389
854
  env->SetMethod(target, "arrayBufferViewHasBuffer", ArrayBufferViewHasBuffer);
390
854
  Local<Object> constants = Object::New(env->isolate());
391
2562
  NODE_DEFINE_CONSTANT(constants, ALL_PROPERTIES);
392
2562
  NODE_DEFINE_CONSTANT(constants, ONLY_WRITABLE);
393
2562
  NODE_DEFINE_CONSTANT(constants, ONLY_ENUMERABLE);
394
2562
  NODE_DEFINE_CONSTANT(constants, ONLY_CONFIGURABLE);
395
2562
  NODE_DEFINE_CONSTANT(constants, SKIP_STRINGS);
396
2562
  NODE_DEFINE_CONSTANT(constants, SKIP_SYMBOLS);
397
854
  target->Set(context,
398
              FIXED_ONE_BYTE_STRING(env->isolate(), "propertyFilter"),
399
1708
              constants).Check();
400
401
  Local<String> should_abort_on_uncaught_toggle =
402
854
      FIXED_ONE_BYTE_STRING(env->isolate(), "shouldAbortOnUncaughtToggle");
403
2562
  CHECK(target
404
            ->Set(env->context(),
405
                  should_abort_on_uncaught_toggle,
406
                  env->should_abort_on_uncaught_toggle().GetJSArray())
407
            .FromJust());
408
409
  Local<FunctionTemplate> weak_ref =
410
854
      env->NewFunctionTemplate(WeakReference::New);
411
1708
  weak_ref->InstanceTemplate()->SetInternalFieldCount(
412
      WeakReference::kInternalFieldCount);
413
854
  weak_ref->Inherit(BaseObject::GetConstructorTemplate(env));
414
854
  env->SetProtoMethod(weak_ref, "get", WeakReference::Get);
415
854
  env->SetProtoMethod(weak_ref, "incRef", WeakReference::IncRef);
416
854
  env->SetProtoMethod(weak_ref, "decRef", WeakReference::DecRef);
417
854
  env->SetConstructorFunction(target, "WeakReference", weak_ref);
418
419
854
  env->SetMethod(target, "guessHandleType", GuessHandleType);
420
421
854
  env->SetMethodNoSideEffect(target, "toUSVString", ToUSVString);
422
854
}
423
424
}  // namespace util
425
}  // namespace node
426
427
5274
NODE_MODULE_CONTEXT_AWARE_INTERNAL(util, node::util::Initialize)
428
5206
NODE_MODULE_EXTERNAL_REFERENCE(util, node::util::RegisterExternalReferences)