tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ArrayBuffer.h (15755B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /* ArrayBuffer functionality. */
      7 
      8 #ifndef js_ArrayBuffer_h
      9 #define js_ArrayBuffer_h
     10 
     11 #include "mozilla/UniquePtr.h"
     12 
     13 #include <stddef.h>  // size_t
     14 #include <stdint.h>  // uint32_t
     15 
     16 #include "jstypes.h"  // JS_PUBLIC_API
     17 #include "js/TypeDecls.h"
     18 #include "js/Utility.h"
     19 
     20 struct JS_PUBLIC_API JSContext;
     21 class JS_PUBLIC_API JSObject;
     22 
     23 namespace JS {
     24 
     25 class JS_PUBLIC_API AutoRequireNoGC;
     26 
     27 // CREATION
     28 
     29 /**
     30 * Create a new ArrayBuffer with the given byte length.
     31 */
     32 extern JS_PUBLIC_API JSObject* NewArrayBuffer(JSContext* cx, size_t nbytes);
     33 
     34 /**
     35 * Create a new ArrayBuffer with the given |contents|, which may be null only
     36 * if |nbytes == 0|.  |contents| must be allocated compatible with deallocation
     37 * by |JS_free|.
     38 *
     39 * Care must be taken that |nbytes| bytes of |contents| remain valid for the
     40 * duration of this call.  In particular, passing the length/pointer of existing
     41 * typed array or ArrayBuffer data is generally unsafe: if a GC occurs during a
     42 * call to this function, it could move those contents to a different location
     43 * and invalidate the provided pointer.
     44 */
     45 extern JS_PUBLIC_API JSObject* NewArrayBufferWithContents(
     46    JSContext* cx, size_t nbytes,
     47    mozilla::UniquePtr<void, JS::FreePolicy> contents);
     48 
     49 /**
     50 * Create a new ArrayBuffer with the given |contents|, which may be null only
     51 * if |nbytes == 0|.  |contents| must be allocated compatible with deallocation
     52 * by |JS_free|.
     53 *
     54 * Care must be taken that |nbytes| bytes of |contents| remain valid for the
     55 * duration of this call.  In particular, passing the length/pointer of existing
     56 * typed array or ArrayBuffer data is generally unsafe: if a GC occurs during a
     57 * call to this function, it could move those contents to a different location
     58 * and invalidate the provided pointer.
     59 */
     60 inline JS_PUBLIC_API JSObject* NewArrayBufferWithContents(
     61    JSContext* cx, size_t nbytes,
     62    mozilla::UniquePtr<char[], JS::FreePolicy> contents) {
     63  // As a convenience, provide an overload for UniquePtr<char[]>.
     64  mozilla::UniquePtr<void, JS::FreePolicy> ptr{contents.release()};
     65  return NewArrayBufferWithContents(cx, nbytes, std::move(ptr));
     66 }
     67 
     68 /**
     69 * Create a new ArrayBuffer with the given |contents|, which may be null only
     70 * if |nbytes == 0|.  |contents| must be allocated compatible with deallocation
     71 * by |JS_free|.
     72 *
     73 * Care must be taken that |nbytes| bytes of |contents| remain valid for the
     74 * duration of this call.  In particular, passing the length/pointer of existing
     75 * typed array or ArrayBuffer data is generally unsafe: if a GC occurs during a
     76 * call to this function, it could move those contents to a different location
     77 * and invalidate the provided pointer.
     78 */
     79 inline JS_PUBLIC_API JSObject* NewArrayBufferWithContents(
     80    JSContext* cx, size_t nbytes,
     81    mozilla::UniquePtr<uint8_t[], JS::FreePolicy> contents) {
     82  // As a convenience, provide an overload for UniquePtr<uint8_t[]>.
     83  mozilla::UniquePtr<void, JS::FreePolicy> ptr{contents.release()};
     84  return NewArrayBufferWithContents(cx, nbytes, std::move(ptr));
     85 }
     86 
     87 /**
     88 * Marker enum to notify callers that the buffer contents must be freed manually
     89 * when the ArrayBuffer allocation failed.
     90 */
     91 enum class NewArrayBufferOutOfMemory { CallerMustFreeMemory };
     92 
     93 /**
     94 * Create a new ArrayBuffer with the given |contents|, which may be null only
     95 * if |nbytes == 0|.  |contents| must be allocated compatible with deallocation
     96 * by |JS_free|.
     97 *
     98 * !!! IMPORTANT !!!
     99 * If and only if an ArrayBuffer is successfully created and returned,
    100 * ownership of |contents| is transferred to the new ArrayBuffer.
    101 *
    102 * Care must be taken that |nbytes| bytes of |contents| remain valid for the
    103 * duration of this call.  In particular, passing the length/pointer of existing
    104 * typed array or ArrayBuffer data is generally unsafe: if a GC occurs during a
    105 * call to this function, it could move those contents to a different location
    106 * and invalidate the provided pointer.
    107 */
    108 extern JS_PUBLIC_API JSObject* NewArrayBufferWithContents(
    109    JSContext* cx, size_t nbytes, void* contents, NewArrayBufferOutOfMemory);
    110 
    111 /**
    112 * Create a new ArrayBuffer, whose bytes are set to the values of the bytes in
    113 * the provided ArrayBuffer.
    114 *
    115 * |maybeArrayBuffer| is asserted to be non-null.  An error is thrown if
    116 * |maybeArrayBuffer| would fail the |IsArrayBufferObject| test given further
    117 * below or if |maybeArrayBuffer| is detached.
    118 *
    119 * |maybeArrayBuffer| may store its contents in any fashion (i.e. it doesn't
    120 * matter whether |maybeArrayBuffer| was allocated using |JS::NewArrayBuffer|,
    121 * |JS::NewExternalArrayBuffer|, or any other ArrayBuffer-allocating function).
    122 *
    123 * The newly-created ArrayBuffer is effectively creatd as if by
    124 * |JS::NewArrayBufferWithContents| passing in |maybeArrayBuffer|'s internal
    125 * data pointer and length, in a manner safe against |maybeArrayBuffer|'s data
    126 * being moved around by the GC.  In particular, the new ArrayBuffer will not
    127 * behave like one created for WASM or asm.js, so it *can* be detached.
    128 */
    129 extern JS_PUBLIC_API JSObject* CopyArrayBuffer(
    130    JSContext* cx, JS::Handle<JSObject*> maybeArrayBuffer);
    131 
    132 using BufferContentsFreeFunc = void (*)(void* contents, void* userData);
    133 
    134 /**
    135 * UniquePtr deleter for external buffer contents.
    136 */
    137 class JS_PUBLIC_API BufferContentsDeleter {
    138  BufferContentsFreeFunc freeFunc_ = nullptr;
    139  void* userData_ = nullptr;
    140 
    141 public:
    142  MOZ_IMPLICIT BufferContentsDeleter(BufferContentsFreeFunc freeFunc,
    143                                     void* userData = nullptr)
    144      : freeFunc_(freeFunc), userData_(userData) {}
    145 
    146  void operator()(void* contents) const { freeFunc_(contents, userData_); }
    147 
    148  BufferContentsFreeFunc freeFunc() const { return freeFunc_; }
    149  void* userData() const { return userData_; }
    150 };
    151 
    152 /**
    153 * Create a new ArrayBuffer with the given contents. The contents must not be
    154 * modified by any other code, internal or external.
    155 *
    156 * When the ArrayBuffer is ready to be disposed of, `freeFunc(contents,
    157 * freeUserData)` will be called to release the ArrayBuffer's reference on the
    158 * contents.
    159 *
    160 * `freeFunc()` must not call any JSAPI functions that could cause a garbage
    161 * collection.
    162 *
    163 * The caller must keep the buffer alive until `freeFunc()` is called, or, if
    164 * `freeFunc` is null, until the JSRuntime is destroyed.
    165 *
    166 * The caller must not access the buffer on other threads. The JS engine will
    167 * not allow the buffer to be transferred to other threads. If you try to
    168 * transfer an external ArrayBuffer to another thread, the data is copied to a
    169 * new malloc buffer. `freeFunc()` must be threadsafe, and may be called from
    170 * any thread.
    171 *
    172 * This allows ArrayBuffers to be used with embedder objects that use reference
    173 * counting, for example. In that case the caller is responsible
    174 * for incrementing the reference count before passing the contents to this
    175 * function. This also allows using non-reference-counted contents that must be
    176 * freed with some function other than free().
    177 */
    178 extern JS_PUBLIC_API JSObject* NewExternalArrayBuffer(
    179    JSContext* cx, size_t nbytes,
    180    mozilla::UniquePtr<void, BufferContentsDeleter> contents);
    181 
    182 /**
    183 * Create a new ArrayBuffer with the given non-null |contents|.
    184 *
    185 * Ownership of |contents| remains with the caller: it isn't transferred to the
    186 * returned ArrayBuffer.  Callers of this function *must* ensure that they
    187 * perform these two steps, in this order, to properly relinquish ownership of
    188 * |contents|:
    189 *
    190 *   1. Call |JS::DetachArrayBuffer| on the buffer returned by this function.
    191 *      (|JS::DetachArrayBuffer| is generally fallible, but a call under these
    192 *      circumstances is guaranteed to succeed.)
    193 *   2. |contents| may be deallocated or discarded consistent with the manner
    194 *      in which it was allocated.
    195 *
    196 * Do not simply allow the returned buffer to be garbage-collected before
    197 * deallocating |contents|, because in general there is no way to know *when*
    198 * an object is fully garbage-collected to the point where this would be safe.
    199 */
    200 extern JS_PUBLIC_API JSObject* NewArrayBufferWithUserOwnedContents(
    201    JSContext* cx, size_t nbytes, void* contents);
    202 
    203 /**
    204 * Create a new mapped ArrayBuffer with the given memory mapped contents. It
    205 * must be legal to free the contents pointer by unmapping it. On success,
    206 * ownership is transferred to the new mapped ArrayBuffer.
    207 */
    208 extern JS_PUBLIC_API JSObject* NewMappedArrayBufferWithContents(JSContext* cx,
    209                                                                size_t nbytes,
    210                                                                void* contents);
    211 
    212 /**
    213 * Create memory mapped ArrayBuffer contents.
    214 * Caller must take care of closing fd after calling this function.
    215 */
    216 extern JS_PUBLIC_API void* CreateMappedArrayBufferContents(int fd,
    217                                                           size_t offset,
    218                                                           size_t length);
    219 
    220 /**
    221 * Release the allocated resource of mapped ArrayBuffer contents before the
    222 * object is created.
    223 * If a new object has been created by JS::NewMappedArrayBufferWithContents()
    224 * with this content, then JS::DetachArrayBuffer() should be used instead to
    225 * release the resource used by the object.
    226 */
    227 extern JS_PUBLIC_API void ReleaseMappedArrayBufferContents(void* contents,
    228                                                           size_t length);
    229 
    230 // TYPE TESTING
    231 
    232 /*
    233 * Check whether obj supports the JS::GetArrayBuffer* APIs.  Note that this may
    234 * return false if a security wrapper is encountered that denies the unwrapping.
    235 * If this test succeeds, then it is safe to call the various predicate and
    236 * accessor JSAPI calls defined below.
    237 */
    238 extern JS_PUBLIC_API bool IsArrayBufferObject(JSObject* obj);
    239 
    240 // PREDICATES
    241 
    242 /**
    243 * Check whether the obj is a detached ArrayBufferObject. Note that this may
    244 * return false if a security wrapper is encountered that denies the
    245 * unwrapping.
    246 */
    247 extern JS_PUBLIC_API bool IsDetachedArrayBufferObject(JSObject* obj);
    248 
    249 /**
    250 * Check whether the obj is ArrayBufferObject and memory mapped. Note that this
    251 * may return false if a security wrapper is encountered that denies the
    252 * unwrapping.
    253 */
    254 extern JS_PUBLIC_API bool IsMappedArrayBufferObject(JSObject* obj);
    255 
    256 /**
    257 * Return true if the ArrayBuffer |obj| contains any data, i.e. it is not a
    258 * detached ArrayBuffer.  (ArrayBuffer.prototype is not an ArrayBuffer.)
    259 *
    260 * |obj| must have passed a JS::IsArrayBufferObject test, or somehow be known
    261 * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
    262 * ArrayBuffer, and the unwrapping will succeed.
    263 */
    264 extern JS_PUBLIC_API bool ArrayBufferHasData(JSObject* obj);
    265 
    266 // ACCESSORS
    267 
    268 extern JS_PUBLIC_API JSObject* UnwrapArrayBuffer(JSObject* obj);
    269 
    270 /**
    271 * Attempt to unwrap |obj| as an ArrayBuffer.
    272 *
    273 * If |obj| *is* an ArrayBuffer, return it unwrapped and set |*length| and
    274 * |*data| to weakly refer to the ArrayBuffer's contents.
    275 *
    276 * If |obj| isn't an ArrayBuffer, return nullptr and do not modify |*length| or
    277 * |*data|.
    278 */
    279 extern JS_PUBLIC_API JSObject* GetObjectAsArrayBuffer(JSObject* obj,
    280                                                      size_t* length,
    281                                                      uint8_t** data);
    282 
    283 /**
    284 * Return the available byte length of an ArrayBuffer.
    285 *
    286 * |obj| must have passed a JS::IsArrayBufferObject test, or somehow be known
    287 * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
    288 * ArrayBuffer, and the unwrapping will succeed.
    289 */
    290 extern JS_PUBLIC_API size_t GetArrayBufferByteLength(JSObject* obj);
    291 
    292 // This one isn't inlined because there are a bunch of different ArrayBuffer
    293 // classes that would have to be individually handled here.
    294 //
    295 // There is an isShared out argument for API consistency (eases use from DOM).
    296 // It will always be set to false.
    297 extern JS_PUBLIC_API void GetArrayBufferLengthAndData(JSObject* obj,
    298                                                      size_t* length,
    299                                                      bool* isSharedMemory,
    300                                                      uint8_t** data);
    301 
    302 /**
    303 * Return a pointer to the start of the data referenced by a typed array. The
    304 * data is still owned by the typed array, and should not be modified on
    305 * another thread. Furthermore, the pointer can become invalid on GC (if the
    306 * data is small and fits inside the array's GC header), so callers must take
    307 * care not to hold on across anything that could GC.
    308 *
    309 * |obj| must have passed a JS::IsArrayBufferObject test, or somehow be known
    310 * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
    311 * ArrayBuffer, and the unwrapping will succeed.
    312 *
    313 * |*isSharedMemory| is always set to false.  The argument is present to
    314 * simplify its use from code that also interacts with SharedArrayBuffer.
    315 */
    316 extern JS_PUBLIC_API uint8_t* GetArrayBufferData(JSObject* obj,
    317                                                 bool* isSharedMemory,
    318                                                 const AutoRequireNoGC&);
    319 
    320 // MUTATORS
    321 
    322 /**
    323 * Detach an ArrayBuffer, causing all associated views to no longer refer to
    324 * the ArrayBuffer's original attached memory.
    325 *
    326 * This function throws only if it is provided a non-ArrayBuffer object or if
    327 * the provided ArrayBuffer is a WASM-backed ArrayBuffer or an ArrayBuffer used
    328 * in asm.js code.
    329 */
    330 extern JS_PUBLIC_API bool DetachArrayBuffer(JSContext* cx,
    331                                            Handle<JSObject*> obj);
    332 
    333 // Indicates if an object has a defined [[ArrayBufferDetachKey]] internal slot,
    334 // which indicates an ArrayBuffer cannot be detached
    335 extern JS_PUBLIC_API bool HasDefinedArrayBufferDetachKey(JSContext* cx,
    336                                                         Handle<JSObject*> obj,
    337                                                         bool* isDefined);
    338 
    339 /**
    340 * Steal the contents of the given ArrayBuffer. The ArrayBuffer has its length
    341 * set to 0 and its contents array cleared. The caller takes ownership of the
    342 * return value and must free it or transfer ownership via
    343 * JS::NewArrayBufferWithContents when done using it.
    344 */
    345 extern JS_PUBLIC_API void* StealArrayBufferContents(JSContext* cx,
    346                                                    Handle<JSObject*> obj);
    347 
    348 /**
    349 * Copy data from one array buffer to another.
    350 *
    351 * Both fromBuffer and toBuffer must be (possibly wrapped)
    352 * ArrayBufferObjectMaybeShared.
    353 *
    354 * This method may throw if the sizes don't match, or if unwrapping fails.
    355 *
    356 * The API for this is modelled on CopyDataBlockBytes from the spec:
    357 * https://tc39.es/ecma262/#sec-copydatablockbytes
    358 */
    359 [[nodiscard]] extern JS_PUBLIC_API bool ArrayBufferCopyData(
    360    JSContext* cx, Handle<JSObject*> toBlock, size_t toIndex,
    361    Handle<JSObject*> fromBlock, size_t fromIndex, size_t count);
    362 
    363 /**
    364 * Copy data from one array buffer to another.
    365 *
    366 * srcBuffer must be a (possibly wrapped) ArrayBufferObjectMaybeShared.
    367 *
    368 * This method may throw if unwrapping or allocation fails.
    369 *
    370 * The API for this is modelled on CloneArrayBuffer from the spec:
    371 * https://tc39.es/ecma262/#sec-clonearraybuffer
    372 */
    373 extern JS_PUBLIC_API JSObject* ArrayBufferClone(JSContext* cx,
    374                                                Handle<JSObject*> srcBuffer,
    375                                                size_t srcByteOffset,
    376                                                size_t srcLength);
    377 
    378 }  // namespace JS
    379 
    380 #endif /* js_ArrayBuffer_h */