Coverage Report

Created: 2025-07-04 09:33

/src/node/deps/v8/include/v8-array-buffer.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2021 the V8 project authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
#ifndef INCLUDE_V8_ARRAY_BUFFER_H_
6
#define INCLUDE_V8_ARRAY_BUFFER_H_
7
8
#include <stddef.h>
9
10
#include <memory>
11
12
#include "v8-local-handle.h"  // NOLINT(build/include_directory)
13
#include "v8-object.h"        // NOLINT(build/include_directory)
14
#include "v8config.h"         // NOLINT(build/include_directory)
15
16
namespace v8 {
17
18
class SharedArrayBuffer;
19
20
#ifndef V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT
21
// The number of required internal fields can be defined by embedder.
22
#define V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT 2
23
#endif
24
25
enum class ArrayBufferCreationMode { kInternalized, kExternalized };
26
27
/**
28
 * A wrapper around the backing store (i.e. the raw memory) of an array buffer.
29
 * See a document linked in http://crbug.com/v8/9908 for more information.
30
 *
31
 * The allocation and destruction of backing stores is generally managed by
32
 * V8. Clients should always use standard C++ memory ownership types (i.e.
33
 * std::unique_ptr and std::shared_ptr) to manage lifetimes of backing stores
34
 * properly, since V8 internal objects may alias backing stores.
35
 *
36
 * This object does not keep the underlying |ArrayBuffer::Allocator| alive by
37
 * default. Use Isolate::CreateParams::array_buffer_allocator_shared when
38
 * creating the Isolate to make it hold a reference to the allocator itself.
39
 */
40
class V8_EXPORT BackingStore : public v8::internal::BackingStoreBase {
41
 public:
42
  ~BackingStore();
43
44
  /**
45
   * Return a pointer to the beginning of the memory block for this backing
46
   * store. The pointer is only valid as long as this backing store object
47
   * lives.
48
   */
49
  void* Data() const;
50
51
  /**
52
   * The length (in bytes) of this backing store.
53
   */
54
  size_t ByteLength() const;
55
56
  /**
57
   * The maximum length (in bytes) that this backing store may grow to.
58
   *
59
   * If this backing store was created for a resizable ArrayBuffer or a growable
60
   * SharedArrayBuffer, it is >= ByteLength(). Otherwise it is ==
61
   * ByteLength().
62
   */
63
  size_t MaxByteLength() const;
64
65
  /**
66
   * Indicates whether the backing store was created for an ArrayBuffer or
67
   * a SharedArrayBuffer.
68
   */
69
  bool IsShared() const;
70
71
  /**
72
   * Indicates whether the backing store was created for a resizable ArrayBuffer
73
   * or a growable SharedArrayBuffer, and thus may be resized by user JavaScript
74
   * code.
75
   */
76
  bool IsResizableByUserJavaScript() const;
77
78
  /**
79
   * Prevent implicit instantiation of operator delete with size_t argument.
80
   * The size_t argument would be incorrect because ptr points to the
81
   * internal BackingStore object.
82
   */
83
4.79k
  void operator delete(void* ptr) { ::operator delete(ptr); }
84
85
  /**
86
   * Wrapper around ArrayBuffer::Allocator::Reallocate that preserves IsShared.
87
   * Assumes that the backing_store was allocated by the ArrayBuffer allocator
88
   * of the given isolate.
89
   */
90
  static std::unique_ptr<BackingStore> Reallocate(
91
      v8::Isolate* isolate, std::unique_ptr<BackingStore> backing_store,
92
      size_t byte_length);
93
94
  /**
95
   * This callback is used only if the memory block for a BackingStore cannot be
96
   * allocated with an ArrayBuffer::Allocator. In such cases the destructor of
97
   * the BackingStore invokes the callback to free the memory block.
98
   */
99
  using DeleterCallback = void (*)(void* data, size_t length,
100
                                   void* deleter_data);
101
102
  /**
103
   * If the memory block of a BackingStore is static or is managed manually,
104
   * then this empty deleter along with nullptr deleter_data can be passed to
105
   * ArrayBuffer::NewBackingStore to indicate that.
106
   *
107
   * The manually managed case should be used with caution and only when it
108
   * is guaranteed that the memory block freeing happens after detaching its
109
   * ArrayBuffer.
110
   */
111
  static void EmptyDeleter(void* data, size_t length, void* deleter_data);
112
113
 private:
114
  /**
115
   * See [Shared]ArrayBuffer::GetBackingStore and
116
   * [Shared]ArrayBuffer::NewBackingStore.
117
   */
118
  BackingStore();
119
};
120
121
#if !defined(V8_IMMINENT_DEPRECATION_WARNINGS)
122
// Use v8::BackingStore::DeleterCallback instead.
123
using BackingStoreDeleterCallback = void (*)(void* data, size_t length,
124
                                             void* deleter_data);
125
126
#endif
127
128
/**
129
 * An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5).
130
 */
131
class V8_EXPORT ArrayBuffer : public Object {
132
 public:
133
  /**
134
   * A thread-safe allocator that V8 uses to allocate |ArrayBuffer|'s memory.
135
   * The allocator is a global V8 setting. It has to be set via
136
   * Isolate::CreateParams.
137
   *
138
   * Memory allocated through this allocator by V8 is accounted for as external
139
   * memory by V8. Note that V8 keeps track of the memory for all internalized
140
   * |ArrayBuffer|s. Responsibility for tracking external memory (using
141
   * Isolate::AdjustAmountOfExternalAllocatedMemory) is handed over to the
142
   * embedder upon externalization and taken over upon internalization (creating
143
   * an internalized buffer from an existing buffer).
144
   *
145
   * Note that it is unsafe to call back into V8 from any of the allocator
146
   * functions.
147
   */
148
  class V8_EXPORT Allocator {
149
   public:
150
134k
    virtual ~Allocator() = default;
151
152
    /**
153
     * Allocate |length| bytes. Return nullptr if allocation is not successful.
154
     * Memory should be initialized to zeroes.
155
     */
156
    virtual void* Allocate(size_t length) = 0;
157
158
    /**
159
     * Allocate |length| bytes. Return nullptr if allocation is not successful.
160
     * Memory does not have to be initialized.
161
     */
162
    virtual void* AllocateUninitialized(size_t length) = 0;
163
164
    /**
165
     * Free the memory block of size |length|, pointed to by |data|.
166
     * That memory is guaranteed to be previously allocated by |Allocate|.
167
     */
168
    virtual void Free(void* data, size_t length) = 0;
169
170
    /**
171
     * Reallocate the memory block of size |old_length| to a memory block of
172
     * size |new_length| by expanding, contracting, or copying the existing
173
     * memory block. If |new_length| > |old_length|, then the new part of
174
     * the memory must be initialized to zeros. Return nullptr if reallocation
175
     * is not successful.
176
     *
177
     * The caller guarantees that the memory block was previously allocated
178
     * using Allocate or AllocateUninitialized.
179
     *
180
     * The default implementation allocates a new block and copies data.
181
     */
182
    virtual void* Reallocate(void* data, size_t old_length, size_t new_length);
183
184
    /**
185
     * ArrayBuffer allocation mode. kNormal is a malloc/free style allocation,
186
     * while kReservation is for larger allocations with the ability to set
187
     * access permissions.
188
     */
189
    enum class AllocationMode { kNormal, kReservation };
190
191
    /**
192
     * Convenience allocator.
193
     *
194
     * When the sandbox is enabled, this allocator will allocate its backing
195
     * memory inside the sandbox. Otherwise, it will rely on malloc/free.
196
     *
197
     * Caller takes ownership, i.e. the returned object needs to be freed using
198
     * |delete allocator| once it is no longer in use.
199
     */
200
    static Allocator* NewDefaultAllocator();
201
  };
202
203
  /**
204
   * Data length in bytes.
205
   */
206
  size_t ByteLength() const;
207
208
  /**
209
   * Maximum length in bytes.
210
   */
211
  size_t MaxByteLength() const;
212
213
  /**
214
   * Create a new ArrayBuffer. Allocate |byte_length| bytes.
215
   * Allocated memory will be owned by a created ArrayBuffer and
216
   * will be deallocated when it is garbage-collected,
217
   * unless the object is externalized.
218
   */
219
  static Local<ArrayBuffer> New(Isolate* isolate, size_t byte_length);
220
221
  /**
222
   * Create a new ArrayBuffer with an existing backing store.
223
   * The created array keeps a reference to the backing store until the array
224
   * is garbage collected. Note that the IsExternal bit does not affect this
225
   * reference from the array to the backing store.
226
   *
227
   * In future IsExternal bit will be removed. Until then the bit is set as
228
   * follows. If the backing store does not own the underlying buffer, then
229
   * the array is created in externalized state. Otherwise, the array is created
230
   * in internalized state. In the latter case the array can be transitioned
231
   * to the externalized state using Externalize(backing_store).
232
   */
233
  static Local<ArrayBuffer> New(Isolate* isolate,
234
                                std::shared_ptr<BackingStore> backing_store);
235
236
  /**
237
   * Returns a new standalone BackingStore that is allocated using the array
238
   * buffer allocator of the isolate. The result can be later passed to
239
   * ArrayBuffer::New.
240
   *
241
   * If the allocator returns nullptr, then the function may cause GCs in the
242
   * given isolate and re-try the allocation. If GCs do not help, then the
243
   * function will crash with an out-of-memory error.
244
   */
245
  static std::unique_ptr<BackingStore> NewBackingStore(Isolate* isolate,
246
                                                       size_t byte_length);
247
  /**
248
   * Returns a new standalone BackingStore that takes over the ownership of
249
   * the given buffer. The destructor of the BackingStore invokes the given
250
   * deleter callback.
251
   *
252
   * The result can be later passed to ArrayBuffer::New. The raw pointer
253
   * to the buffer must not be passed again to any V8 API function.
254
   */
255
  static std::unique_ptr<BackingStore> NewBackingStore(
256
      void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter,
257
      void* deleter_data);
258
259
  /**
260
   * Returns a new resizable standalone BackingStore that is allocated using the
261
   * array buffer allocator of the isolate. The result can be later passed to
262
   * ArrayBuffer::New.
263
   *
264
   * |byte_length| must be <= |max_byte_length|.
265
   *
266
   * This function is usable without an isolate. Unlike |NewBackingStore| calls
267
   * with an isolate, GCs cannot be triggered, and there are no
268
   * retries. Allocation failure will cause the function to crash with an
269
   * out-of-memory error.
270
   */
271
  static std::unique_ptr<BackingStore> NewResizableBackingStore(
272
      size_t byte_length, size_t max_byte_length);
273
274
  /**
275
   * Returns true if this ArrayBuffer may be detached.
276
   */
277
  bool IsDetachable() const;
278
279
  /**
280
   * Returns true if this ArrayBuffer has been detached.
281
   */
282
  bool WasDetached() const;
283
284
  /**
285
   * Detaches this ArrayBuffer and all its views (typed arrays).
286
   * Detaching sets the byte length of the buffer and all typed arrays to zero,
287
   * preventing JavaScript from ever accessing underlying backing store.
288
   * ArrayBuffer should have been externalized and must be detachable.
289
   */
290
  V8_DEPRECATE_SOON(
291
      "Use the version which takes a key parameter (passing a null handle is "
292
      "ok).")
293
  void Detach();
294
295
  /**
296
   * Detaches this ArrayBuffer and all its views (typed arrays).
297
   * Detaching sets the byte length of the buffer and all typed arrays to zero,
298
   * preventing JavaScript from ever accessing underlying backing store.
299
   * ArrayBuffer should have been externalized and must be detachable. Returns
300
   * Nothing if the key didn't pass the [[ArrayBufferDetachKey]] check,
301
   * Just(true) otherwise.
302
   */
303
  V8_WARN_UNUSED_RESULT Maybe<bool> Detach(v8::Local<v8::Value> key);
304
305
  /**
306
   * Sets the ArrayBufferDetachKey.
307
   */
308
  void SetDetachKey(v8::Local<v8::Value> key);
309
310
  /**
311
   * Get a shared pointer to the backing store of this array buffer. This
312
   * pointer coordinates the lifetime management of the internal storage
313
   * with any live ArrayBuffers on the heap, even across isolates. The embedder
314
   * should not attempt to manage lifetime of the storage through other means.
315
   *
316
   * The returned shared pointer will not be empty, even if the ArrayBuffer has
317
   * been detached. Use |WasDetached| to tell if it has been detached instead.
318
   */
319
  std::shared_ptr<BackingStore> GetBackingStore();
320
321
  /**
322
   * More efficient shortcut for GetBackingStore()->Data(). The returned pointer
323
   * is valid as long as the ArrayBuffer is alive.
324
   */
325
  void* Data() const;
326
327
0
  V8_INLINE static ArrayBuffer* Cast(Value* value) {
328
0
#ifdef V8_ENABLE_CHECKS
329
0
    CheckCast(value);
330
0
#endif
331
0
    return static_cast<ArrayBuffer*>(value);
332
0
  }
333
334
  static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT;
335
  static const int kEmbedderFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT;
336
337
 private:
338
  ArrayBuffer();
339
  static void CheckCast(Value* obj);
340
};
341
342
#ifndef V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT
343
// The number of required internal fields can be defined by embedder.
344
#define V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT 2
345
#endif
346
347
/**
348
 * A base class for an instance of one of "views" over ArrayBuffer,
349
 * including TypedArrays and DataView (ES6 draft 15.13).
350
 */
351
class V8_EXPORT ArrayBufferView : public Object {
352
 public:
353
  /**
354
   * Returns underlying ArrayBuffer.
355
   */
356
  Local<ArrayBuffer> Buffer();
357
  /**
358
   * Byte offset in |Buffer|.
359
   */
360
  size_t ByteOffset();
361
  /**
362
   * Size of a view in bytes.
363
   */
364
  size_t ByteLength();
365
366
  /**
367
   * Copy the contents of the ArrayBufferView's buffer to an embedder defined
368
   * memory without additional overhead that calling ArrayBufferView::Buffer
369
   * might incur.
370
   *
371
   * Will write at most min(|byte_length|, ByteLength) bytes starting at
372
   * ByteOffset of the underlying buffer to the memory starting at |dest|.
373
   * Returns the number of bytes actually written.
374
   */
375
  size_t CopyContents(void* dest, size_t byte_length);
376
377
  /**
378
   * Returns true if ArrayBufferView's backing ArrayBuffer has already been
379
   * allocated.
380
   */
381
  bool HasBuffer() const;
382
383
0
  V8_INLINE static ArrayBufferView* Cast(Value* value) {
384
0
#ifdef V8_ENABLE_CHECKS
385
0
    CheckCast(value);
386
0
#endif
387
0
    return static_cast<ArrayBufferView*>(value);
388
0
  }
389
390
  static const int kInternalFieldCount =
391
      V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT;
392
  static const int kEmbedderFieldCount =
393
      V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT;
394
395
 private:
396
  ArrayBufferView();
397
  static void CheckCast(Value* obj);
398
};
399
400
/**
401
 * An instance of DataView constructor (ES6 draft 15.13.7).
402
 */
403
class V8_EXPORT DataView : public ArrayBufferView {
404
 public:
405
  static Local<DataView> New(Local<ArrayBuffer> array_buffer,
406
                             size_t byte_offset, size_t length);
407
  static Local<DataView> New(Local<SharedArrayBuffer> shared_array_buffer,
408
                             size_t byte_offset, size_t length);
409
0
  V8_INLINE static DataView* Cast(Value* value) {
410
0
#ifdef V8_ENABLE_CHECKS
411
0
    CheckCast(value);
412
0
#endif
413
0
    return static_cast<DataView*>(value);
414
0
  }
415
416
 private:
417
  DataView();
418
  static void CheckCast(Value* obj);
419
};
420
421
/**
422
 * An instance of the built-in SharedArrayBuffer constructor.
423
 */
424
class V8_EXPORT SharedArrayBuffer : public Object {
425
 public:
426
  /**
427
   * Data length in bytes.
428
   */
429
  size_t ByteLength() const;
430
431
  /**
432
   * Maximum length in bytes.
433
   */
434
  size_t MaxByteLength() const;
435
436
  /**
437
   * Create a new SharedArrayBuffer. Allocate |byte_length| bytes.
438
   * Allocated memory will be owned by a created SharedArrayBuffer and
439
   * will be deallocated when it is garbage-collected,
440
   * unless the object is externalized.
441
   */
442
  static Local<SharedArrayBuffer> New(Isolate* isolate, size_t byte_length);
443
444
  /**
445
   * Create a new SharedArrayBuffer with an existing backing store.
446
   * The created array keeps a reference to the backing store until the array
447
   * is garbage collected. Note that the IsExternal bit does not affect this
448
   * reference from the array to the backing store.
449
   *
450
   * In future IsExternal bit will be removed. Until then the bit is set as
451
   * follows. If the backing store does not own the underlying buffer, then
452
   * the array is created in externalized state. Otherwise, the array is created
453
   * in internalized state. In the latter case the array can be transitioned
454
   * to the externalized state using Externalize(backing_store).
455
   */
456
  static Local<SharedArrayBuffer> New(
457
      Isolate* isolate, std::shared_ptr<BackingStore> backing_store);
458
459
  /**
460
   * Returns a new standalone BackingStore that is allocated using the array
461
   * buffer allocator of the isolate. The result can be later passed to
462
   * SharedArrayBuffer::New.
463
   *
464
   * If the allocator returns nullptr, then the function may cause GCs in the
465
   * given isolate and re-try the allocation. If GCs do not help, then the
466
   * function will crash with an out-of-memory error.
467
   */
468
  static std::unique_ptr<BackingStore> NewBackingStore(Isolate* isolate,
469
                                                       size_t byte_length);
470
  /**
471
   * Returns a new standalone BackingStore that takes over the ownership of
472
   * the given buffer. The destructor of the BackingStore invokes the given
473
   * deleter callback.
474
   *
475
   * The result can be later passed to SharedArrayBuffer::New. The raw pointer
476
   * to the buffer must not be passed again to any V8 functions.
477
   */
478
  static std::unique_ptr<BackingStore> NewBackingStore(
479
      void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter,
480
      void* deleter_data);
481
482
  /**
483
   * Get a shared pointer to the backing store of this array buffer. This
484
   * pointer coordinates the lifetime management of the internal storage
485
   * with any live ArrayBuffers on the heap, even across isolates. The embedder
486
   * should not attempt to manage lifetime of the storage through other means.
487
   */
488
  std::shared_ptr<BackingStore> GetBackingStore();
489
490
  /**
491
   * More efficient shortcut for GetBackingStore()->Data(). The returned pointer
492
   * is valid as long as the ArrayBuffer is alive.
493
   */
494
  void* Data() const;
495
496
0
  V8_INLINE static SharedArrayBuffer* Cast(Value* value) {
497
0
#ifdef V8_ENABLE_CHECKS
498
0
    CheckCast(value);
499
0
#endif
500
0
    return static_cast<SharedArrayBuffer*>(value);
501
0
  }
502
503
  static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT;
504
505
 private:
506
  SharedArrayBuffer();
507
  static void CheckCast(Value* obj);
508
};
509
510
}  // namespace v8
511
512
#endif  // INCLUDE_V8_ARRAY_BUFFER_H_