Skip to content

Commit

Permalink
doc: add warnings about transferring Buffers and ArrayBuffer
Browse files Browse the repository at this point in the history
Signed-off-by: James M Snell <[email protected]>

PR-URL: #33252
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Mathias Buus <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Juan José Arboleda <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
  • Loading branch information
jasnell authored and codebytere committed Jun 7, 2020
1 parent 82da74b commit ac5cdd6
Showing 1 changed file with 46 additions and 0 deletions.
46 changes: 46 additions & 0 deletions doc/api/worker_threads.md
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,51 @@ posting without having side effects.
For more information on the serialization and deserialization mechanisms
behind this API, see the [serialization API of the `v8` module][v8.serdes].

#### Considerations when transferring TypedArrays and Buffers

All `TypedArray` and `Buffer` instances are views over an underlying
`ArrayBuffer`. That is, it is the `ArrayBuffer` that actually stores
the raw data while the `TypedArray` and `Buffer` objects provide a
way of viewing and manipulating the data. It is possible and common
for multiple views to be created over the same `ArrayBuffer` instance.
Great care must be taken when using a transfer list to transfer an
`ArrayBuffer` as doing so will cause all `TypedArray` and `Buffer`
instances that share that same `ArrayBuffer` to become unusable.

```js
const ab = new ArrayBuffer(10);

const u1 = new Uint8Array(ab);
const u2 = new Uint16Array(ab);

console.log(u2.length); // prints 5

port.postMessage(u1, [u1.buffer]);

console.log(u2.length); // prints 0
```

For `Buffer` instances, specifically, whether the underlying
`ArrayBuffer` can be transferred or cloned depends entirely on how
instances were created, which often cannot be reliably determined.

Depending on how a `Buffer` instance was created, it may or may
not own its underlying `ArrayBuffer`. An `ArrayBuffer` must not
be transferred unless it is known that the `Buffer` instance
owns it. In particular, for `Buffer`s created from the internal
`Buffer` pool (using, for instance `Buffer.from()` or `Buffer.alloc()`),
transferring them is not possible and they will always be cloned,
which sends a copy of the entire `Buffer` pool.
This behavior may come with unintended higher memory
usage and possible security concerns.

See [`Buffer.allocUnsafe()`][] for more details on `Buffer` pooling.

The `ArrayBuffer`s for `Buffer` instances created using
`Buffer.alloc()` or `Buffer.allocUnsafeSlow()` can always be
transferred but doing so will render all other existing views of
those `ArrayBuffer`s unusable.

### `port.ref()`
<!-- YAML
added: v10.5.0
Expand Down Expand Up @@ -754,6 +799,7 @@ active handle in the event system. If the worker is already `unref()`ed calling
[`'exit'` event]: #worker_threads_event_exit
[`AsyncResource`]: async_hooks.html#async_hooks_class_asyncresource
[`Buffer`]: buffer.html
[`Buffer.allocUnsafe()`]: buffer.html#buffer_class_method_buffer_allocunsafe_size
[`ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST`]: errors.html#errors_err_missing_message_port_in_transfer_list
[`ERR_WORKER_NOT_RUNNING`]: errors.html#ERR_WORKER_NOT_RUNNING
[`EventEmitter`]: events.html
Expand Down

0 comments on commit ac5cdd6

Please sign in to comment.