GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_buffer.cc Lines: 221 516 42.8 %
Date: 2019-02-01 22:03:38 Branches: 138 724 19.1 %

Line Branch Exec Source
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_errors.h"
25
#include "node_internals.h"
26
27
#include "env-inl.h"
28
#include "string_bytes.h"
29
#include "string_search.h"
30
#include "util-inl.h"
31
#include "v8-profiler.h"
32
#include "v8.h"
33
34
#include <string.h>
35
#include <limits.h>
36
37
#define MIN(a, b) ((a) < (b) ? (a) : (b))
38
39
#define THROW_AND_RETURN_UNLESS_BUFFER(env, obj)                            \
40
  THROW_AND_RETURN_IF_NOT_BUFFER(env, obj, "argument")                      \
41
42
#define THROW_AND_RETURN_IF_OOB(r)                                          \
43
  do {                                                                      \
44
    if ((r).IsNothing()) return;                                            \
45
    if (!(r).FromJust())                                                    \
46
      return node::THROW_ERR_OUT_OF_RANGE(env, "Index out of range");       \
47
  } while (0)                                                               \
48
49
#define SLICE_START_END(env, start_arg, end_arg, end_max)                   \
50
  size_t start;                                                             \
51
  size_t end;                                                               \
52
  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, start_arg, 0, &start));      \
53
  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, end_arg, end_max, &end));    \
54
  if (end < start) end = start;                                             \
55
  THROW_AND_RETURN_IF_OOB(Just(end <= end_max));                            \
56
  size_t length = end - start;
57
58
namespace node {
59
60
namespace {
61
62
173
inline void* BufferMalloc(size_t length) {
63
173
  return per_process::cli_options->zero_fill_all_buffers ?
64
             node::UncheckedCalloc(length) :
65
173
             node::UncheckedMalloc(length);
66
}
67
68
}  // namespace
69
70
namespace Buffer {
71
72
using v8::ArrayBuffer;
73
using v8::ArrayBufferCreationMode;
74
using v8::ArrayBufferView;
75
using v8::Context;
76
using v8::EscapableHandleScope;
77
using v8::FunctionCallbackInfo;
78
using v8::Integer;
79
using v8::Isolate;
80
using v8::Just;
81
using v8::Local;
82
using v8::Maybe;
83
using v8::MaybeLocal;
84
using v8::Nothing;
85
using v8::Object;
86
using v8::String;
87
using v8::Uint32;
88
using v8::Uint32Array;
89
using v8::Uint8Array;
90
using v8::Value;
91
using v8::WeakCallbackInfo;
92
93
namespace {
94
95
6
class CallbackInfo {
96
 public:
97
  static inline void Free(char* data, void* hint);
98
  static inline CallbackInfo* New(Isolate* isolate,
99
                                  Local<ArrayBuffer> object,
100
                                  FreeCallback callback,
101
                                  char* data,
102
                                  void* hint = 0);
103
 private:
104
  static void WeakCallback(const WeakCallbackInfo<CallbackInfo>&);
105
  inline void WeakCallback(Isolate* isolate);
106
  inline CallbackInfo(Isolate* isolate,
107
                      Local<ArrayBuffer> object,
108
                      FreeCallback callback,
109
                      char* data,
110
                      void* hint);
111
  Persistent<ArrayBuffer> persistent_;
112
  FreeCallback const callback_;
113
  char* const data_;
114
  void* const hint_;
115
  DISALLOW_COPY_AND_ASSIGN(CallbackInfo);
116
};
117
118
119
void CallbackInfo::Free(char* data, void*) {
120
  ::free(data);
121
}
122
123
124
3
CallbackInfo* CallbackInfo::New(Isolate* isolate,
125
                                Local<ArrayBuffer> object,
126
                                FreeCallback callback,
127
                                char* data,
128
                                void* hint) {
129
3
  return new CallbackInfo(isolate, object, callback, data, hint);
130
}
131
132
133
3
CallbackInfo::CallbackInfo(Isolate* isolate,
134
                           Local<ArrayBuffer> object,
135
                           FreeCallback callback,
136
                           char* data,
137
                           void* hint)
138
    : persistent_(isolate, object),
139
      callback_(callback),
140
      data_(data),
141
6
      hint_(hint) {
142
3
  ArrayBuffer::Contents obj_c = object->GetContents();
143
3
  CHECK_EQ(data_, static_cast<char*>(obj_c.Data()));
144
3
  if (object->ByteLength() != 0)
145
3
    CHECK_NOT_NULL(data_);
146
147
3
  persistent_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
148
3
  isolate->AdjustAmountOfExternalAllocatedMemory(sizeof(*this));
149
3
}
150
151
152
3
void CallbackInfo::WeakCallback(
153
    const WeakCallbackInfo<CallbackInfo>& data) {
154
3
  CallbackInfo* self = data.GetParameter();
155
3
  self->WeakCallback(data.GetIsolate());
156
3
  delete self;
157
3
}
158
159
160
3
void CallbackInfo::WeakCallback(Isolate* isolate) {
161
3
  callback_(data_, hint_);
162
3
  int64_t change_in_bytes = -static_cast<int64_t>(sizeof(*this));
163
  isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
164
3
}
165
166
167
// Parse index for external array data. An empty Maybe indicates
168
// a pending exception. `false` indicates that the index is out-of-bounds.
169
102204
inline MUST_USE_RESULT Maybe<bool> ParseArrayIndex(Environment* env,
170
                                                   Local<Value> arg,
171
                                                   size_t def,
172
                                                   size_t* ret) {
173
204408
  if (arg->IsUndefined()) {
174
16
    *ret = def;
175
16
    return Just(true);
176
  }
177
178
  int64_t tmp_i;
179
306564
  if (!arg->IntegerValue(env->context()).To(&tmp_i))
180
    return Nothing<bool>();
181
182
102188
  if (tmp_i < 0)
183
    return Just(false);
184
185
  // Check that the result fits in a size_t.
186
102188
  const uint64_t kSizeMax = static_cast<uint64_t>(static_cast<size_t>(-1));
187
  // coverity[pointless_expression]
188
  if (static_cast<uint64_t>(tmp_i) > kSizeMax)
189
    return Just(false);
190
191
102188
  *ret = static_cast<size_t>(tmp_i);
192
102188
  return Just(true);
193
}
194
195
}  // anonymous namespace
196
197
// Buffer methods
198
199
257433
bool HasInstance(Local<Value> val) {
200
257433
  return val->IsArrayBufferView();
201
}
202
203
204
25545
bool HasInstance(Local<Object> obj) {
205
25545
  return obj->IsArrayBufferView();
206
}
207
208
209
1527
char* Data(Local<Value> val) {
210
1527
  CHECK(val->IsArrayBufferView());
211
1527
  Local<ArrayBufferView> ui = val.As<ArrayBufferView>();
212
3054
  ArrayBuffer::Contents ab_c = ui->Buffer()->GetContents();
213
3054
  return static_cast<char*>(ab_c.Data()) + ui->ByteOffset();
214
}
215
216
217
13033
char* Data(Local<Object> obj) {
218
13033
  CHECK(obj->IsArrayBufferView());
219
13033
  Local<ArrayBufferView> ui = obj.As<ArrayBufferView>();
220
26066
  ArrayBuffer::Contents ab_c = ui->Buffer()->GetContents();
221
26066
  return static_cast<char*>(ab_c.Data()) + ui->ByteOffset();
222
}
223
224
225
839
size_t Length(Local<Value> val) {
226
839
  CHECK(val->IsArrayBufferView());
227
839
  Local<ArrayBufferView> ui = val.As<ArrayBufferView>();
228
839
  return ui->ByteLength();
229
}
230
231
232
13024
size_t Length(Local<Object> obj) {
233
13024
  CHECK(obj->IsArrayBufferView());
234
13024
  Local<ArrayBufferView> ui = obj.As<ArrayBufferView>();
235
13024
  return ui->ByteLength();
236
}
237
238
239
168
MaybeLocal<Object> New(Isolate* isolate,
240
                       Local<String> string,
241
                       enum encoding enc) {
242
168
  EscapableHandleScope scope(isolate);
243
244
  size_t length;
245
336
  if (!StringBytes::Size(isolate, string, enc).To(&length))
246
    return Local<Object>();
247
168
  size_t actual = 0;
248
168
  char* data = nullptr;
249
250
168
  if (length > 0) {
251
168
    data = static_cast<char*>(BufferMalloc(length));
252
253
168
    if (data == nullptr) {
254
      THROW_ERR_MEMORY_ALLOCATION_FAILED(isolate);
255
      return Local<Object>();
256
    }
257
258
168
    actual = StringBytes::Write(isolate, data, length, string, enc);
259
168
    CHECK(actual <= length);
260
261
168
    if (actual == 0) {
262
      free(data);
263
      data = nullptr;
264
168
    } else if (actual < length) {
265
      data = node::Realloc(data, actual);
266
    }
267
  }
268
269
  Local<Object> buf;
270
336
  if (New(isolate, data, actual).ToLocal(&buf))
271
168
    return scope.Escape(buf);
272
273
  // Object failed to be created. Clean up resources.
274
  free(data);
275
  return Local<Object>();
276
}
277
278
279
1
MaybeLocal<Object> New(Isolate* isolate, size_t length) {
280
1
  EscapableHandleScope handle_scope(isolate);
281
  Local<Object> obj;
282
1
  Environment* env = Environment::GetCurrent(isolate);
283
1
  if (env == nullptr) {
284
    THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate);
285
    return MaybeLocal<Object>();
286
  }
287
2
  if (Buffer::New(env, length).ToLocal(&obj))
288
1
    return handle_scope.Escape(obj);
289
  return Local<Object>();
290
}
291
292
293
9
MaybeLocal<Object> New(Environment* env, size_t length) {
294
9
  EscapableHandleScope scope(env->isolate());
295
296
  // V8 currently only allows a maximum Typed Array index of max Smi.
297
9
  if (length > kMaxLength) {
298
    env->isolate()->ThrowException(ERR_BUFFER_TOO_LARGE(env->isolate()));
299
    return Local<Object>();
300
  }
301
302
  void* data;
303
9
  if (length > 0) {
304
5
    data = BufferMalloc(length);
305
5
    if (data == nullptr) {
306
      THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
307
      return Local<Object>();
308
    }
309
  } else {
310
4
    data = nullptr;
311
  }
312
313
  Local<ArrayBuffer> ab =
314
    ArrayBuffer::New(env->isolate(),
315
        data,
316
        length,
317
9
        ArrayBufferCreationMode::kInternalized);
318
  Local<Object> obj;
319
18
  if (Buffer::New(env, ab, 0, length).ToLocal(&obj))
320
9
    return scope.Escape(obj);
321
  return Local<Object>();
322
}
323
324
325
1
MaybeLocal<Object> Copy(Isolate* isolate, const char* data, size_t length) {
326
1
  EscapableHandleScope handle_scope(isolate);
327
1
  Environment* env = Environment::GetCurrent(isolate);
328
1
  if (env == nullptr) {
329
    THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate);
330
    return MaybeLocal<Object>();
331
  }
332
  Local<Object> obj;
333
2
  if (Buffer::Copy(env, data, length).ToLocal(&obj))
334
1
    return handle_scope.Escape(obj);
335
  return Local<Object>();
336
}
337
338
339
1
MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
340
1
  EscapableHandleScope scope(env->isolate());
341
342
  // V8 currently only allows a maximum Typed Array index of max Smi.
343
1
  if (length > kMaxLength) {
344
    env->isolate()->ThrowException(ERR_BUFFER_TOO_LARGE(env->isolate()));
345
    return Local<Object>();
346
  }
347
348
  void* new_data;
349
1
  if (length > 0) {
350
1
    CHECK_NOT_NULL(data);
351
1
    new_data = node::UncheckedMalloc(length);
352
1
    if (new_data == nullptr) {
353
      THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
354
      return Local<Object>();
355
    }
356
1
    memcpy(new_data, data, length);
357
  } else {
358
    new_data = nullptr;
359
  }
360
361
  Local<ArrayBuffer> ab =
362
    ArrayBuffer::New(env->isolate(),
363
        new_data,
364
        length,
365
1
        ArrayBufferCreationMode::kInternalized);
366
  Local<Object> obj;
367
2
  if (Buffer::New(env, ab, 0, length).ToLocal(&obj))
368
1
    return scope.Escape(obj);
369
  return Local<Object>();
370
}
371
372
373
3
MaybeLocal<Object> New(Isolate* isolate,
374
                       char* data,
375
                       size_t length,
376
                       FreeCallback callback,
377
                       void* hint) {
378
3
  EscapableHandleScope handle_scope(isolate);
379
3
  Environment* env = Environment::GetCurrent(isolate);
380
3
  if (env == nullptr) {
381
    callback(data, hint);
382
    THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate);
383
    return MaybeLocal<Object>();
384
  }
385
  Local<Object> obj;
386
6
  if (Buffer::New(env, data, length, callback, hint).ToLocal(&obj))
387
3
    return handle_scope.Escape(obj);
388
  return Local<Object>();
389
}
390
391
392
3
MaybeLocal<Object> New(Environment* env,
393
                       char* data,
394
                       size_t length,
395
                       FreeCallback callback,
396
                       void* hint) {
397
3
  EscapableHandleScope scope(env->isolate());
398
399
3
  if (length > kMaxLength) {
400
    env->isolate()->ThrowException(ERR_BUFFER_TOO_LARGE(env->isolate()));
401
    callback(data, hint);
402
    return Local<Object>();
403
  }
404
405
3
  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), data, length);
406
3
  MaybeLocal<Uint8Array> ui = Buffer::New(env, ab, 0, length);
407
408
3
  CallbackInfo::New(env->isolate(), ab, callback, data, hint);
409
410
3
  if (ui.IsEmpty())
411
    return MaybeLocal<Object>();
412
413
3
  return scope.Escape(ui.ToLocalChecked());
414
}
415
416
417
168
MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) {
418
168
  EscapableHandleScope handle_scope(isolate);
419
168
  Environment* env = Environment::GetCurrent(isolate);
420
168
  if (env == nullptr) {
421
    free(data);
422
    THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate);
423
    return MaybeLocal<Object>();
424
  }
425
  Local<Object> obj;
426
336
  if (Buffer::New(env, data, length).ToLocal(&obj))
427
168
    return handle_scope.Escape(obj);
428
  return Local<Object>();
429
}
430
431
432
168
MaybeLocal<Object> New(Environment* env, char* data, size_t length) {
433
168
  if (length > 0) {
434
168
    CHECK_NOT_NULL(data);
435
168
    CHECK(length <= kMaxLength);
436
  }
437
438
  Local<ArrayBuffer> ab =
439
      ArrayBuffer::New(env->isolate(),
440
                       data,
441
                       length,
442
168
                       ArrayBufferCreationMode::kInternalized);
443
336
  return Buffer::New(env, ab, 0, length).FromMaybe(Local<Object>());
444
}
445
446
namespace {
447
448
168
void CreateFromString(const FunctionCallbackInfo<Value>& args) {
449
504
  CHECK(args[0]->IsString());
450
504
  CHECK(args[1]->IsString());
451
452
  enum encoding enc = ParseEncoding(args.GetIsolate(),
453
                                    args[1].As<String>(),
454
336
                                    UTF8);
455
  Local<Object> buf;
456
504
  if (New(args.GetIsolate(), args[0].As<String>(), enc).ToLocal(&buf))
457
336
    args.GetReturnValue().Set(buf);
458
168
}
459
460
461
template <encoding encoding>
462
25197
void StringSlice(const FunctionCallbackInfo<Value>& args) {
463
25197
  Environment* env = Environment::GetCurrent(args);
464
25197
  Isolate* isolate = env->isolate();
465
466



25197
  THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
467









201576
  SPREAD_BUFFER_ARG(args.This(), ts_obj);
468
469



25197
  if (ts_obj_length == 0)
470
    return args.GetReturnValue().SetEmptyString();
471
472





















251970
  SLICE_START_END(env, args[0], args[1], ts_obj_length)
473
474
  Local<Value> error;
475
  MaybeLocal<Value> ret =
476
      StringBytes::Encode(isolate,
477
                          ts_obj_data + start,
478
                          length,
479
                          encoding,
480
25197
                          &error);
481



25197
  if (ret.IsEmpty()) {
482
    CHECK(!error.IsEmpty());
483
    isolate->ThrowException(error);
484
    return;
485
  }
486
50394
  args.GetReturnValue().Set(ret.ToLocalChecked());
487
}
488
489
490
// bytesCopied = copy(buffer, target[, targetStart][, sourceStart][, sourceEnd])
491
4
void Copy(const FunctionCallbackInfo<Value> &args) {
492
4
  Environment* env = Environment::GetCurrent(args);
493
494
4
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
495
4
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[1]);
496
8
  Local<Object> buffer_obj = args[0].As<Object>();
497
8
  Local<Object> target_obj = args[1].As<Object>();
498

24
  SPREAD_BUFFER_ARG(buffer_obj, ts_obj);
499

24
  SPREAD_BUFFER_ARG(target_obj, target);
500
501
  size_t target_start;
502
  size_t source_start;
503
  size_t source_end;
504
505

16
  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[2], 0, &target_start));
506

16
  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[3], 0, &source_start));
507

16
  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[4], ts_obj_length,
508
                                          &source_end));
509
510
  // Copy 0 bytes; we're done
511

4
  if (target_start >= target_length || source_start >= source_end)
512
    return args.GetReturnValue().Set(0);
513
514
4
  if (source_start > ts_obj_length)
515
    return THROW_ERR_OUT_OF_RANGE(
516
        env, "The value of \"sourceStart\" is out of range.");
517
518
4
  if (source_end - source_start > target_length - target_start)
519
    source_end = source_start + target_length - target_start;
520
521
4
  uint32_t to_copy = MIN(MIN(source_end - source_start,
522
                             target_length - target_start),
523
                             ts_obj_length - source_start);
524
525
4
  memmove(target_data + target_start, ts_obj_data + source_start, to_copy);
526
8
  args.GetReturnValue().Set(to_copy);
527
}
528
529
530
void Fill(const FunctionCallbackInfo<Value>& args) {
531
  Environment* env = Environment::GetCurrent(args);
532
  Local<Context> ctx = env->context();
533
534
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
535
  SPREAD_BUFFER_ARG(args[0], ts_obj);
536
537
  uint32_t start;
538
  if (!args[2]->Uint32Value(ctx).To(&start)) return;
539
  uint32_t end;
540
  if (!args[3]->Uint32Value(ctx).To(&end)) return;
541
  size_t fill_length = end - start;
542
  Local<String> str_obj;
543
  size_t str_length;
544
  enum encoding enc;
545
546
  // OOB Check. Throw the error in JS.
547
  if (start > end || fill_length + start > ts_obj_length)
548
    return args.GetReturnValue().Set(-2);
549
550
  // First check if Buffer has been passed.
551
  if (Buffer::HasInstance(args[1])) {
552
    SPREAD_BUFFER_ARG(args[1], fill_obj);
553
    str_length = fill_obj_length;
554
    memcpy(ts_obj_data + start, fill_obj_data, MIN(str_length, fill_length));
555
    goto start_fill;
556
  }
557
558
  // Then coerce everything that's not a string.
559
  if (!args[1]->IsString()) {
560
    uint32_t val;
561
    if (!args[1]->Uint32Value(ctx).To(&val)) return;
562
    int value = val & 255;
563
    memset(ts_obj_data + start, value, fill_length);
564
    return;
565
  }
566
567
  str_obj = args[1]->ToString(env->context()).ToLocalChecked();
568
  enc = ParseEncoding(env->isolate(), args[4], UTF8);
569
570
  // Can't use StringBytes::Write() in all cases. For example if attempting
571
  // to write a two byte character into a one byte Buffer.
572
  if (enc == UTF8) {
573
    str_length = str_obj->Utf8Length(env->isolate());
574
    node::Utf8Value str(env->isolate(), args[1]);
575
    memcpy(ts_obj_data + start, *str, MIN(str_length, fill_length));
576
577
  } else if (enc == UCS2) {
578
    str_length = str_obj->Length() * sizeof(uint16_t);
579
    node::TwoByteValue str(env->isolate(), args[1]);
580
    if (IsBigEndian())
581
      SwapBytes16(reinterpret_cast<char*>(&str[0]), str_length);
582
583
    memcpy(ts_obj_data + start, *str, MIN(str_length, fill_length));
584
585
  } else {
586
    // Write initial String to Buffer, then use that memory to copy remainder
587
    // of string. Correct the string length for cases like HEX where less than
588
    // the total string length is written.
589
    str_length = StringBytes::Write(env->isolate(),
590
                                    ts_obj_data + start,
591
                                    fill_length,
592
                                    str_obj,
593
                                    enc,
594
                                    nullptr);
595
  }
596
597
 start_fill:
598
599
  if (str_length >= fill_length)
600
    return;
601
602
  // If str_length is zero, then either an empty buffer was provided, or Write()
603
  // indicated that no bytes could be written. If no bytes could be written,
604
  // then return -1 because the fill value is invalid. This will trigger a throw
605
  // in JavaScript. Silently failing should be avoided because it can lead to
606
  // buffers with unexpected contents.
607
  if (str_length == 0)
608
    return args.GetReturnValue().Set(-1);
609
610
  size_t in_there = str_length;
611
  char* ptr = ts_obj_data + start + str_length;
612
613
  while (in_there < fill_length - in_there) {
614
    memcpy(ptr, ts_obj_data + start, in_there);
615
    ptr += in_there;
616
    in_there *= 2;
617
  }
618
619
  if (in_there < fill_length) {
620
    memcpy(ptr, ts_obj_data + start, fill_length - in_there);
621
  }
622
}
623
624
625
template <encoding encoding>
626
348
void StringWrite(const FunctionCallbackInfo<Value>& args) {
627
348
  Environment* env = Environment::GetCurrent(args);
628
629



348
  THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
630









2784
  SPREAD_BUFFER_ARG(args.This(), ts_obj);
631
632



1044
  THROW_AND_RETURN_IF_NOT_STRING(env, args[0], "argument");
633
634
1392
  Local<String> str = args[0]->ToString(env->context()).ToLocalChecked();
635
636
  size_t offset;
637
  size_t max_length;
638
639






1392
  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[1], 0, &offset));
640



348
  if (offset > ts_obj_length) {
641
    return node::THROW_ERR_BUFFER_OUT_OF_BOUNDS(
642
        env, "\"offset\" is outside of buffer bounds");
643
  }
644
645






1740
  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[2], ts_obj_length - offset,
646
                                          &max_length));
647
648
348
  max_length = MIN(ts_obj_length - offset, max_length);
649
650



348
  if (max_length == 0)
651
    return args.GetReturnValue().Set(0);
652
653
  uint32_t written = StringBytes::Write(env->isolate(),
654
                                        ts_obj_data + offset,
655
                                        max_length,
656
                                        str,
657
                                        encoding,
658
348
                                        nullptr);
659
696
  args.GetReturnValue().Set(written);
660
}
661
662
908
void ByteLengthUtf8(const FunctionCallbackInfo<Value> &args) {
663
908
  Environment* env = Environment::GetCurrent(args);
664
2724
  CHECK(args[0]->IsString());
665
666
  // Fast case: avoid StringBytes on UTF8 string. Jump to v8.
667
5448
  args.GetReturnValue().Set(args[0].As<String>()->Utf8Length(env->isolate()));
668
908
}
669
670
// Normalize val to be an integer in the range of [1, -1] since
671
// implementations of memcmp() can vary by platform.
672
static int normalizeCompareVal(int val, size_t a_length, size_t b_length) {
673
  if (val == 0) {
674
    if (a_length > b_length)
675
      return 1;
676
    else if (a_length < b_length)
677
      return -1;
678
  } else {
679
    if (val > 0)
680
      return 1;
681
    else
682
      return -1;
683
  }
684
  return val;
685
}
686
687
void CompareOffset(const FunctionCallbackInfo<Value> &args) {
688
  Environment* env = Environment::GetCurrent(args);
689
690
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
691
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[1]);
692
  SPREAD_BUFFER_ARG(args[0], ts_obj);
693
  SPREAD_BUFFER_ARG(args[1], target);
694
695
  size_t target_start;
696
  size_t source_start;
697
  size_t source_end;
698
  size_t target_end;
699
700
  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[2], 0, &target_start));
701
  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[3], 0, &source_start));
702
  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[4], target_length,
703
                                          &target_end));
704
  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[5], ts_obj_length,
705
                                          &source_end));
706
707
  if (source_start > ts_obj_length)
708
    return THROW_ERR_OUT_OF_RANGE(
709
        env, "The value of \"sourceStart\" is out of range.");
710
  if (target_start > target_length)
711
    return THROW_ERR_OUT_OF_RANGE(
712
        env, "The value of \"targetStart\" is out of range.");
713
714
  CHECK_LE(source_start, source_end);
715
  CHECK_LE(target_start, target_end);
716
717
  size_t to_cmp = MIN(MIN(source_end - source_start,
718
                      target_end - target_start),
719
                      ts_obj_length - source_start);
720
721
  int val = normalizeCompareVal(to_cmp > 0 ?
722
                                  memcmp(ts_obj_data + source_start,
723
                                         target_data + target_start,
724
                                         to_cmp) : 0,
725
                                source_end - source_start,
726
                                target_end - target_start);
727
728
  args.GetReturnValue().Set(val);
729
}
730
731
void Compare(const FunctionCallbackInfo<Value> &args) {
732
  Environment* env = Environment::GetCurrent(args);
733
734
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
735
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[1]);
736
  SPREAD_BUFFER_ARG(args[0], obj_a);
737
  SPREAD_BUFFER_ARG(args[1], obj_b);
738
739
  size_t cmp_length = MIN(obj_a_length, obj_b_length);
740
741
  int val = normalizeCompareVal(cmp_length > 0 ?
742
                                memcmp(obj_a_data, obj_b_data, cmp_length) : 0,
743
                                obj_a_length, obj_b_length);
744
  args.GetReturnValue().Set(val);
745
}
746
747
748
// Computes the offset for starting an indexOf or lastIndexOf search.
749
// Returns either a valid offset in [0...<length - 1>], ie inside the Buffer,
750
// or -1 to signal that there is no possible match.
751
int64_t IndexOfOffset(size_t length,
752
                      int64_t offset_i64,
753
                      int64_t needle_length,
754
                      bool is_forward) {
755
  int64_t length_i64 = static_cast<int64_t>(length);
756
  if (offset_i64 < 0) {
757
    if (offset_i64 + length_i64 >= 0) {
758
      // Negative offsets count backwards from the end of the buffer.
759
      return length_i64 + offset_i64;
760
    } else if (is_forward || needle_length == 0) {
761
      // indexOf from before the start of the buffer: search the whole buffer.
762
      return 0;
763
    } else {
764
      // lastIndexOf from before the start of the buffer: no match.
765
      return -1;
766
    }
767
  } else {
768
    if (offset_i64 + needle_length <= length_i64) {
769
      // Valid positive offset.
770
      return offset_i64;
771
    } else if (needle_length == 0) {
772
      // Out of buffer bounds, but empty needle: point to end of buffer.
773
      return length_i64;
774
    } else if (is_forward) {
775
      // indexOf from past the end of the buffer: no match.
776
      return -1;
777
    } else {
778
      // lastIndexOf from past the end of the buffer: search the whole buffer.
779
      return length_i64 - 1;
780
    }
781
  }
782
}
783
784
void IndexOfString(const FunctionCallbackInfo<Value>& args) {
785
  Environment* env = Environment::GetCurrent(args);
786
  Isolate* isolate = env->isolate();
787
788
  CHECK(args[1]->IsString());
789
  CHECK(args[2]->IsNumber());
790
  CHECK(args[4]->IsBoolean());
791
792
  enum encoding enc = ParseEncoding(isolate, args[3], UTF8);
793
794
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
795
  SPREAD_BUFFER_ARG(args[0], ts_obj);
796
797
  Local<String> needle = args[1].As<String>();
798
  int64_t offset_i64 = args[2].As<Integer>()->Value();
799
  bool is_forward = args[4]->IsTrue();
800
801
  const char* haystack = ts_obj_data;
802
  // Round down to the nearest multiple of 2 in case of UCS2.
803
  const size_t haystack_length = (enc == UCS2) ?
804
      ts_obj_length &~ 1 : ts_obj_length;  // NOLINT(whitespace/operators)
805
806
  size_t needle_length;
807
  if (!StringBytes::Size(isolate, needle, enc).To(&needle_length)) return;
808
809
  int64_t opt_offset = IndexOfOffset(haystack_length,
810
                                     offset_i64,
811
                                     needle_length,
812
                                     is_forward);
813
814
  if (needle_length == 0) {
815
    // Match String#indexOf() and String#lastIndexOf() behavior.
816
    args.GetReturnValue().Set(static_cast<double>(opt_offset));
817
    return;
818
  }
819
820
  if (haystack_length == 0) {
821
    return args.GetReturnValue().Set(-1);
822
  }
823
824
  if (opt_offset <= -1) {
825
    return args.GetReturnValue().Set(-1);
826
  }
827
  size_t offset = static_cast<size_t>(opt_offset);
828
  CHECK_LT(offset, haystack_length);
829
  if ((is_forward && needle_length + offset > haystack_length) ||
830
      needle_length > haystack_length) {
831
    return args.GetReturnValue().Set(-1);
832
  }
833
834
  size_t result = haystack_length;
835
836
  if (enc == UCS2) {
837
    String::Value needle_value(isolate, needle);
838
    if (*needle_value == nullptr)
839
      return args.GetReturnValue().Set(-1);
840
841
    if (haystack_length < 2 || needle_value.length() < 1) {
842
      return args.GetReturnValue().Set(-1);
843
    }
844
845
    if (IsBigEndian()) {
846
      StringBytes::InlineDecoder decoder;
847
      if (decoder.Decode(env, needle, args[3], UCS2).IsNothing()) return;
848
      const uint16_t* decoded_string =
849
          reinterpret_cast<const uint16_t*>(decoder.out());
850
851
      if (decoded_string == nullptr)
852
        return args.GetReturnValue().Set(-1);
853
854
      result = SearchString(reinterpret_cast<const uint16_t*>(haystack),
855
                            haystack_length / 2,
856
                            decoded_string,
857
                            decoder.size() / 2,
858
                            offset / 2,
859
                            is_forward);
860
    } else {
861
      result = SearchString(reinterpret_cast<const uint16_t*>(haystack),
862
                            haystack_length / 2,
863
                            reinterpret_cast<const uint16_t*>(*needle_value),
864
                            needle_value.length(),
865
                            offset / 2,
866
                            is_forward);
867
    }
868
    result *= 2;
869
  } else if (enc == UTF8) {
870
    String::Utf8Value needle_value(isolate, needle);
871
    if (*needle_value == nullptr)
872
      return args.GetReturnValue().Set(-1);
873
874
    result = SearchString(reinterpret_cast<const uint8_t*>(haystack),
875
                          haystack_length,
876
                          reinterpret_cast<const uint8_t*>(*needle_value),
877
                          needle_length,
878
                          offset,
879
                          is_forward);
880
  } else if (enc == LATIN1) {
881
    uint8_t* needle_data = node::UncheckedMalloc<uint8_t>(needle_length);
882
    if (needle_data == nullptr) {
883
      return args.GetReturnValue().Set(-1);
884
    }
885
    needle->WriteOneByte(
886
        isolate, needle_data, 0, needle_length, String::NO_NULL_TERMINATION);
887
888
    result = SearchString(reinterpret_cast<const uint8_t*>(haystack),
889
                          haystack_length,
890
                          needle_data,
891
                          needle_length,
892
                          offset,
893
                          is_forward);
894
    free(needle_data);
895
  }
896
897
  args.GetReturnValue().Set(
898
      result == haystack_length ? -1 : static_cast<int>(result));
899
}
900
901
void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
902
  CHECK(args[1]->IsObject());
903
  CHECK(args[2]->IsNumber());
904
  CHECK(args[4]->IsBoolean());
905
906
  enum encoding enc = ParseEncoding(args.GetIsolate(),
907
                                    args[3],
908
                                    UTF8);
909
910
  THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
911
  THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[1]);
912
  SPREAD_BUFFER_ARG(args[0], ts_obj);
913
  SPREAD_BUFFER_ARG(args[1], buf);
914
  int64_t offset_i64 = args[2].As<Integer>()->Value();
915
  bool is_forward = args[4]->IsTrue();
916
917
  const char* haystack = ts_obj_data;
918
  const size_t haystack_length = ts_obj_length;
919
  const char* needle = buf_data;
920
  const size_t needle_length = buf_length;
921
922
  int64_t opt_offset = IndexOfOffset(haystack_length,
923
                                     offset_i64,
924
                                     needle_length,
925
                                     is_forward);
926
927
  if (needle_length == 0) {
928
    // Match String#indexOf() and String#lastIndexOf() behavior.
929
    args.GetReturnValue().Set(static_cast<double>(opt_offset));
930
    return;
931
  }
932
933
  if (haystack_length == 0) {
934
    return args.GetReturnValue().Set(-1);
935
  }
936
937
  if (opt_offset <= -1) {
938
    return args.GetReturnValue().Set(-1);
939
  }
940
  size_t offset = static_cast<size_t>(opt_offset);
941
  CHECK_LT(offset, haystack_length);
942
  if ((is_forward && needle_length + offset > haystack_length) ||
943
      needle_length > haystack_length) {
944
    return args.GetReturnValue().Set(-1);
945
  }
946
947
  size_t result = haystack_length;
948
949
  if (enc == UCS2) {
950
    if (haystack_length < 2 || needle_length < 2) {
951
      return args.GetReturnValue().Set(-1);
952
    }
953
    result = SearchString(
954
        reinterpret_cast<const uint16_t*>(haystack),
955
        haystack_length / 2,
956
        reinterpret_cast<const uint16_t*>(needle),
957
        needle_length / 2,
958
        offset / 2,
959
        is_forward);
960
    result *= 2;
961
  } else {
962
    result = SearchString(
963
        reinterpret_cast<const uint8_t*>(haystack),
964
        haystack_length,
965
        reinterpret_cast<const uint8_t*>(needle),
966
        needle_length,
967
        offset,
968
        is_forward);
969
  }
970
971
  args.GetReturnValue().Set(
972
      result == haystack_length ? -1 : static_cast<int>(result));
973
}
974
975
void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
976
  CHECK(args[1]->IsUint32());
977
  CHECK(args[2]->IsNumber());
978
  CHECK(args[3]->IsBoolean());
979
980
  THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
981
  SPREAD_BUFFER_ARG(args[0], ts_obj);
982
983
  uint32_t needle = args[1].As<Uint32>()->Value();
984
  int64_t offset_i64 = args[2].As<Integer>()->Value();
985
  bool is_forward = args[3]->IsTrue();
986
987
  int64_t opt_offset = IndexOfOffset(ts_obj_length, offset_i64, 1, is_forward);
988
  if (opt_offset <= -1 || ts_obj_length == 0) {
989
    return args.GetReturnValue().Set(-1);
990
  }
991
  size_t offset = static_cast<size_t>(opt_offset);
992
  CHECK_LT(offset, ts_obj_length);
993
994
  const void* ptr;
995
  if (is_forward) {
996
    ptr = memchr(ts_obj_data + offset, needle, ts_obj_length - offset);
997
  } else {
998
    ptr = node::stringsearch::MemrchrFill(ts_obj_data, needle, offset + 1);
999
  }
1000
  const char* ptr_char = static_cast<const char*>(ptr);
1001
  args.GetReturnValue().Set(ptr ? static_cast<int>(ptr_char - ts_obj_data)
1002
                                : -1);
1003
}
1004
1005
1006
void Swap16(const FunctionCallbackInfo<Value>& args) {
1007
  Environment* env = Environment::GetCurrent(args);
1008
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
1009
  SPREAD_BUFFER_ARG(args[0], ts_obj);
1010
  SwapBytes16(ts_obj_data, ts_obj_length);
1011
  args.GetReturnValue().Set(args[0]);
1012
}
1013
1014
1015
void Swap32(const FunctionCallbackInfo<Value>& args) {
1016
  Environment* env = Environment::GetCurrent(args);
1017
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
1018
  SPREAD_BUFFER_ARG(args[0], ts_obj);
1019
  SwapBytes32(ts_obj_data, ts_obj_length);
1020
  args.GetReturnValue().Set(args[0]);
1021
}
1022
1023
1024
void Swap64(const FunctionCallbackInfo<Value>& args) {
1025
  Environment* env = Environment::GetCurrent(args);
1026
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
1027
  SPREAD_BUFFER_ARG(args[0], ts_obj);
1028
  SwapBytes64(ts_obj_data, ts_obj_length);
1029
  args.GetReturnValue().Set(args[0]);
1030
}
1031
1032
1033
// Encode a single string to a UTF-8 Uint8Array (not Buffer).
1034
// Used in TextEncoder.prototype.encode.
1035
static void EncodeUtf8String(const FunctionCallbackInfo<Value>& args) {
1036
  Environment* env = Environment::GetCurrent(args);
1037
  Isolate* isolate = env->isolate();
1038
  CHECK_GE(args.Length(), 1);
1039
  CHECK(args[0]->IsString());
1040
1041
  Local<String> str = args[0].As<String>();
1042
  size_t length = str->Utf8Length(isolate);
1043
  char* data = node::UncheckedMalloc(length);
1044
  str->WriteUtf8(isolate,
1045
                 data,
1046
                 -1,  // We are certain that `data` is sufficiently large
1047
                 nullptr,
1048
                 String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8);
1049
  auto array_buf = ArrayBuffer::New(
1050
      isolate, data, length, ArrayBufferCreationMode::kInternalized);
1051
  auto array = Uint8Array::New(array_buf, 0, length);
1052
  args.GetReturnValue().Set(array);
1053
}
1054
1055
1056
164
void SetBufferPrototype(const FunctionCallbackInfo<Value>& args) {
1057
164
  Environment* env = Environment::GetCurrent(args);
1058
1059
328
  CHECK(args[0]->IsObject());
1060
328
  Local<Object> proto = args[0].As<Object>();
1061
164
  env->set_buffer_prototype_object(proto);
1062
164
}
1063
1064
1065
164
void Initialize(Local<Object> target,
1066
                Local<Value> unused,
1067
                Local<Context> context,
1068
                void* priv) {
1069
164
  Environment* env = Environment::GetCurrent(context);
1070
1071
164
  env->SetMethod(target, "setBufferPrototype", SetBufferPrototype);
1072
164
  env->SetMethodNoSideEffect(target, "createFromString", CreateFromString);
1073
1074
164
  env->SetMethodNoSideEffect(target, "byteLengthUtf8", ByteLengthUtf8);
1075
164
  env->SetMethod(target, "copy", Copy);
1076
164
  env->SetMethodNoSideEffect(target, "compare", Compare);
1077
164
  env->SetMethodNoSideEffect(target, "compareOffset", CompareOffset);
1078
164
  env->SetMethod(target, "fill", Fill);
1079
164
  env->SetMethodNoSideEffect(target, "indexOfBuffer", IndexOfBuffer);
1080
164
  env->SetMethodNoSideEffect(target, "indexOfNumber", IndexOfNumber);
1081
164
  env->SetMethodNoSideEffect(target, "indexOfString", IndexOfString);
1082
1083
164
  env->SetMethod(target, "swap16", Swap16);
1084
164
  env->SetMethod(target, "swap32", Swap32);
1085
164
  env->SetMethod(target, "swap64", Swap64);
1086
1087
164
  env->SetMethodNoSideEffect(target, "encodeUtf8String", EncodeUtf8String);
1088
1089
  target->Set(env->context(),
1090
              FIXED_ONE_BYTE_STRING(env->isolate(), "kMaxLength"),
1091
820
              Integer::NewFromUnsigned(env->isolate(), kMaxLength)).FromJust();
1092
1093
  target->Set(env->context(),
1094
              FIXED_ONE_BYTE_STRING(env->isolate(), "kStringMaxLength"),
1095
820
              Integer::New(env->isolate(), String::kMaxLength)).FromJust();
1096
1097
164
  env->SetMethodNoSideEffect(target, "asciiSlice", StringSlice<ASCII>);
1098
164
  env->SetMethodNoSideEffect(target, "base64Slice", StringSlice<BASE64>);
1099
164
  env->SetMethodNoSideEffect(target, "latin1Slice", StringSlice<LATIN1>);
1100
164
  env->SetMethodNoSideEffect(target, "hexSlice", StringSlice<HEX>);
1101
164
  env->SetMethodNoSideEffect(target, "ucs2Slice", StringSlice<UCS2>);
1102
164
  env->SetMethodNoSideEffect(target, "utf8Slice", StringSlice<UTF8>);
1103
1104
164
  env->SetMethod(target, "asciiWrite", StringWrite<ASCII>);
1105
164
  env->SetMethod(target, "base64Write", StringWrite<BASE64>);
1106
164
  env->SetMethod(target, "latin1Write", StringWrite<LATIN1>);
1107
164
  env->SetMethod(target, "hexWrite", StringWrite<HEX>);
1108
164
  env->SetMethod(target, "ucs2Write", StringWrite<UCS2>);
1109
164
  env->SetMethod(target, "utf8Write", StringWrite<UTF8>);
1110
1111
  // It can be a nullptr when running inside an isolate where we
1112
  // do not own the ArrayBuffer allocator.
1113
164
  if (uint32_t* zero_fill_field = env->isolate_data()->zero_fill_field()) {
1114
    Local<ArrayBuffer> array_buffer = ArrayBuffer::New(
1115
164
        env->isolate(), zero_fill_field, sizeof(*zero_fill_field));
1116
820
    CHECK(target
1117
              ->Set(env->context(),
1118
                    FIXED_ONE_BYTE_STRING(env->isolate(), "zeroFill"),
1119
                    Uint32Array::New(array_buffer, 0, 1))
1120
              .FromJust());
1121
  }
1122
164
}
1123
1124
}  // anonymous namespace
1125
}  // namespace Buffer
1126
}  // namespace node
1127
1128
164
NODE_MODULE_CONTEXT_AWARE_INTERNAL(buffer, node::Buffer::Initialize)