Bug Summary

File:out/../src/node_buffer.cc
Warning:line 1027, column 10
Value stored to 'result' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name node_buffer.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/maurizio/node-v18.6.0/out -resource-dir /usr/local/lib/clang/16.0.0 -D V8_DEPRECATION_WARNINGS -D V8_IMMINENT_DEPRECATION_WARNINGS -D _GLIBCXX_USE_CXX11_ABI=1 -D NODE_OPENSSL_CONF_NAME=nodejs_conf -D NODE_OPENSSL_HAS_QUIC -D __STDC_FORMAT_MACROS -D OPENSSL_NO_PINSHARED -D OPENSSL_THREADS -D NODE_ARCH="x64" -D NODE_PLATFORM="linux" -D NODE_WANT_INTERNALS=1 -D V8_DEPRECATION_WARNINGS=1 -D NODE_OPENSSL_SYSTEM_CERT_PATH="" -D NODE_USE_NODE_CODE_CACHE=1 -D HAVE_INSPECTOR=1 -D NODE_ENABLE_LARGE_CODE_PAGES=1 -D __POSIX__ -D NODE_USE_V8_PLATFORM=1 -D NODE_HAVE_I18N_SUPPORT=1 -D HAVE_OPENSSL=1 -D OPENSSL_API_COMPAT=0x10100000L -D UCONFIG_NO_SERVICE=1 -D U_ENABLE_DYLOAD=0 -D U_STATIC_IMPLEMENTATION=1 -D U_HAVE_STD_STRING=1 -D UCONFIG_NO_BREAK_ITERATION=0 -D _LARGEFILE_SOURCE -D _FILE_OFFSET_BITS=64 -D _POSIX_C_SOURCE=200112 -D NGHTTP2_STATICLIB -D NDEBUG -D OPENSSL_USE_NODELETE -D L_ENDIAN -D OPENSSL_BUILDING_OPENSSL -D AES_ASM -D BSAES_ASM -D CMLL_ASM -D ECP_NISTZ256_ASM -D GHASH_ASM -D KECCAK1600_ASM -D MD5_ASM -D OPENSSL_BN_ASM_GF2m -D OPENSSL_BN_ASM_MONT -D OPENSSL_BN_ASM_MONT5 -D OPENSSL_CPUID_OBJ -D OPENSSL_IA32_SSE2 -D PADLOCK_ASM -D POLY1305_ASM -D SHA1_ASM -D SHA256_ASM -D SHA512_ASM -D VPAES_ASM -D WHIRLPOOL_ASM -D X25519_ASM -D OPENSSL_PIC -D NGTCP2_STATICLIB -D NGHTTP3_STATICLIB -I ../src -I /home/maurizio/node-v18.6.0/out/Release/obj/gen -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/include -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/src -I ../deps/googletest/include -I ../deps/histogram/src -I ../deps/uvwasi/include -I ../deps/v8/include -I ../deps/icu-small/source/i18n -I ../deps/icu-small/source/common -I ../deps/zlib -I ../deps/llhttp/include -I ../deps/cares/include -I ../deps/uv/include -I ../deps/nghttp2/lib/includes -I ../deps/brotli/c/include -I ../deps/openssl/openssl/include -I ../deps/openssl/openssl/crypto/include -I ../deps/openssl/config/archs/linux-x86_64/asm/include -I ../deps/openssl/config/archs/linux-x86_64/asm -I ../deps/ngtcp2 -I ../deps/ngtcp2/ngtcp2/lib/includes -I ../deps/ngtcp2/ngtcp2/crypto/includes -I ../deps/ngtcp2/nghttp3/lib/includes -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/backward -internal-isystem /usr/local/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-unused-parameter -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/home/maurizio/node-v18.6.0/out -ferror-limit 19 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-08-22-142216-507842-1 -x c++ ../src/node_buffer.cc
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 "node_buffer.h"
23#include "node.h"
24#include "node_blob.h"
25#include "node_errors.h"
26#include "node_external_reference.h"
27#include "node_internals.h"
28
29#include "env-inl.h"
30#include "string_bytes.h"
31#include "string_search.h"
32#include "util-inl.h"
33#include "v8.h"
34
35#include <cstring>
36#include <climits>
37
38#define THROW_AND_RETURN_UNLESS_BUFFER(env, obj)do { if (!Buffer::HasInstance(obj)) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
\
39 THROW_AND_RETURN_IF_NOT_BUFFER(env, obj, "argument")do { if (!Buffer::HasInstance(obj)) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
\
40
41#define THROW_AND_RETURN_IF_OOB(r)do { Maybe<bool> m = (r); if (m.IsNothing()) return; if
(!m.FromJust()) return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"
); } while (0)
\
42 do { \
43 Maybe<bool> m = (r); \
44 if (m.IsNothing()) return; \
45 if (!m.FromJust()) \
46 return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"); \
47 } while (0) \
48
49namespace node {
50namespace Buffer {
51
52using v8::ArrayBuffer;
53using v8::ArrayBufferView;
54using v8::BackingStore;
55using v8::Context;
56using v8::EscapableHandleScope;
57using v8::FunctionCallbackInfo;
58using v8::Global;
59using v8::HandleScope;
60using v8::Int32;
61using v8::Integer;
62using v8::Isolate;
63using v8::Just;
64using v8::Local;
65using v8::Maybe;
66using v8::MaybeLocal;
67using v8::Nothing;
68using v8::Number;
69using v8::Object;
70using v8::SharedArrayBuffer;
71using v8::String;
72using v8::Uint32;
73using v8::Uint32Array;
74using v8::Uint8Array;
75using v8::Value;
76
77namespace {
78
79class CallbackInfo {
80 public:
81 static inline Local<ArrayBuffer> CreateTrackedArrayBuffer(
82 Environment* env,
83 char* data,
84 size_t length,
85 FreeCallback callback,
86 void* hint);
87
88 CallbackInfo(const CallbackInfo&) = delete;
89 CallbackInfo& operator=(const CallbackInfo&) = delete;
90
91 private:
92 static void CleanupHook(void* data);
93 inline void OnBackingStoreFree();
94 inline void CallAndResetCallback();
95 inline CallbackInfo(Environment* env,
96 FreeCallback callback,
97 char* data,
98 void* hint);
99 Global<ArrayBuffer> persistent_;
100 Mutex mutex_; // Protects callback_.
101 FreeCallback callback_;
102 char* const data_;
103 void* const hint_;
104 Environment* const env_;
105};
106
107
108Local<ArrayBuffer> CallbackInfo::CreateTrackedArrayBuffer(
109 Environment* env,
110 char* data,
111 size_t length,
112 FreeCallback callback,
113 void* hint) {
114 CHECK_NOT_NULL(callback)do { if (__builtin_expect(!!(!((callback) != nullptr)), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "114", "(callback) != nullptr", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
115 CHECK_IMPLIES(data == nullptr, length == 0)do { if (__builtin_expect(!!(!(!(data == nullptr) || (length ==
0))), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "115", "!(data == nullptr) || (length == 0)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
116
117 CallbackInfo* self = new CallbackInfo(env, callback, data, hint);
118 std::unique_ptr<BackingStore> bs =
119 ArrayBuffer::NewBackingStore(data, length, [](void*, size_t, void* arg) {
120 static_cast<CallbackInfo*>(arg)->OnBackingStoreFree();
121 }, self);
122 Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
123
124 // V8 simply ignores the BackingStore deleter callback if data == nullptr,
125 // but our API contract requires it being called.
126 if (data == nullptr) {
127 ab->Detach();
128 self->OnBackingStoreFree(); // This calls `callback` asynchronously.
129 } else {
130 // Store the ArrayBuffer so that we can detach it later.
131 self->persistent_.Reset(env->isolate(), ab);
132 self->persistent_.SetWeak();
133 }
134
135 return ab;
136}
137
138
139CallbackInfo::CallbackInfo(Environment* env,
140 FreeCallback callback,
141 char* data,
142 void* hint)
143 : callback_(callback),
144 data_(data),
145 hint_(hint),
146 env_(env) {
147 env->AddCleanupHook(CleanupHook, this);
148 env->isolate()->AdjustAmountOfExternalAllocatedMemory(sizeof(*this));
149}
150
151void CallbackInfo::CleanupHook(void* data) {
152 CallbackInfo* self = static_cast<CallbackInfo*>(data);
153
154 {
155 HandleScope handle_scope(self->env_->isolate());
156 Local<ArrayBuffer> ab = self->persistent_.Get(self->env_->isolate());
157 if (!ab.IsEmpty() && ab->IsDetachable()) {
158 ab->Detach();
159 self->persistent_.Reset();
160 }
161 }
162
163 // Call the callback in this case, but don't delete `this` yet because the
164 // BackingStore deleter callback will do so later.
165 self->CallAndResetCallback();
166}
167
168void CallbackInfo::CallAndResetCallback() {
169 FreeCallback callback;
170 {
171 Mutex::ScopedLock lock(mutex_);
172 callback = callback_;
173 callback_ = nullptr;
174 }
175 if (callback != nullptr) {
176 // Clean up all Environment-related state and run the callback.
177 env_->RemoveCleanupHook(CleanupHook, this);
178 int64_t change_in_bytes = -static_cast<int64_t>(sizeof(*this));
179 env_->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
180
181 callback(data_, hint_);
182 }
183}
184
185void CallbackInfo::OnBackingStoreFree() {
186 // This method should always release the memory for `this`.
187 std::unique_ptr<CallbackInfo> self { this };
188 Mutex::ScopedLock lock(mutex_);
189 // If callback_ == nullptr, that means that the callback has already run from
190 // the cleanup hook, and there is nothing left to do here besides to clean
191 // up the memory involved. In particular, the underlying `Environment` may
192 // be gone at this point, so don’t attempt to call SetImmediateThreadsafe().
193 if (callback_ == nullptr) return;
194
195 env_->SetImmediateThreadsafe([self = std::move(self)](Environment* env) {
196 CHECK_EQ(self->env_, env)do { if (__builtin_expect(!!(!((self->env_) == (env))), 0)
) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "196", "(self->env_) == (env)", __PRETTY_FUNCTION__ }
; node::Assert(args); } while (0); } } while (0)
; // Consistency check.
197
198 self->CallAndResetCallback();
199 });
200}
201
202
203// Parse index for external array data. An empty Maybe indicates
204// a pending exception. `false` indicates that the index is out-of-bounds.
205inline MUST_USE_RESULT__attribute__((warn_unused_result)) Maybe<bool> ParseArrayIndex(Environment* env,
206 Local<Value> arg,
207 size_t def,
208 size_t* ret) {
209 if (arg->IsUndefined()) {
210 *ret = def;
211 return Just(true);
212 }
213
214 int64_t tmp_i;
215 if (!arg->IntegerValue(env->context()).To(&tmp_i))
216 return Nothing<bool>();
217
218 if (tmp_i < 0)
219 return Just(false);
220
221 // Check that the result fits in a size_t.
222 // coverity[pointless_expression]
223 if (static_cast<uint64_t>(tmp_i) > std::numeric_limits<size_t>::max())
224 return Just(false);
225
226 *ret = static_cast<size_t>(tmp_i);
227 return Just(true);
228}
229
230} // anonymous namespace
231
232// Buffer methods
233
234bool HasInstance(Local<Value> val) {
235 return val->IsArrayBufferView();
236}
237
238
239bool HasInstance(Local<Object> obj) {
240 return obj->IsArrayBufferView();
241}
242
243
244char* Data(Local<Value> val) {
245 CHECK(val->IsArrayBufferView())do { if (__builtin_expect(!!(!(val->IsArrayBufferView())),
0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "245", "val->IsArrayBufferView()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
246 Local<ArrayBufferView> ui = val.As<ArrayBufferView>();
247 return static_cast<char*>(ui->Buffer()->GetBackingStore()->Data()) +
248 ui->ByteOffset();
249}
250
251
252char* Data(Local<Object> obj) {
253 return Data(obj.As<Value>());
254}
255
256
257size_t Length(Local<Value> val) {
258 CHECK(val->IsArrayBufferView())do { if (__builtin_expect(!!(!(val->IsArrayBufferView())),
0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "258", "val->IsArrayBufferView()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
259 Local<ArrayBufferView> ui = val.As<ArrayBufferView>();
260 return ui->ByteLength();
261}
262
263
264size_t Length(Local<Object> obj) {
265 CHECK(obj->IsArrayBufferView())do { if (__builtin_expect(!!(!(obj->IsArrayBufferView())),
0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "265", "obj->IsArrayBufferView()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
266 Local<ArrayBufferView> ui = obj.As<ArrayBufferView>();
267 return ui->ByteLength();
268}
269
270
271MaybeLocal<Uint8Array> New(Environment* env,
272 Local<ArrayBuffer> ab,
273 size_t byte_offset,
274 size_t length) {
275 CHECK(!env->buffer_prototype_object().IsEmpty())do { if (__builtin_expect(!!(!(!env->buffer_prototype_object
().IsEmpty())), 0)) { do { static const node::AssertionInfo args
= { "../src/node_buffer.cc" ":" "275", "!env->buffer_prototype_object().IsEmpty()"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
276 Local<Uint8Array> ui = Uint8Array::New(ab, byte_offset, length);
277 Maybe<bool> mb =
278 ui->SetPrototype(env->context(), env->buffer_prototype_object());
279 if (mb.IsNothing())
280 return MaybeLocal<Uint8Array>();
281 return ui;
282}
283
284MaybeLocal<Uint8Array> New(Isolate* isolate,
285 Local<ArrayBuffer> ab,
286 size_t byte_offset,
287 size_t length) {
288 Environment* env = Environment::GetCurrent(isolate);
289 if (env == nullptr) {
290 THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate);
291 return MaybeLocal<Uint8Array>();
292 }
293 return New(env, ab, byte_offset, length);
294}
295
296
297MaybeLocal<Object> New(Isolate* isolate,
298 Local<String> string,
299 enum encoding enc) {
300 EscapableHandleScope scope(isolate);
301
302 size_t length;
303 if (!StringBytes::Size(isolate, string, enc).To(&length))
304 return Local<Object>();
305 size_t actual = 0;
306 std::unique_ptr<BackingStore> store;
307
308 if (length > 0) {
309 store = ArrayBuffer::NewBackingStore(isolate, length);
310
311 if (UNLIKELY(!store)__builtin_expect(!!(!store), 0)) {
312 THROW_ERR_MEMORY_ALLOCATION_FAILED(isolate);
313 return Local<Object>();
314 }
315
316 actual = StringBytes::Write(
317 isolate,
318 static_cast<char*>(store->Data()),
319 length,
320 string,
321 enc);
322 CHECK(actual <= length)do { if (__builtin_expect(!!(!(actual <= length)), 0)) { do
{ static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "322", "actual <= length", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
323
324 if (LIKELY(actual > 0)__builtin_expect(!!(actual > 0), 1)) {
325 if (actual < length)
326 store = BackingStore::Reallocate(isolate, std::move(store), actual);
327 Local<ArrayBuffer> buf = ArrayBuffer::New(isolate, std::move(store));
328 Local<Object> obj;
329 if (UNLIKELY(!New(isolate, buf, 0, actual).ToLocal(&obj))__builtin_expect(!!(!New(isolate, buf, 0, actual).ToLocal(&
obj)), 0)
)
330 return MaybeLocal<Object>();
331 return scope.Escape(obj);
332 }
333 }
334
335 return scope.EscapeMaybe(New(isolate, 0));
336}
337
338
339MaybeLocal<Object> New(Isolate* isolate, size_t length) {
340 EscapableHandleScope handle_scope(isolate);
341 Local<Object> obj;
342 Environment* env = Environment::GetCurrent(isolate);
343 if (env == nullptr) {
344 THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate);
345 return MaybeLocal<Object>();
346 }
347 if (Buffer::New(env, length).ToLocal(&obj))
348 return handle_scope.Escape(obj);
349 return Local<Object>();
350}
351
352
353MaybeLocal<Object> New(Environment* env, size_t length) {
354 Isolate* isolate(env->isolate());
355 EscapableHandleScope scope(isolate);
356
357 // V8 currently only allows a maximum Typed Array index of max Smi.
358 if (length > kMaxLength) {
359 isolate->ThrowException(ERR_BUFFER_TOO_LARGE(isolate));
360 return Local<Object>();
361 }
362
363 Local<ArrayBuffer> ab;
364 {
365 NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
366 std::unique_ptr<BackingStore> bs =
367 ArrayBuffer::NewBackingStore(isolate, length);
368
369 CHECK(bs)do { if (__builtin_expect(!!(!(bs)), 0)) { do { static const node
::AssertionInfo args = { "../src/node_buffer.cc" ":" "369", "bs"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
370
371 ab = ArrayBuffer::New(isolate, std::move(bs));
372 }
373
374 MaybeLocal<Object> obj =
375 New(env, ab, 0, ab->ByteLength())
376 .FromMaybe(Local<Uint8Array>());
377
378 return scope.EscapeMaybe(obj);
379}
380
381
382MaybeLocal<Object> Copy(Isolate* isolate, const char* data, size_t length) {
383 EscapableHandleScope handle_scope(isolate);
384 Environment* env = Environment::GetCurrent(isolate);
385 if (env == nullptr) {
386 THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate);
387 return MaybeLocal<Object>();
388 }
389 Local<Object> obj;
390 if (Buffer::Copy(env, data, length).ToLocal(&obj))
391 return handle_scope.Escape(obj);
392 return Local<Object>();
393}
394
395
396MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
397 Isolate* isolate(env->isolate());
398 EscapableHandleScope scope(isolate);
399
400 // V8 currently only allows a maximum Typed Array index of max Smi.
401 if (length > kMaxLength) {
402 isolate->ThrowException(ERR_BUFFER_TOO_LARGE(isolate));
403 return Local<Object>();
404 }
405
406 Local<ArrayBuffer> ab;
407 {
408 NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
409 std::unique_ptr<BackingStore> bs =
410 ArrayBuffer::NewBackingStore(isolate, length);
411
412 CHECK(bs)do { if (__builtin_expect(!!(!(bs)), 0)) { do { static const node
::AssertionInfo args = { "../src/node_buffer.cc" ":" "412", "bs"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
413
414 memcpy(bs->Data(), data, length);
415
416 ab = ArrayBuffer::New(isolate, std::move(bs));
417 }
418
419 MaybeLocal<Object> obj =
420 New(env, ab, 0, ab->ByteLength())
421 .FromMaybe(Local<Uint8Array>());
422
423 return scope.EscapeMaybe(obj);
424}
425
426
427MaybeLocal<Object> New(Isolate* isolate,
428 char* data,
429 size_t length,
430 FreeCallback callback,
431 void* hint) {
432 EscapableHandleScope handle_scope(isolate);
433 Environment* env = Environment::GetCurrent(isolate);
434 if (env == nullptr) {
435 callback(data, hint);
436 THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate);
437 return MaybeLocal<Object>();
438 }
439 return handle_scope.EscapeMaybe(
440 Buffer::New(env, data, length, callback, hint));
441}
442
443
444MaybeLocal<Object> New(Environment* env,
445 char* data,
446 size_t length,
447 FreeCallback callback,
448 void* hint) {
449 EscapableHandleScope scope(env->isolate());
450
451 if (length > kMaxLength) {
452 env->isolate()->ThrowException(ERR_BUFFER_TOO_LARGE(env->isolate()));
453 callback(data, hint);
454 return Local<Object>();
455 }
456
457 Local<ArrayBuffer> ab =
458 CallbackInfo::CreateTrackedArrayBuffer(env, data, length, callback, hint);
459 if (ab->SetPrivate(env->context(),
460 env->untransferable_object_private_symbol(),
461 True(env->isolate())).IsNothing()) {
462 return Local<Object>();
463 }
464 MaybeLocal<Uint8Array> maybe_ui = Buffer::New(env, ab, 0, length);
465
466 Local<Uint8Array> ui;
467 if (!maybe_ui.ToLocal(&ui))
468 return MaybeLocal<Object>();
469
470 return scope.Escape(ui);
471}
472
473// Warning: This function needs `data` to be allocated with malloc() and not
474// necessarily isolate's ArrayBuffer::Allocator.
475MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) {
476 EscapableHandleScope handle_scope(isolate);
477 Environment* env = Environment::GetCurrent(isolate);
478 if (env == nullptr) {
479 free(data);
480 THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate);
481 return MaybeLocal<Object>();
482 }
483 Local<Object> obj;
484 if (Buffer::New(env, data, length).ToLocal(&obj))
485 return handle_scope.Escape(obj);
486 return Local<Object>();
487}
488
489// The contract for this function is that `data` is allocated with malloc()
490// and not necessarily isolate's ArrayBuffer::Allocator.
491MaybeLocal<Object> New(Environment* env,
492 char* data,
493 size_t length) {
494 if (length > 0) {
495 CHECK_NOT_NULL(data)do { if (__builtin_expect(!!(!((data) != nullptr)), 0)) { do {
static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "495", "(data) != nullptr", __PRETTY_FUNCTION__ }; node::
Assert(args); } while (0); } } while (0)
;
496 // V8 currently only allows a maximum Typed Array index of max Smi.
497 if (length > kMaxLength) {
498 Isolate* isolate(env->isolate());
499 isolate->ThrowException(ERR_BUFFER_TOO_LARGE(isolate));
500 return Local<Object>();
501 }
502 }
503
504 EscapableHandleScope handle_scope(env->isolate());
505
506 auto free_callback = [](void* data, size_t length, void* deleter_data) {
507 free(data);
508 };
509 std::unique_ptr<BackingStore> bs =
510 v8::ArrayBuffer::NewBackingStore(data, length, free_callback, nullptr);
511
512 Local<ArrayBuffer> ab = v8::ArrayBuffer::New(env->isolate(), std::move(bs));
513
514 Local<Object> obj;
515 if (Buffer::New(env, ab, 0, length).ToLocal(&obj))
516 return handle_scope.Escape(obj);
517 return Local<Object>();
518}
519
520namespace {
521
522void CreateFromString(const FunctionCallbackInfo<Value>& args) {
523 CHECK(args[0]->IsString())do { if (__builtin_expect(!!(!(args[0]->IsString())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "523", "args[0]->IsString()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
524 CHECK(args[1]->IsInt32())do { if (__builtin_expect(!!(!(args[1]->IsInt32())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "524", "args[1]->IsInt32()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
525
526 enum encoding enc = static_cast<enum encoding>(args[1].As<Int32>()->Value());
527 Local<Object> buf;
528 if (New(args.GetIsolate(), args[0].As<String>(), enc).ToLocal(&buf))
529 args.GetReturnValue().Set(buf);
530}
531
532
533template <encoding encoding>
534void StringSlice(const FunctionCallbackInfo<Value>& args) {
535 Environment* env = Environment::GetCurrent(args);
536 Isolate* isolate = env->isolate();
537
538 THROW_AND_RETURN_UNLESS_BUFFER(env, args.This())do { if (!Buffer::HasInstance(args.This())) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
;
539 ArrayBufferViewContents<char> buffer(args.This());
540
541 if (buffer.length() == 0)
542 return args.GetReturnValue().SetEmptyString();
543
544 size_t start = 0;
545 size_t end = 0;
546 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[0], 0, &start))do { Maybe<bool> m = (ParseArrayIndex(env, args[0], 0, &
start)); if (m.IsNothing()) return; if (!m.FromJust()) return
node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"); } while
(0)
;
547 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[1], buffer.length(), &end))do { Maybe<bool> m = (ParseArrayIndex(env, args[1], buffer
.length(), &end)); if (m.IsNothing()) return; if (!m.FromJust
()) return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"
); } while (0)
;
548 if (end < start) end = start;
549 THROW_AND_RETURN_IF_OOB(Just(end <= buffer.length()))do { Maybe<bool> m = (Just(end <= buffer.length()));
if (m.IsNothing()) return; if (!m.FromJust()) return node::THROW_ERR_OUT_OF_RANGE
(env, "Index out of range"); } while (0)
;
550 size_t length = end - start;
551
552 Local<Value> error;
553 MaybeLocal<Value> maybe_ret =
554 StringBytes::Encode(isolate,
555 buffer.data() + start,
556 length,
557 encoding,
558 &error);
559 Local<Value> ret;
560 if (!maybe_ret.ToLocal(&ret)) {
561 CHECK(!error.IsEmpty())do { if (__builtin_expect(!!(!(!error.IsEmpty())), 0)) { do {
static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "561", "!error.IsEmpty()", __PRETTY_FUNCTION__ }; node::
Assert(args); } while (0); } } while (0)
;
562 isolate->ThrowException(error);
563 return;
564 }
565 args.GetReturnValue().Set(ret);
566}
567
568
569// bytesCopied = copy(buffer, target[, targetStart][, sourceStart][, sourceEnd])
570void Copy(const FunctionCallbackInfo<Value> &args) {
571 Environment* env = Environment::GetCurrent(args);
572
573 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0])do { if (!Buffer::HasInstance(args[0])) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
;
574 THROW_AND_RETURN_UNLESS_BUFFER(env, args[1])do { if (!Buffer::HasInstance(args[1])) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
;
575 ArrayBufferViewContents<char> source(args[0]);
576 Local<Object> target_obj = args[1].As<Object>();
577 SPREAD_BUFFER_ARG(target_obj, target)do { if (__builtin_expect(!!(!((target_obj)->IsArrayBufferView
())), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "577", "(target_obj)->IsArrayBufferView()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0); v8::Local
<v8::ArrayBufferView> target = (target_obj).As<v8::ArrayBufferView
>(); std::shared_ptr<v8::BackingStore> target_bs = target
->Buffer()->GetBackingStore(); const size_t target_offset
= target->ByteOffset(); const size_t target_length = target
->ByteLength(); char* const target_data = static_cast<char
*>(target_bs->Data()) + target_offset; if (target_length
> 0) do { if (__builtin_expect(!!(!((target_data) != (nullptr
))), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "577", "(target_data) != (nullptr)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0);
;
578
579 size_t target_start = 0;
580 size_t source_start = 0;
581 size_t source_end = 0;
582
583 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[2], 0, &target_start))do { Maybe<bool> m = (ParseArrayIndex(env, args[2], 0, &
target_start)); if (m.IsNothing()) return; if (!m.FromJust())
return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"
); } while (0)
;
584 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[3], 0, &source_start))do { Maybe<bool> m = (ParseArrayIndex(env, args[3], 0, &
source_start)); if (m.IsNothing()) return; if (!m.FromJust())
return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"
); } while (0)
;
585 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[4], source.length(),do { Maybe<bool> m = (ParseArrayIndex(env, args[4], source
.length(), &source_end)); if (m.IsNothing()) return; if (
!m.FromJust()) return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"
); } while (0)
586 &source_end))do { Maybe<bool> m = (ParseArrayIndex(env, args[4], source
.length(), &source_end)); if (m.IsNothing()) return; if (
!m.FromJust()) return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"
); } while (0)
;
587
588 // Copy 0 bytes; we're done
589 if (target_start >= target_length || source_start >= source_end)
590 return args.GetReturnValue().Set(0);
591
592 if (source_start > source.length())
593 return THROW_ERR_OUT_OF_RANGE(
594 env, "The value of \"sourceStart\" is out of range.");
595
596 if (source_end - source_start > target_length - target_start)
597 source_end = source_start + target_length - target_start;
598
599 uint32_t to_copy = std::min(
600 std::min(source_end - source_start, target_length - target_start),
601 source.length() - source_start);
602
603 memmove(target_data + target_start, source.data() + source_start, to_copy);
604 args.GetReturnValue().Set(to_copy);
605}
606
607
608void Fill(const FunctionCallbackInfo<Value>& args) {
609 Environment* env = Environment::GetCurrent(args);
610 Local<Context> ctx = env->context();
611
612 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0])do { if (!Buffer::HasInstance(args[0])) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
;
613 SPREAD_BUFFER_ARG(args[0], ts_obj)do { if (__builtin_expect(!!(!((args[0])->IsArrayBufferView
())), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "613", "(args[0])->IsArrayBufferView()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0); v8::Local
<v8::ArrayBufferView> ts_obj = (args[0]).As<v8::ArrayBufferView
>(); std::shared_ptr<v8::BackingStore> ts_obj_bs = ts_obj
->Buffer()->GetBackingStore(); const size_t ts_obj_offset
= ts_obj->ByteOffset(); const size_t ts_obj_length = ts_obj
->ByteLength(); char* const ts_obj_data = static_cast<char
*>(ts_obj_bs->Data()) + ts_obj_offset; if (ts_obj_length
> 0) do { if (__builtin_expect(!!(!((ts_obj_data) != (nullptr
))), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "613", "(ts_obj_data) != (nullptr)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0);
;
614
615 size_t start = 0;
616 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[2], 0, &start))do { Maybe<bool> m = (ParseArrayIndex(env, args[2], 0, &
start)); if (m.IsNothing()) return; if (!m.FromJust()) return
node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"); } while
(0)
;
617 size_t end;
618 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[3], 0, &end))do { Maybe<bool> m = (ParseArrayIndex(env, args[3], 0, &
end)); if (m.IsNothing()) return; if (!m.FromJust()) return node
::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"); } while (
0)
;
619
620 size_t fill_length = end - start;
621 Local<String> str_obj;
622 size_t str_length;
623 enum encoding enc;
624
625 // OOB Check. Throw the error in JS.
626 if (start > end || fill_length + start > ts_obj_length)
627 return args.GetReturnValue().Set(-2);
628
629 // First check if Buffer has been passed.
630 if (Buffer::HasInstance(args[1])) {
631 SPREAD_BUFFER_ARG(args[1], fill_obj)do { if (__builtin_expect(!!(!((args[1])->IsArrayBufferView
())), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "631", "(args[1])->IsArrayBufferView()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0); v8::Local
<v8::ArrayBufferView> fill_obj = (args[1]).As<v8::ArrayBufferView
>(); std::shared_ptr<v8::BackingStore> fill_obj_bs =
fill_obj->Buffer()->GetBackingStore(); const size_t fill_obj_offset
= fill_obj->ByteOffset(); const size_t fill_obj_length = fill_obj
->ByteLength(); char* const fill_obj_data = static_cast<
char*>(fill_obj_bs->Data()) + fill_obj_offset; if (fill_obj_length
> 0) do { if (__builtin_expect(!!(!((fill_obj_data) != (nullptr
))), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "631", "(fill_obj_data) != (nullptr)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0);
;
632 str_length = fill_obj_length;
633 memcpy(
634 ts_obj_data + start, fill_obj_data, std::min(str_length, fill_length));
635 goto start_fill;
636 }
637
638 // Then coerce everything that's not a string.
639 if (!args[1]->IsString()) {
640 uint32_t val;
641 if (!args[1]->Uint32Value(ctx).To(&val)) return;
642 int value = val & 255;
643 memset(ts_obj_data + start, value, fill_length);
644 return;
645 }
646
647 str_obj = args[1]->ToString(env->context()).ToLocalChecked();
648 enc = ParseEncoding(env->isolate(), args[4], UTF8);
649
650 // Can't use StringBytes::Write() in all cases. For example if attempting
651 // to write a two byte character into a one byte Buffer.
652 if (enc == UTF8) {
653 str_length = str_obj->Utf8Length(env->isolate());
654 node::Utf8Value str(env->isolate(), args[1]);
655 memcpy(ts_obj_data + start, *str, std::min(str_length, fill_length));
656
657 } else if (enc == UCS2) {
658 str_length = str_obj->Length() * sizeof(uint16_t);
659 node::TwoByteValue str(env->isolate(), args[1]);
660 if (IsBigEndian())
661 SwapBytes16(reinterpret_cast<char*>(&str[0]), str_length);
662
663 memcpy(ts_obj_data + start, *str, std::min(str_length, fill_length));
664
665 } else {
666 // Write initial String to Buffer, then use that memory to copy remainder
667 // of string. Correct the string length for cases like HEX where less than
668 // the total string length is written.
669 str_length = StringBytes::Write(env->isolate(),
670 ts_obj_data + start,
671 fill_length,
672 str_obj,
673 enc,
674 nullptr);
675 }
676
677start_fill:
678
679 if (str_length >= fill_length)
680 return;
681
682 // If str_length is zero, then either an empty buffer was provided, or Write()
683 // indicated that no bytes could be written. If no bytes could be written,
684 // then return -1 because the fill value is invalid. This will trigger a throw
685 // in JavaScript. Silently failing should be avoided because it can lead to
686 // buffers with unexpected contents.
687 if (str_length == 0)
688 return args.GetReturnValue().Set(-1);
689
690 size_t in_there = str_length;
691 char* ptr = ts_obj_data + start + str_length;
692
693 while (in_there < fill_length - in_there) {
694 memcpy(ptr, ts_obj_data + start, in_there);
695 ptr += in_there;
696 in_there *= 2;
697 }
698
699 if (in_there < fill_length) {
700 memcpy(ptr, ts_obj_data + start, fill_length - in_there);
701 }
702}
703
704
705template <encoding encoding>
706void StringWrite(const FunctionCallbackInfo<Value>& args) {
707 Environment* env = Environment::GetCurrent(args);
708
709 THROW_AND_RETURN_UNLESS_BUFFER(env, args.This())do { if (!Buffer::HasInstance(args.This())) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
;
710 SPREAD_BUFFER_ARG(args.This(), ts_obj)do { if (__builtin_expect(!!(!((args.This())->IsArrayBufferView
())), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "710", "(args.This())->IsArrayBufferView()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0); v8::Local
<v8::ArrayBufferView> ts_obj = (args.This()).As<v8::
ArrayBufferView>(); std::shared_ptr<v8::BackingStore>
ts_obj_bs = ts_obj->Buffer()->GetBackingStore(); const
size_t ts_obj_offset = ts_obj->ByteOffset(); const size_t
ts_obj_length = ts_obj->ByteLength(); char* const ts_obj_data
= static_cast<char*>(ts_obj_bs->Data()) + ts_obj_offset
; if (ts_obj_length > 0) do { if (__builtin_expect(!!(!((ts_obj_data
) != (nullptr))), 0)) { do { static const node::AssertionInfo
args = { "../src/node_buffer.cc" ":" "710", "(ts_obj_data) != (nullptr)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0);
;
711
712 THROW_AND_RETURN_IF_NOT_STRING(env, args[0], "argument")do { if (!args[0]->IsString()) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a string"); } while (0)
;
713
714 Local<String> str = args[0]->ToString(env->context()).ToLocalChecked();
715
716 size_t offset = 0;
717 size_t max_length = 0;
718
719 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[1], 0, &offset))do { Maybe<bool> m = (ParseArrayIndex(env, args[1], 0, &
offset)); if (m.IsNothing()) return; if (!m.FromJust()) return
node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"); } while
(0)
;
720 if (offset > ts_obj_length) {
721 return node::THROW_ERR_BUFFER_OUT_OF_BOUNDS(
722 env, "\"offset\" is outside of buffer bounds");
723 }
724
725 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[2], ts_obj_length - offset,do { Maybe<bool> m = (ParseArrayIndex(env, args[2], ts_obj_length
- offset, &max_length)); if (m.IsNothing()) return; if (
!m.FromJust()) return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"
); } while (0)
726 &max_length))do { Maybe<bool> m = (ParseArrayIndex(env, args[2], ts_obj_length
- offset, &max_length)); if (m.IsNothing()) return; if (
!m.FromJust()) return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"
); } while (0)
;
727
728 max_length = std::min(ts_obj_length - offset, max_length);
729
730 if (max_length == 0)
731 return args.GetReturnValue().Set(0);
732
733 uint32_t written = StringBytes::Write(env->isolate(),
734 ts_obj_data + offset,
735 max_length,
736 str,
737 encoding,
738 nullptr);
739 args.GetReturnValue().Set(written);
740}
741
742void ByteLengthUtf8(const FunctionCallbackInfo<Value> &args) {
743 Environment* env = Environment::GetCurrent(args);
744 CHECK(args[0]->IsString())do { if (__builtin_expect(!!(!(args[0]->IsString())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "744", "args[0]->IsString()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
745
746 // Fast case: avoid StringBytes on UTF8 string. Jump to v8.
747 args.GetReturnValue().Set(args[0].As<String>()->Utf8Length(env->isolate()));
748}
749
750// Normalize val to be an integer in the range of [1, -1] since
751// implementations of memcmp() can vary by platform.
752static int normalizeCompareVal(int val, size_t a_length, size_t b_length) {
753 if (val == 0) {
754 if (a_length > b_length)
755 return 1;
756 else if (a_length < b_length)
757 return -1;
758 } else {
759 if (val > 0)
760 return 1;
761 else
762 return -1;
763 }
764 return val;
765}
766
767void CompareOffset(const FunctionCallbackInfo<Value> &args) {
768 Environment* env = Environment::GetCurrent(args);
769
770 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0])do { if (!Buffer::HasInstance(args[0])) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
;
771 THROW_AND_RETURN_UNLESS_BUFFER(env, args[1])do { if (!Buffer::HasInstance(args[1])) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
;
772 ArrayBufferViewContents<char> source(args[0]);
773 ArrayBufferViewContents<char> target(args[1]);
774
775 size_t target_start = 0;
776 size_t source_start = 0;
777 size_t source_end = 0;
778 size_t target_end = 0;
779
780 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[2], 0, &target_start))do { Maybe<bool> m = (ParseArrayIndex(env, args[2], 0, &
target_start)); if (m.IsNothing()) return; if (!m.FromJust())
return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"
); } while (0)
;
781 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[3], 0, &source_start))do { Maybe<bool> m = (ParseArrayIndex(env, args[3], 0, &
source_start)); if (m.IsNothing()) return; if (!m.FromJust())
return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"
); } while (0)
;
782 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[4], target.length(),do { Maybe<bool> m = (ParseArrayIndex(env, args[4], target
.length(), &target_end)); if (m.IsNothing()) return; if (
!m.FromJust()) return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"
); } while (0)
783 &target_end))do { Maybe<bool> m = (ParseArrayIndex(env, args[4], target
.length(), &target_end)); if (m.IsNothing()) return; if (
!m.FromJust()) return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"
); } while (0)
;
784 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[5], source.length(),do { Maybe<bool> m = (ParseArrayIndex(env, args[5], source
.length(), &source_end)); if (m.IsNothing()) return; if (
!m.FromJust()) return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"
); } while (0)
785 &source_end))do { Maybe<bool> m = (ParseArrayIndex(env, args[5], source
.length(), &source_end)); if (m.IsNothing()) return; if (
!m.FromJust()) return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range"
); } while (0)
;
786
787 if (source_start > source.length())
788 return THROW_ERR_OUT_OF_RANGE(
789 env, "The value of \"sourceStart\" is out of range.");
790 if (target_start > target.length())
791 return THROW_ERR_OUT_OF_RANGE(
792 env, "The value of \"targetStart\" is out of range.");
793
794 CHECK_LE(source_start, source_end)do { if (__builtin_expect(!!(!((source_start) <= (source_end
))), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "794", "(source_start) <= (source_end)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
795 CHECK_LE(target_start, target_end)do { if (__builtin_expect(!!(!((target_start) <= (target_end
))), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "795", "(target_start) <= (target_end)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
796
797 size_t to_cmp =
798 std::min(std::min(source_end - source_start, target_end - target_start),
799 source.length() - source_start);
800
801 int val = normalizeCompareVal(to_cmp > 0 ?
802 memcmp(source.data() + source_start,
803 target.data() + target_start,
804 to_cmp) : 0,
805 source_end - source_start,
806 target_end - target_start);
807
808 args.GetReturnValue().Set(val);
809}
810
811void Compare(const FunctionCallbackInfo<Value> &args) {
812 Environment* env = Environment::GetCurrent(args);
813
814 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0])do { if (!Buffer::HasInstance(args[0])) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
;
815 THROW_AND_RETURN_UNLESS_BUFFER(env, args[1])do { if (!Buffer::HasInstance(args[1])) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
;
816 ArrayBufferViewContents<char> a(args[0]);
817 ArrayBufferViewContents<char> b(args[1]);
818
819 size_t cmp_length = std::min(a.length(), b.length());
820
821 int val = normalizeCompareVal(cmp_length > 0 ?
822 memcmp(a.data(), b.data(), cmp_length) : 0,
823 a.length(), b.length());
824 args.GetReturnValue().Set(val);
825}
826
827
828// Computes the offset for starting an indexOf or lastIndexOf search.
829// Returns either a valid offset in [0...<length - 1>], ie inside the Buffer,
830// or -1 to signal that there is no possible match.
831int64_t IndexOfOffset(size_t length,
832 int64_t offset_i64,
833 int64_t needle_length,
834 bool is_forward) {
835 int64_t length_i64 = static_cast<int64_t>(length);
836 if (offset_i64 < 0) {
837 if (offset_i64 + length_i64 >= 0) {
838 // Negative offsets count backwards from the end of the buffer.
839 return length_i64 + offset_i64;
840 } else if (is_forward || needle_length == 0) {
841 // indexOf from before the start of the buffer: search the whole buffer.
842 return 0;
843 } else {
844 // lastIndexOf from before the start of the buffer: no match.
845 return -1;
846 }
847 } else {
848 if (offset_i64 + needle_length <= length_i64) {
849 // Valid positive offset.
850 return offset_i64;
851 } else if (needle_length == 0) {
852 // Out of buffer bounds, but empty needle: point to end of buffer.
853 return length_i64;
854 } else if (is_forward) {
855 // indexOf from past the end of the buffer: no match.
856 return -1;
857 } else {
858 // lastIndexOf from past the end of the buffer: search the whole buffer.
859 return length_i64 - 1;
860 }
861 }
862}
863
864void IndexOfString(const FunctionCallbackInfo<Value>& args) {
865 Environment* env = Environment::GetCurrent(args);
866 Isolate* isolate = env->isolate();
867
868 CHECK(args[1]->IsString())do { if (__builtin_expect(!!(!(args[1]->IsString())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "868", "args[1]->IsString()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
869 CHECK(args[2]->IsNumber())do { if (__builtin_expect(!!(!(args[2]->IsNumber())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "869", "args[2]->IsNumber()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
870 CHECK(args[3]->IsInt32())do { if (__builtin_expect(!!(!(args[3]->IsInt32())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "870", "args[3]->IsInt32()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
871 CHECK(args[4]->IsBoolean())do { if (__builtin_expect(!!(!(args[4]->IsBoolean())), 0))
{ do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "871", "args[4]->IsBoolean()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
872
873 enum encoding enc = static_cast<enum encoding>(args[3].As<Int32>()->Value());
874
875 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0])do { if (!Buffer::HasInstance(args[0])) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
;
876 ArrayBufferViewContents<char> buffer(args[0]);
877
878 Local<String> needle = args[1].As<String>();
879 int64_t offset_i64 = args[2].As<Integer>()->Value();
880 bool is_forward = args[4]->IsTrue();
881
882 const char* haystack = buffer.data();
883 // Round down to the nearest multiple of 2 in case of UCS2.
884 const size_t haystack_length = (enc == UCS2) ?
885 buffer.length() &~ 1 : buffer.length(); // NOLINT(whitespace/operators)
886
887 size_t needle_length;
888 if (!StringBytes::Size(isolate, needle, enc).To(&needle_length)) return;
889
890 int64_t opt_offset = IndexOfOffset(haystack_length,
891 offset_i64,
892 needle_length,
893 is_forward);
894
895 if (needle_length == 0) {
896 // Match String#indexOf() and String#lastIndexOf() behavior.
897 args.GetReturnValue().Set(static_cast<double>(opt_offset));
898 return;
899 }
900
901 if (haystack_length == 0) {
902 return args.GetReturnValue().Set(-1);
903 }
904
905 if (opt_offset <= -1) {
906 return args.GetReturnValue().Set(-1);
907 }
908 size_t offset = static_cast<size_t>(opt_offset);
909 CHECK_LT(offset, haystack_length)do { if (__builtin_expect(!!(!((offset) < (haystack_length
))), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "909", "(offset) < (haystack_length)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
910 if ((is_forward && needle_length + offset > haystack_length) ||
911 needle_length > haystack_length) {
912 return args.GetReturnValue().Set(-1);
913 }
914
915 size_t result = haystack_length;
916
917 if (enc == UCS2) {
918 String::Value needle_value(isolate, needle);
919 if (*needle_value == nullptr)
920 return args.GetReturnValue().Set(-1);
921
922 if (haystack_length < 2 || needle_value.length() < 1) {
923 return args.GetReturnValue().Set(-1);
924 }
925
926 if (IsBigEndian()) {
927 StringBytes::InlineDecoder decoder;
928 if (decoder.Decode(env, needle, enc).IsNothing()) return;
929 const uint16_t* decoded_string =
930 reinterpret_cast<const uint16_t*>(decoder.out());
931
932 if (decoded_string == nullptr)
933 return args.GetReturnValue().Set(-1);
934
935 result = SearchString(reinterpret_cast<const uint16_t*>(haystack),
936 haystack_length / 2,
937 decoded_string,
938 decoder.size() / 2,
939 offset / 2,
940 is_forward);
941 } else {
942 result = SearchString(reinterpret_cast<const uint16_t*>(haystack),
943 haystack_length / 2,
944 reinterpret_cast<const uint16_t*>(*needle_value),
945 needle_value.length(),
946 offset / 2,
947 is_forward);
948 }
949 result *= 2;
950 } else if (enc == UTF8) {
951 String::Utf8Value needle_value(isolate, needle);
952 if (*needle_value == nullptr)
953 return args.GetReturnValue().Set(-1);
954
955 result = SearchString(reinterpret_cast<const uint8_t*>(haystack),
956 haystack_length,
957 reinterpret_cast<const uint8_t*>(*needle_value),
958 needle_length,
959 offset,
960 is_forward);
961 } else if (enc == LATIN1) {
962 uint8_t* needle_data = node::UncheckedMalloc<uint8_t>(needle_length);
963 if (needle_data == nullptr) {
964 return args.GetReturnValue().Set(-1);
965 }
966 needle->WriteOneByte(
967 isolate, needle_data, 0, needle_length, String::NO_NULL_TERMINATION);
968
969 result = SearchString(reinterpret_cast<const uint8_t*>(haystack),
970 haystack_length,
971 needle_data,
972 needle_length,
973 offset,
974 is_forward);
975 free(needle_data);
976 }
977
978 args.GetReturnValue().Set(
979 result == haystack_length ? -1 : static_cast<int>(result));
980}
981
982void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
983 CHECK(args[1]->IsObject())do { if (__builtin_expect(!!(!(args[1]->IsObject())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "983", "args[1]->IsObject()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
984 CHECK(args[2]->IsNumber())do { if (__builtin_expect(!!(!(args[2]->IsNumber())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "984", "args[2]->IsNumber()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
985 CHECK(args[3]->IsInt32())do { if (__builtin_expect(!!(!(args[3]->IsInt32())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "985", "args[3]->IsInt32()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
986 CHECK(args[4]->IsBoolean())do { if (__builtin_expect(!!(!(args[4]->IsBoolean())), 0))
{ do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "986", "args[4]->IsBoolean()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
987
988 enum encoding enc = static_cast<enum encoding>(args[3].As<Int32>()->Value());
989
990 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0])do { if (!Buffer::HasInstance(args[0])) return node::THROW_ERR_INVALID_ARG_TYPE
(Environment::GetCurrent(args), "argument" " must be a buffer"
); } while (0)
;
991 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[1])do { if (!Buffer::HasInstance(args[1])) return node::THROW_ERR_INVALID_ARG_TYPE
(Environment::GetCurrent(args), "argument" " must be a buffer"
); } while (0)
;
992 ArrayBufferViewContents<char> haystack_contents(args[0]);
993 ArrayBufferViewContents<char> needle_contents(args[1]);
994 int64_t offset_i64 = args[2].As<Integer>()->Value();
995 bool is_forward = args[4]->IsTrue();
996
997 const char* haystack = haystack_contents.data();
998 const size_t haystack_length = haystack_contents.length();
999 const char* needle = needle_contents.data();
1000 const size_t needle_length = needle_contents.length();
1001
1002 int64_t opt_offset = IndexOfOffset(haystack_length,
1003 offset_i64,
1004 needle_length,
1005 is_forward);
1006
1007 if (needle_length == 0) {
1008 // Match String#indexOf() and String#lastIndexOf() behavior.
1009 args.GetReturnValue().Set(static_cast<double>(opt_offset));
1010 return;
1011 }
1012
1013 if (haystack_length == 0) {
1014 return args.GetReturnValue().Set(-1);
1015 }
1016
1017 if (opt_offset <= -1) {
1018 return args.GetReturnValue().Set(-1);
1019 }
1020 size_t offset = static_cast<size_t>(opt_offset);
1021 CHECK_LT(offset, haystack_length)do { if (__builtin_expect(!!(!((offset) < (haystack_length
))), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1021", "(offset) < (haystack_length)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
1022 if ((is_forward && needle_length + offset > haystack_length) ||
1023 needle_length > haystack_length) {
1024 return args.GetReturnValue().Set(-1);
1025 }
1026
1027 size_t result = haystack_length;
Value stored to 'result' during its initialization is never read
1028
1029 if (enc == UCS2) {
1030 if (haystack_length < 2 || needle_length < 2) {
1031 return args.GetReturnValue().Set(-1);
1032 }
1033 result = SearchString(
1034 reinterpret_cast<const uint16_t*>(haystack),
1035 haystack_length / 2,
1036 reinterpret_cast<const uint16_t*>(needle),
1037 needle_length / 2,
1038 offset / 2,
1039 is_forward);
1040 result *= 2;
1041 } else {
1042 result = SearchString(
1043 reinterpret_cast<const uint8_t*>(haystack),
1044 haystack_length,
1045 reinterpret_cast<const uint8_t*>(needle),
1046 needle_length,
1047 offset,
1048 is_forward);
1049 }
1050
1051 args.GetReturnValue().Set(
1052 result == haystack_length ? -1 : static_cast<int>(result));
1053}
1054
1055void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
1056 CHECK(args[1]->IsUint32())do { if (__builtin_expect(!!(!(args[1]->IsUint32())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1056", "args[1]->IsUint32()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1057 CHECK(args[2]->IsNumber())do { if (__builtin_expect(!!(!(args[2]->IsNumber())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1057", "args[2]->IsNumber()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1058 CHECK(args[3]->IsBoolean())do { if (__builtin_expect(!!(!(args[3]->IsBoolean())), 0))
{ do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1058", "args[3]->IsBoolean()", __PRETTY_FUNCTION__ }
; node::Assert(args); } while (0); } } while (0)
;
1059
1060 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0])do { if (!Buffer::HasInstance(args[0])) return node::THROW_ERR_INVALID_ARG_TYPE
(Environment::GetCurrent(args), "argument" " must be a buffer"
); } while (0)
;
1061 ArrayBufferViewContents<char> buffer(args[0]);
1062
1063 uint32_t needle = args[1].As<Uint32>()->Value();
1064 int64_t offset_i64 = args[2].As<Integer>()->Value();
1065 bool is_forward = args[3]->IsTrue();
1066
1067 int64_t opt_offset =
1068 IndexOfOffset(buffer.length(), offset_i64, 1, is_forward);
1069 if (opt_offset <= -1 || buffer.length() == 0) {
1070 return args.GetReturnValue().Set(-1);
1071 }
1072 size_t offset = static_cast<size_t>(opt_offset);
1073 CHECK_LT(offset, buffer.length())do { if (__builtin_expect(!!(!((offset) < (buffer.length()
))), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1073", "(offset) < (buffer.length())", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
1074
1075 const void* ptr;
1076 if (is_forward) {
1077 ptr = memchr(buffer.data() + offset, needle, buffer.length() - offset);
1078 } else {
1079 ptr = node::stringsearch::MemrchrFill(buffer.data(), needle, offset + 1);
1080 }
1081 const char* ptr_char = static_cast<const char*>(ptr);
1082 args.GetReturnValue().Set(ptr ? static_cast<int>(ptr_char - buffer.data())
1083 : -1);
1084}
1085
1086
1087void Swap16(const FunctionCallbackInfo<Value>& args) {
1088 Environment* env = Environment::GetCurrent(args);
1089 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0])do { if (!Buffer::HasInstance(args[0])) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
;
1090 SPREAD_BUFFER_ARG(args[0], ts_obj)do { if (__builtin_expect(!!(!((args[0])->IsArrayBufferView
())), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1090", "(args[0])->IsArrayBufferView()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0); v8::Local
<v8::ArrayBufferView> ts_obj = (args[0]).As<v8::ArrayBufferView
>(); std::shared_ptr<v8::BackingStore> ts_obj_bs = ts_obj
->Buffer()->GetBackingStore(); const size_t ts_obj_offset
= ts_obj->ByteOffset(); const size_t ts_obj_length = ts_obj
->ByteLength(); char* const ts_obj_data = static_cast<char
*>(ts_obj_bs->Data()) + ts_obj_offset; if (ts_obj_length
> 0) do { if (__builtin_expect(!!(!((ts_obj_data) != (nullptr
))), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1090", "(ts_obj_data) != (nullptr)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0);
;
1091 SwapBytes16(ts_obj_data, ts_obj_length);
1092 args.GetReturnValue().Set(args[0]);
1093}
1094
1095
1096void Swap32(const FunctionCallbackInfo<Value>& args) {
1097 Environment* env = Environment::GetCurrent(args);
1098 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0])do { if (!Buffer::HasInstance(args[0])) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
;
1099 SPREAD_BUFFER_ARG(args[0], ts_obj)do { if (__builtin_expect(!!(!((args[0])->IsArrayBufferView
())), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1099", "(args[0])->IsArrayBufferView()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0); v8::Local
<v8::ArrayBufferView> ts_obj = (args[0]).As<v8::ArrayBufferView
>(); std::shared_ptr<v8::BackingStore> ts_obj_bs = ts_obj
->Buffer()->GetBackingStore(); const size_t ts_obj_offset
= ts_obj->ByteOffset(); const size_t ts_obj_length = ts_obj
->ByteLength(); char* const ts_obj_data = static_cast<char
*>(ts_obj_bs->Data()) + ts_obj_offset; if (ts_obj_length
> 0) do { if (__builtin_expect(!!(!((ts_obj_data) != (nullptr
))), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1099", "(ts_obj_data) != (nullptr)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0);
;
1100 SwapBytes32(ts_obj_data, ts_obj_length);
1101 args.GetReturnValue().Set(args[0]);
1102}
1103
1104
1105void Swap64(const FunctionCallbackInfo<Value>& args) {
1106 Environment* env = Environment::GetCurrent(args);
1107 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0])do { if (!Buffer::HasInstance(args[0])) return node::THROW_ERR_INVALID_ARG_TYPE
(env, "argument" " must be a buffer"); } while (0)
;
1108 SPREAD_BUFFER_ARG(args[0], ts_obj)do { if (__builtin_expect(!!(!((args[0])->IsArrayBufferView
())), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1108", "(args[0])->IsArrayBufferView()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0); v8::Local
<v8::ArrayBufferView> ts_obj = (args[0]).As<v8::ArrayBufferView
>(); std::shared_ptr<v8::BackingStore> ts_obj_bs = ts_obj
->Buffer()->GetBackingStore(); const size_t ts_obj_offset
= ts_obj->ByteOffset(); const size_t ts_obj_length = ts_obj
->ByteLength(); char* const ts_obj_data = static_cast<char
*>(ts_obj_bs->Data()) + ts_obj_offset; if (ts_obj_length
> 0) do { if (__builtin_expect(!!(!((ts_obj_data) != (nullptr
))), 0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1108", "(ts_obj_data) != (nullptr)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0);
;
1109 SwapBytes64(ts_obj_data, ts_obj_length);
1110 args.GetReturnValue().Set(args[0]);
1111}
1112
1113
1114// Encode a single string to a UTF-8 Uint8Array (not Buffer).
1115// Used in TextEncoder.prototype.encode.
1116static void EncodeUtf8String(const FunctionCallbackInfo<Value>& args) {
1117 Environment* env = Environment::GetCurrent(args);
1118 Isolate* isolate = env->isolate();
1119 CHECK_GE(args.Length(), 1)do { if (__builtin_expect(!!(!((args.Length()) >= (1))), 0
)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1119", "(args.Length()) >= (1)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
1120 CHECK(args[0]->IsString())do { if (__builtin_expect(!!(!(args[0]->IsString())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1120", "args[0]->IsString()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1121
1122 Local<String> str = args[0].As<String>();
1123 size_t length = str->Utf8Length(isolate);
1124
1125 Local<ArrayBuffer> ab;
1126 {
1127 NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
1128 std::unique_ptr<BackingStore> bs =
1129 ArrayBuffer::NewBackingStore(isolate, length);
1130
1131 CHECK(bs)do { if (__builtin_expect(!!(!(bs)), 0)) { do { static const node
::AssertionInfo args = { "../src/node_buffer.cc" ":" "1131", "bs"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
1132
1133 str->WriteUtf8(isolate,
1134 static_cast<char*>(bs->Data()),
1135 -1, // We are certain that `data` is sufficiently large
1136 nullptr,
1137 String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8);
1138
1139 ab = ArrayBuffer::New(isolate, std::move(bs));
1140 }
1141
1142 auto array = Uint8Array::New(ab, 0, length);
1143 args.GetReturnValue().Set(array);
1144}
1145
1146
1147static void EncodeInto(const FunctionCallbackInfo<Value>& args) {
1148 Environment* env = Environment::GetCurrent(args);
1149 Isolate* isolate = env->isolate();
1150 CHECK_GE(args.Length(), 3)do { if (__builtin_expect(!!(!((args.Length()) >= (3))), 0
)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1150", "(args.Length()) >= (3)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
1151 CHECK(args[0]->IsString())do { if (__builtin_expect(!!(!(args[0]->IsString())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1151", "args[0]->IsString()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1152 CHECK(args[1]->IsUint8Array())do { if (__builtin_expect(!!(!(args[1]->IsUint8Array())), 0
)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1152", "args[1]->IsUint8Array()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
1153 CHECK(args[2]->IsUint32Array())do { if (__builtin_expect(!!(!(args[2]->IsUint32Array())),
0)) { do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1153", "args[2]->IsUint32Array()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
1154
1155 Local<String> source = args[0].As<String>();
1156
1157 Local<Uint8Array> dest = args[1].As<Uint8Array>();
1158 Local<ArrayBuffer> buf = dest->Buffer();
1159 char* write_result =
1160 static_cast<char*>(buf->GetBackingStore()->Data()) + dest->ByteOffset();
1161 size_t dest_length = dest->ByteLength();
1162
1163 // results = [ read, written ]
1164 Local<Uint32Array> result_arr = args[2].As<Uint32Array>();
1165 uint32_t* results = reinterpret_cast<uint32_t*>(
1166 static_cast<char*>(result_arr->Buffer()->GetBackingStore()->Data()) +
1167 result_arr->ByteOffset());
1168
1169 int nchars;
1170 int written = source->WriteUtf8(
1171 isolate,
1172 write_result,
1173 dest_length,
1174 &nchars,
1175 String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8);
1176 results[0] = nchars;
1177 results[1] = written;
1178}
1179
1180
1181void SetBufferPrototype(const FunctionCallbackInfo<Value>& args) {
1182 Environment* env = Environment::GetCurrent(args);
1183
1184 CHECK(args[0]->IsObject())do { if (__builtin_expect(!!(!(args[0]->IsObject())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1184", "args[0]->IsObject()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1185 Local<Object> proto = args[0].As<Object>();
1186 env->set_buffer_prototype_object(proto);
1187}
1188
1189void GetZeroFillToggle(const FunctionCallbackInfo<Value>& args) {
1190 Environment* env = Environment::GetCurrent(args);
1191 NodeArrayBufferAllocator* allocator = env->isolate_data()->node_allocator();
1192 Local<ArrayBuffer> ab;
1193 // It can be a nullptr when running inside an isolate where we
1194 // do not own the ArrayBuffer allocator.
1195 if (allocator == nullptr) {
1196 // Create a dummy Uint32Array - the JS land can only toggle the C++ land
1197 // setting when the allocator uses our toggle. With this the toggle in JS
1198 // land results in no-ops.
1199 ab = ArrayBuffer::New(env->isolate(), sizeof(uint32_t));
1200 } else {
1201 uint32_t* zero_fill_field = allocator->zero_fill_field();
1202 std::unique_ptr<BackingStore> backing =
1203 ArrayBuffer::NewBackingStore(zero_fill_field,
1204 sizeof(*zero_fill_field),
1205 [](void*, size_t, void*) {},
1206 nullptr);
1207 ab = ArrayBuffer::New(env->isolate(), std::move(backing));
1208 }
1209
1210 ab->SetPrivate(
1211 env->context(),
1212 env->untransferable_object_private_symbol(),
1213 True(env->isolate())).Check();
1214
1215 args.GetReturnValue().Set(Uint32Array::New(ab, 0, 1));
1216}
1217
1218void DetachArrayBuffer(const FunctionCallbackInfo<Value>& args) {
1219 Environment* env = Environment::GetCurrent(args);
1220 if (args[0]->IsArrayBuffer()) {
1221 Local<ArrayBuffer> buf = args[0].As<ArrayBuffer>();
1222 if (buf->IsDetachable()) {
1223 std::shared_ptr<BackingStore> store = buf->GetBackingStore();
1224 buf->Detach();
1225 args.GetReturnValue().Set(ArrayBuffer::New(env->isolate(), store));
1226 }
1227 }
1228}
1229
1230void CopyArrayBuffer(const FunctionCallbackInfo<Value>& args) {
1231 // args[0] == Destination ArrayBuffer
1232 // args[1] == Destination ArrayBuffer Offset
1233 // args[2] == Source ArrayBuffer
1234 // args[3] == Source ArrayBuffer Offset
1235 // args[4] == bytesToCopy
1236
1237 CHECK(args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer())do { if (__builtin_expect(!!(!(args[0]->IsArrayBuffer() ||
args[0]->IsSharedArrayBuffer())), 0)) { do { static const
node::AssertionInfo args = { "../src/node_buffer.cc" ":" "1237"
, "args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer()"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
1238 CHECK(args[1]->IsUint32())do { if (__builtin_expect(!!(!(args[1]->IsUint32())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1238", "args[1]->IsUint32()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1239 CHECK(args[2]->IsArrayBuffer() || args[2]->IsSharedArrayBuffer())do { if (__builtin_expect(!!(!(args[2]->IsArrayBuffer() ||
args[2]->IsSharedArrayBuffer())), 0)) { do { static const
node::AssertionInfo args = { "../src/node_buffer.cc" ":" "1239"
, "args[2]->IsArrayBuffer() || args[2]->IsSharedArrayBuffer()"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
1240 CHECK(args[3]->IsUint32())do { if (__builtin_expect(!!(!(args[3]->IsUint32())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1240", "args[3]->IsUint32()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1241 CHECK(args[4]->IsUint32())do { if (__builtin_expect(!!(!(args[4]->IsUint32())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_buffer.cc"
":" "1241", "args[4]->IsUint32()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1242
1243 std::shared_ptr<BackingStore> destination;
1244 std::shared_ptr<BackingStore> source;
1245
1246 if (args[0]->IsArrayBuffer()) {
1247 destination = args[0].As<ArrayBuffer>()->GetBackingStore();
1248 } else if (args[0]->IsSharedArrayBuffer()) {
1249 destination = args[0].As<SharedArrayBuffer>()->GetBackingStore();
1250 }
1251
1252 if (args[2]->IsArrayBuffer()) {
1253 source = args[2].As<ArrayBuffer>()->GetBackingStore();
1254 } else if (args[0]->IsSharedArrayBuffer()) {
1255 source = args[2].As<SharedArrayBuffer>()->GetBackingStore();
1256 }
1257
1258 uint32_t destination_offset = args[1].As<Uint32>()->Value();
1259 uint32_t source_offset = args[3].As<Uint32>()->Value();
1260 size_t bytes_to_copy = args[4].As<Uint32>()->Value();
1261
1262 CHECK_GE(destination->ByteLength() - destination_offset, bytes_to_copy)do { if (__builtin_expect(!!(!((destination->ByteLength() -
destination_offset) >= (bytes_to_copy))), 0)) { do { static
const node::AssertionInfo args = { "../src/node_buffer.cc" ":"
"1262", "(destination->ByteLength() - destination_offset) >= (bytes_to_copy)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
1263 CHECK_GE(source->ByteLength() - source_offset, bytes_to_copy)do { if (__builtin_expect(!!(!((source->ByteLength() - source_offset
) >= (bytes_to_copy))), 0)) { do { static const node::AssertionInfo
args = { "../src/node_buffer.cc" ":" "1263", "(source->ByteLength() - source_offset) >= (bytes_to_copy)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
1264
1265 uint8_t* dest =
1266 static_cast<uint8_t*>(destination->Data()) + destination_offset;
1267 uint8_t* src =
1268 static_cast<uint8_t*>(source->Data()) + source_offset;
1269 memcpy(dest, src, bytes_to_copy);
1270}
1271
1272void Initialize(Local<Object> target,
1273 Local<Value> unused,
1274 Local<Context> context,
1275 void* priv) {
1276 Environment* env = Environment::GetCurrent(context);
1277
1278 env->SetMethod(target, "setBufferPrototype", SetBufferPrototype);
1279 env->SetMethodNoSideEffect(target, "createFromString", CreateFromString);
1280
1281 env->SetMethodNoSideEffect(target, "byteLengthUtf8", ByteLengthUtf8);
1282 env->SetMethod(target, "copy", Copy);
1283 env->SetMethodNoSideEffect(target, "compare", Compare);
1284 env->SetMethodNoSideEffect(target, "compareOffset", CompareOffset);
1285 env->SetMethod(target, "fill", Fill);
1286 env->SetMethodNoSideEffect(target, "indexOfBuffer", IndexOfBuffer);
1287 env->SetMethodNoSideEffect(target, "indexOfNumber", IndexOfNumber);
1288 env->SetMethodNoSideEffect(target, "indexOfString", IndexOfString);
1289
1290 env->SetMethod(target, "detachArrayBuffer", DetachArrayBuffer);
1291 env->SetMethod(target, "copyArrayBuffer", CopyArrayBuffer);
1292
1293 env->SetMethod(target, "swap16", Swap16);
1294 env->SetMethod(target, "swap32", Swap32);
1295 env->SetMethod(target, "swap64", Swap64);
1296
1297 env->SetMethod(target, "encodeInto", EncodeInto);
1298 env->SetMethodNoSideEffect(target, "encodeUtf8String", EncodeUtf8String);
1299
1300 target->Set(env->context(),
1301 FIXED_ONE_BYTE_STRING(env->isolate(), "kMaxLength"),
1302 Number::New(env->isolate(), kMaxLength)).Check();
1303
1304 target->Set(env->context(),
1305 FIXED_ONE_BYTE_STRING(env->isolate(), "kStringMaxLength"),
1306 Integer::New(env->isolate(), String::kMaxLength)).Check();
1307
1308 env->SetMethodNoSideEffect(target, "asciiSlice", StringSlice<ASCII>);
1309 env->SetMethodNoSideEffect(target, "base64Slice", StringSlice<BASE64>);
1310 env->SetMethodNoSideEffect(target, "base64urlSlice", StringSlice<BASE64URL>);
1311 env->SetMethodNoSideEffect(target, "latin1Slice", StringSlice<LATIN1>);
1312 env->SetMethodNoSideEffect(target, "hexSlice", StringSlice<HEX>);
1313 env->SetMethodNoSideEffect(target, "ucs2Slice", StringSlice<UCS2>);
1314 env->SetMethodNoSideEffect(target, "utf8Slice", StringSlice<UTF8>);
1315
1316 env->SetMethod(target, "asciiWrite", StringWrite<ASCII>);
1317 env->SetMethod(target, "base64Write", StringWrite<BASE64>);
1318 env->SetMethod(target, "base64urlWrite", StringWrite<BASE64URL>);
1319 env->SetMethod(target, "latin1Write", StringWrite<LATIN1>);
1320 env->SetMethod(target, "hexWrite", StringWrite<HEX>);
1321 env->SetMethod(target, "ucs2Write", StringWrite<UCS2>);
1322 env->SetMethod(target, "utf8Write", StringWrite<UTF8>);
1323
1324 env->SetMethod(target, "getZeroFillToggle", GetZeroFillToggle);
1325}
1326
1327} // anonymous namespace
1328
1329void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1330 registry->Register(SetBufferPrototype);
1331 registry->Register(CreateFromString);
1332
1333 registry->Register(ByteLengthUtf8);
1334 registry->Register(Copy);
1335 registry->Register(Compare);
1336 registry->Register(CompareOffset);
1337 registry->Register(Fill);
1338 registry->Register(IndexOfBuffer);
1339 registry->Register(IndexOfNumber);
1340 registry->Register(IndexOfString);
1341
1342 registry->Register(Swap16);
1343 registry->Register(Swap32);
1344 registry->Register(Swap64);
1345
1346 registry->Register(EncodeInto);
1347 registry->Register(EncodeUtf8String);
1348
1349 registry->Register(StringSlice<ASCII>);
1350 registry->Register(StringSlice<BASE64>);
1351 registry->Register(StringSlice<BASE64URL>);
1352 registry->Register(StringSlice<LATIN1>);
1353 registry->Register(StringSlice<HEX>);
1354 registry->Register(StringSlice<UCS2>);
1355 registry->Register(StringSlice<UTF8>);
1356
1357 registry->Register(StringWrite<ASCII>);
1358 registry->Register(StringWrite<BASE64>);
1359 registry->Register(StringWrite<BASE64URL>);
1360 registry->Register(StringWrite<LATIN1>);
1361 registry->Register(StringWrite<HEX>);
1362 registry->Register(StringWrite<UCS2>);
1363 registry->Register(StringWrite<UTF8>);
1364 registry->Register(GetZeroFillToggle);
1365
1366 registry->Register(DetachArrayBuffer);
1367 registry->Register(CopyArrayBuffer);
1368}
1369
1370} // namespace Buffer
1371} // namespace node
1372
1373NODE_MODULE_CONTEXT_AWARE_INTERNAL(buffer, node::Buffer::Initialize)static node::node_module _module = { 108, NM_F_INTERNAL, nullptr
, "../src/node_buffer.cc", nullptr, (node::addon_context_register_func
)(node::Buffer::Initialize), "buffer", nullptr, nullptr}; void
_register_buffer() { node_module_register(&_module); }
1374NODE_MODULE_EXTERNAL_REFERENCE(buffer, node::Buffer::RegisterExternalReferences)void _register_external_reference_buffer( node::ExternalReferenceRegistry
* registry) { node::Buffer::RegisterExternalReferences(registry
); }