1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #include "util.h"  // NOLINT(build/include_inline)
23 #include "util-inl.h"
24 
25 #include "debug_utils-inl.h"
26 #include "env-inl.h"
27 #include "node_buffer.h"
28 #include "node_errors.h"
29 #include "node_internals.h"
30 #include "node_util.h"
31 #include "string_bytes.h"
32 #include "uv.h"
33 #include "init_param.h"
34 
35 #ifdef _WIN32
36 #include <io.h>  // _S_IREAD _S_IWRITE
37 #include <time.h>
38 #ifndef S_IRUSR
39 #define S_IRUSR _S_IREAD
40 #endif  // S_IRUSR
41 #ifndef S_IWUSR
42 #define S_IWUSR _S_IWRITE
43 #endif  // S_IWUSR
44 #else
45 #include <sys/time.h>
46 #include <sys/types.h>
47 #endif
48 
49 #include <atomic>
50 #include <cstdio>
51 #include <cstring>
52 #include <iomanip>
53 #include <sstream>
54 
55 #define ARGBUFFSIZE 32
56 
57 static std::atomic_int seq = {0};  // Sequence number for diagnostic filenames.
58 
59 namespace node {
60 
61 using v8::ArrayBufferView;
62 using v8::Isolate;
63 using v8::Local;
64 using v8::String;
65 using v8::Value;
66 
ReadSystemXpmState()67 bool ReadSystemXpmState() {
68   char buffer[ARGBUFFSIZE] = { 0 };
69   uint32_t buffSize = sizeof(buffer);
70 
71   if (SystemGetParameter("ohos.boot.advsecmode.state", buffer, &buffSize) == 0 && strcmp(buffer, "0") != 0) {
72     return true;
73   }
74   return false;
75 }
76 
77 template <typename T>
MakeUtf8String(Isolate* isolate, Local<Value> value, MaybeStackBuffer<T>* target)78 static void MakeUtf8String(Isolate* isolate,
79                            Local<Value> value,
80                            MaybeStackBuffer<T>* target) {
81   Local<String> string;
82   if (!value->ToString(isolate->GetCurrentContext()).ToLocal(&string)) return;
83 
84   size_t storage;
85   if (!StringBytes::StorageSize(isolate, string, UTF8).To(&storage)) return;
86   storage += 1;
87   target->AllocateSufficientStorage(storage);
88   const int flags =
89       String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8;
90   const int length =
91       string->WriteUtf8(isolate, target->out(), storage, nullptr, flags);
92   target->SetLengthAndZeroTerminate(length);
93 }
94 
Utf8Value(Isolate* isolate, Local<Value> value)95 Utf8Value::Utf8Value(Isolate* isolate, Local<Value> value) {
96   if (value.IsEmpty())
97     return;
98 
99   MakeUtf8String(isolate, value, this);
100 }
101 
102 
TwoByteValue(Isolate* isolate, Local<Value> value)103 TwoByteValue::TwoByteValue(Isolate* isolate, Local<Value> value) {
104   if (value.IsEmpty()) {
105     return;
106   }
107 
108   Local<String> string;
109   if (!value->ToString(isolate->GetCurrentContext()).ToLocal(&string)) return;
110 
111   // Allocate enough space to include the null terminator
112   const size_t storage = string->Length() + 1;
113   AllocateSufficientStorage(storage);
114 
115   const int flags = String::NO_NULL_TERMINATION;
116   const int length = string->Write(isolate, out(), 0, storage, flags);
117   SetLengthAndZeroTerminate(length);
118 }
119 
BufferValue(Isolate* isolate, Local<Value> value)120 BufferValue::BufferValue(Isolate* isolate, Local<Value> value) {
121   // Slightly different take on Utf8Value. If value is a String,
122   // it will return a Utf8 encoded string. If value is a Buffer,
123   // it will copy the data out of the Buffer as is.
124   if (value.IsEmpty()) {
125     // Dereferencing this object will return nullptr.
126     Invalidate();
127     return;
128   }
129 
130   if (value->IsString()) {
131     MakeUtf8String(isolate, value, this);
132   } else if (value->IsArrayBufferView()) {
133     const size_t len = value.As<ArrayBufferView>()->ByteLength();
134     // Leave place for the terminating '\0' byte.
135     AllocateSufficientStorage(len + 1);
136     value.As<ArrayBufferView>()->CopyContents(out(), len);
137     SetLengthAndZeroTerminate(len);
138   } else {
139     Invalidate();
140   }
141 }
142 
LowMemoryNotification()143 void LowMemoryNotification() {
144   if (per_process::v8_initialized) {
145     auto isolate = Isolate::TryGetCurrent();
146     if (isolate != nullptr) {
147       isolate->LowMemoryNotification();
148     }
149   }
150 }
151 
GetProcessTitle(const char* default_title)152 std::string GetProcessTitle(const char* default_title) {
153   std::string buf(16, '\0');
154 
155   for (;;) {
156     const int rc = uv_get_process_title(buf.data(), buf.size());
157 
158     if (rc == 0)
159       break;
160 
161     // If uv_setup_args() was not called, `uv_get_process_title()` will always
162     // return `UV_ENOBUFS`, no matter the input size. Guard against a possible
163     // infinite loop by limiting the buffer size.
164     if (rc != UV_ENOBUFS || buf.size() >= 1024 * 1024)
165       return default_title;
166 
167     buf.resize(2 * buf.size());
168   }
169 
170   // Strip excess trailing nul bytes. Using strlen() here is safe,
171   // uv_get_process_title() always zero-terminates the result.
172   buf.resize(strlen(buf.data()));
173 
174   return buf;
175 }
176 
GetHumanReadableProcessName()177 std::string GetHumanReadableProcessName() {
178   return SPrintF("%s[%d]", GetProcessTitle("Node.js"), uv_os_getpid());
179 }
180 
SplitString(const std::string_view in, const std::string_view delim)181 std::vector<std::string_view> SplitString(const std::string_view in,
182                                           const std::string_view delim) {
183   std::vector<std::string_view> out;
184 
185   for (auto first = in.data(), second = in.data(), last = first + in.size();
186        second != last && first != last;
187        first = second + 1) {
188     second =
189         std::find_first_of(first, last, std::cbegin(delim), std::cend(delim));
190 
191     if (first != second) {
192       out.emplace_back(first, second - first);
193     }
194   }
195 
196   return out;
197 }
198 
ThrowErrStringTooLong(Isolate* isolate)199 void ThrowErrStringTooLong(Isolate* isolate) {
200   isolate->ThrowException(ERR_STRING_TOO_LONG(isolate));
201 }
202 
GetCurrentTimeInMicroseconds()203 double GetCurrentTimeInMicroseconds() {
204   constexpr double kMicrosecondsPerSecond = 1e6;
205   uv_timeval64_t tv;
206   CHECK_EQ(0, uv_gettimeofday(&tv));
207   return kMicrosecondsPerSecond * tv.tv_sec + tv.tv_usec;
208 }
209 
WriteFileSync(const char* path, uv_buf_t buf)210 int WriteFileSync(const char* path, uv_buf_t buf) {
211   uv_fs_t req;
212   int fd = uv_fs_open(nullptr,
213                       &req,
214                       path,
215                       O_WRONLY | O_CREAT | O_TRUNC,
216                       S_IWUSR | S_IRUSR,
217                       nullptr);
218   uv_fs_req_cleanup(&req);
219   if (fd < 0) {
220     return fd;
221   }
222 
223   int err = uv_fs_write(nullptr, &req, fd, &buf, 1, 0, nullptr);
224   uv_fs_req_cleanup(&req);
225   if (err < 0) {
226     return err;
227   }
228 
229   err = uv_fs_close(nullptr, &req, fd, nullptr);
230   uv_fs_req_cleanup(&req);
231   return err;
232 }
233 
WriteFileSync(v8::Isolate* isolate, const char* path, v8::Local<v8::String> string)234 int WriteFileSync(v8::Isolate* isolate,
235                   const char* path,
236                   v8::Local<v8::String> string) {
237   node::Utf8Value utf8(isolate, string);
238   uv_buf_t buf = uv_buf_init(utf8.out(), utf8.length());
239   return WriteFileSync(path, buf);
240 }
241 
ReadFileSync(std::string* result, const char* path)242 int ReadFileSync(std::string* result, const char* path) {
243   uv_fs_t req;
244   auto defer_req_cleanup = OnScopeLeave([&req]() {
245     uv_fs_req_cleanup(&req);
246   });
247 
248   uv_file file = uv_fs_open(nullptr, &req, path, O_RDONLY, 0, nullptr);
249   if (req.result < 0) {
250     // req will be cleaned up by scope leave.
251     return req.result;
252   }
253   uv_fs_req_cleanup(&req);
254 
255   auto defer_close = OnScopeLeave([file]() {
256     uv_fs_t close_req;
257     CHECK_EQ(0, uv_fs_close(nullptr, &close_req, file, nullptr));
258     uv_fs_req_cleanup(&close_req);
259   });
260 
261   *result = std::string("");
262   char buffer[4096];
263   uv_buf_t buf = uv_buf_init(buffer, sizeof(buffer));
264 
265   while (true) {
266     const int r =
267         uv_fs_read(nullptr, &req, file, &buf, 1, result->length(), nullptr);
268     if (req.result < 0) {
269       // req will be cleaned up by scope leave.
270       return req.result;
271     }
272     uv_fs_req_cleanup(&req);
273     if (r <= 0) {
274       break;
275     }
276     result->append(buf.base, r);
277   }
278   return 0;
279 }
280 
LocalTime(TIME_TYPE* tm_struct)281 void DiagnosticFilename::LocalTime(TIME_TYPE* tm_struct) {
282 #ifdef _WIN32
283   GetLocalTime(tm_struct);
284 #else  // UNIX, OSX
285   struct timeval time_val;
286   gettimeofday(&time_val, nullptr);
287   localtime_r(&time_val.tv_sec, tm_struct);
288 #endif
289 }
290 
291 // Defined in node_internals.h
MakeFilename( uint64_t thread_id, const char* prefix, const char* ext)292 std::string DiagnosticFilename::MakeFilename(
293     uint64_t thread_id,
294     const char* prefix,
295     const char* ext) {
296   std::ostringstream oss;
297   TIME_TYPE tm_struct;
298   LocalTime(&tm_struct);
299   oss << prefix;
300 #ifdef _WIN32
301   oss << "." << std::setfill('0') << std::setw(4) << tm_struct.wYear;
302   oss << std::setfill('0') << std::setw(2) << tm_struct.wMonth;
303   oss << std::setfill('0') << std::setw(2) << tm_struct.wDay;
304   oss << "." << std::setfill('0') << std::setw(2) << tm_struct.wHour;
305   oss << std::setfill('0') << std::setw(2) << tm_struct.wMinute;
306   oss << std::setfill('0') << std::setw(2) << tm_struct.wSecond;
307 #else  // UNIX, OSX
308   oss << "."
309             << std::setfill('0')
310             << std::setw(4)
311             << tm_struct.tm_year + 1900;
312   oss << std::setfill('0')
313             << std::setw(2)
314             << tm_struct.tm_mon + 1;
315   oss << std::setfill('0')
316             << std::setw(2)
317             << tm_struct.tm_mday;
318   oss << "."
319             << std::setfill('0')
320             << std::setw(2)
321             << tm_struct.tm_hour;
322   oss << std::setfill('0')
323             << std::setw(2)
324             << tm_struct.tm_min;
325   oss << std::setfill('0')
326             << std::setw(2)
327             << tm_struct.tm_sec;
328 #endif
329   oss << "." << uv_os_getpid();
330   oss << "." << thread_id;
331   oss << "." << std::setfill('0') << std::setw(3) << ++seq;
332   oss << "." << ext;
333   return oss.str();
334 }
335 
NewFunctionTemplate( v8::Isolate* isolate, v8::FunctionCallback callback, Local<v8::Signature> signature, v8::ConstructorBehavior behavior, v8::SideEffectType side_effect_type, const v8::CFunction* c_function)336 Local<v8::FunctionTemplate> NewFunctionTemplate(
337     v8::Isolate* isolate,
338     v8::FunctionCallback callback,
339     Local<v8::Signature> signature,
340     v8::ConstructorBehavior behavior,
341     v8::SideEffectType side_effect_type,
342     const v8::CFunction* c_function) {
343   return v8::FunctionTemplate::New(isolate,
344                                    callback,
345                                    Local<v8::Value>(),
346                                    signature,
347                                    0,
348                                    behavior,
349                                    side_effect_type,
350                                    c_function);
351 }
352 
SetMethod(Local<v8::Context> context, Local<v8::Object> that, const char* name, v8::FunctionCallback callback)353 void SetMethod(Local<v8::Context> context,
354                Local<v8::Object> that,
355                const char* name,
356                v8::FunctionCallback callback) {
357   Isolate* isolate = context->GetIsolate();
358   Local<v8::Function> function =
359       NewFunctionTemplate(isolate,
360                           callback,
361                           Local<v8::Signature>(),
362                           v8::ConstructorBehavior::kThrow,
363                           v8::SideEffectType::kHasSideEffect)
364           ->GetFunction(context)
365           .ToLocalChecked();
366   // kInternalized strings are created in the old space.
367   const v8::NewStringType type = v8::NewStringType::kInternalized;
368   Local<v8::String> name_string =
369       v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
370   that->Set(context, name_string, function).Check();
371   function->SetName(name_string);  // NODE_SET_METHOD() compatibility.
372 }
373 
SetMethod(v8::Isolate* isolate, v8::Local<v8::Template> that, const char* name, v8::FunctionCallback callback)374 void SetMethod(v8::Isolate* isolate,
375                v8::Local<v8::Template> that,
376                const char* name,
377                v8::FunctionCallback callback) {
378   Local<v8::FunctionTemplate> t =
379       NewFunctionTemplate(isolate,
380                           callback,
381                           Local<v8::Signature>(),
382                           v8::ConstructorBehavior::kThrow,
383                           v8::SideEffectType::kHasSideEffect);
384   // kInternalized strings are created in the old space.
385   const v8::NewStringType type = v8::NewStringType::kInternalized;
386   Local<v8::String> name_string =
387       v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
388   that->Set(name_string, t);
389 }
390 
SetFastMethod(Local<v8::Context> context, Local<v8::Object> that, const char* name, v8::FunctionCallback slow_callback, const v8::CFunction* c_function)391 void SetFastMethod(Local<v8::Context> context,
392                    Local<v8::Object> that,
393                    const char* name,
394                    v8::FunctionCallback slow_callback,
395                    const v8::CFunction* c_function) {
396   Isolate* isolate = context->GetIsolate();
397   Local<v8::Function> function =
398       NewFunctionTemplate(isolate,
399                           slow_callback,
400                           Local<v8::Signature>(),
401                           v8::ConstructorBehavior::kThrow,
402                           v8::SideEffectType::kHasSideEffect,
403                           c_function)
404           ->GetFunction(context)
405           .ToLocalChecked();
406   const v8::NewStringType type = v8::NewStringType::kInternalized;
407   Local<v8::String> name_string =
408       v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
409   that->Set(context, name_string, function).Check();
410 }
411 
SetFastMethodNoSideEffect(Local<v8::Context> context, Local<v8::Object> that, const char* name, v8::FunctionCallback slow_callback, const v8::CFunction* c_function)412 void SetFastMethodNoSideEffect(Local<v8::Context> context,
413                                Local<v8::Object> that,
414                                const char* name,
415                                v8::FunctionCallback slow_callback,
416                                const v8::CFunction* c_function) {
417   Isolate* isolate = context->GetIsolate();
418   Local<v8::Function> function =
419       NewFunctionTemplate(isolate,
420                           slow_callback,
421                           Local<v8::Signature>(),
422                           v8::ConstructorBehavior::kThrow,
423                           v8::SideEffectType::kHasNoSideEffect,
424                           c_function)
425           ->GetFunction(context)
426           .ToLocalChecked();
427   const v8::NewStringType type = v8::NewStringType::kInternalized;
428   Local<v8::String> name_string =
429       v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
430   that->Set(context, name_string, function).Check();
431 }
432 
SetMethodNoSideEffect(Local<v8::Context> context, Local<v8::Object> that, const char* name, v8::FunctionCallback callback)433 void SetMethodNoSideEffect(Local<v8::Context> context,
434                            Local<v8::Object> that,
435                            const char* name,
436                            v8::FunctionCallback callback) {
437   Isolate* isolate = context->GetIsolate();
438   Local<v8::Function> function =
439       NewFunctionTemplate(isolate,
440                           callback,
441                           Local<v8::Signature>(),
442                           v8::ConstructorBehavior::kThrow,
443                           v8::SideEffectType::kHasNoSideEffect)
444           ->GetFunction(context)
445           .ToLocalChecked();
446   // kInternalized strings are created in the old space.
447   const v8::NewStringType type = v8::NewStringType::kInternalized;
448   Local<v8::String> name_string =
449       v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
450   that->Set(context, name_string, function).Check();
451   function->SetName(name_string);  // NODE_SET_METHOD() compatibility.
452 }
453 
SetProtoMethod(v8::Isolate* isolate, Local<v8::FunctionTemplate> that, const char* name, v8::FunctionCallback callback)454 void SetProtoMethod(v8::Isolate* isolate,
455                     Local<v8::FunctionTemplate> that,
456                     const char* name,
457                     v8::FunctionCallback callback) {
458   Local<v8::Signature> signature = v8::Signature::New(isolate, that);
459   Local<v8::FunctionTemplate> t =
460       NewFunctionTemplate(isolate,
461                           callback,
462                           signature,
463                           v8::ConstructorBehavior::kThrow,
464                           v8::SideEffectType::kHasSideEffect);
465   // kInternalized strings are created in the old space.
466   const v8::NewStringType type = v8::NewStringType::kInternalized;
467   Local<v8::String> name_string =
468       v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
469   that->PrototypeTemplate()->Set(name_string, t);
470   t->SetClassName(name_string);  // NODE_SET_PROTOTYPE_METHOD() compatibility.
471 }
472 
SetProtoMethodNoSideEffect(v8::Isolate* isolate, Local<v8::FunctionTemplate> that, const char* name, v8::FunctionCallback callback)473 void SetProtoMethodNoSideEffect(v8::Isolate* isolate,
474                                 Local<v8::FunctionTemplate> that,
475                                 const char* name,
476                                 v8::FunctionCallback callback) {
477   Local<v8::Signature> signature = v8::Signature::New(isolate, that);
478   Local<v8::FunctionTemplate> t =
479       NewFunctionTemplate(isolate,
480                           callback,
481                           signature,
482                           v8::ConstructorBehavior::kThrow,
483                           v8::SideEffectType::kHasNoSideEffect);
484   // kInternalized strings are created in the old space.
485   const v8::NewStringType type = v8::NewStringType::kInternalized;
486   Local<v8::String> name_string =
487       v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
488   that->PrototypeTemplate()->Set(name_string, t);
489   t->SetClassName(name_string);  // NODE_SET_PROTOTYPE_METHOD() compatibility.
490 }
491 
SetInstanceMethod(v8::Isolate* isolate, Local<v8::FunctionTemplate> that, const char* name, v8::FunctionCallback callback)492 void SetInstanceMethod(v8::Isolate* isolate,
493                        Local<v8::FunctionTemplate> that,
494                        const char* name,
495                        v8::FunctionCallback callback) {
496   Local<v8::Signature> signature = v8::Signature::New(isolate, that);
497   Local<v8::FunctionTemplate> t =
498       NewFunctionTemplate(isolate,
499                           callback,
500                           signature,
501                           v8::ConstructorBehavior::kThrow,
502                           v8::SideEffectType::kHasSideEffect);
503   // kInternalized strings are created in the old space.
504   const v8::NewStringType type = v8::NewStringType::kInternalized;
505   Local<v8::String> name_string =
506       v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
507   that->InstanceTemplate()->Set(name_string, t);
508   t->SetClassName(name_string);
509 }
510 
SetConstructorFunction(Local<v8::Context> context, Local<v8::Object> that, const char* name, Local<v8::FunctionTemplate> tmpl, SetConstructorFunctionFlag flag)511 void SetConstructorFunction(Local<v8::Context> context,
512                             Local<v8::Object> that,
513                             const char* name,
514                             Local<v8::FunctionTemplate> tmpl,
515                             SetConstructorFunctionFlag flag) {
516   Isolate* isolate = context->GetIsolate();
517   SetConstructorFunction(
518       context, that, OneByteString(isolate, name), tmpl, flag);
519 }
520 
SetConstructorFunction(Local<v8::Context> context, Local<v8::Object> that, Local<v8::String> name, Local<v8::FunctionTemplate> tmpl, SetConstructorFunctionFlag flag)521 void SetConstructorFunction(Local<v8::Context> context,
522                             Local<v8::Object> that,
523                             Local<v8::String> name,
524                             Local<v8::FunctionTemplate> tmpl,
525                             SetConstructorFunctionFlag flag) {
526   if (LIKELY(flag == SetConstructorFunctionFlag::SET_CLASS_NAME))
527     tmpl->SetClassName(name);
528   that->Set(context, name, tmpl->GetFunction(context).ToLocalChecked()).Check();
529 }
530 
531 namespace {
532 
533 class NonOwningExternalOneByteResource
534     : public v8::String::ExternalOneByteStringResource {
535  public:
NonOwningExternalOneByteResource(const UnionBytes& source)536   explicit NonOwningExternalOneByteResource(const UnionBytes& source)
537       : source_(source) {}
538   ~NonOwningExternalOneByteResource() override = default;
539 
540   const char* data() const override {
541     return reinterpret_cast<const char*>(source_.one_bytes_data());
542   }
543   size_t length() const override { return source_.length(); }
544 
545   NonOwningExternalOneByteResource(const NonOwningExternalOneByteResource&) =
546       delete;
547   NonOwningExternalOneByteResource& operator=(
548       const NonOwningExternalOneByteResource&) = delete;
549 
550  private:
551   const UnionBytes source_;
552 };
553 
554 class NonOwningExternalTwoByteResource
555     : public v8::String::ExternalStringResource {
556  public:
NonOwningExternalTwoByteResource(const UnionBytes& source)557   explicit NonOwningExternalTwoByteResource(const UnionBytes& source)
558       : source_(source) {}
559   ~NonOwningExternalTwoByteResource() override = default;
560 
561   const uint16_t* data() const override { return source_.two_bytes_data(); }
562   size_t length() const override { return source_.length(); }
563 
564   NonOwningExternalTwoByteResource(const NonOwningExternalTwoByteResource&) =
565       delete;
566   NonOwningExternalTwoByteResource& operator=(
567       const NonOwningExternalTwoByteResource&) = delete;
568 
569  private:
570   const UnionBytes source_;
571 };
572 
573 }  // anonymous namespace
574 
ToStringChecked(Isolate* isolate) const575 Local<String> UnionBytes::ToStringChecked(Isolate* isolate) const {
576   if (UNLIKELY(length() == 0)) {
577     // V8 requires non-null data pointers for empty external strings,
578     // but we don't guarantee that. Solve this by not creating an
579     // external string at all in that case.
580     return String::Empty(isolate);
581   }
582   if (is_one_byte()) {
583     NonOwningExternalOneByteResource* source =
584         new NonOwningExternalOneByteResource(*this);
585     return String::NewExternalOneByte(isolate, source).ToLocalChecked();
586   } else {
587     NonOwningExternalTwoByteResource* source =
588         new NonOwningExternalTwoByteResource(*this);
589     return String::NewExternalTwoByte(isolate, source).ToLocalChecked();
590   }
591 }
592 
593 }  // namespace node
594