From 67a5a65fb358857c1fd4d71317b67b29eadc44bb Mon Sep 17 00:00:00 2001
From: James M Snell <jasnell@gmail.com>
Date: Tue, 5 May 2020 07:57:40 -0700
Subject: [PATCH] doc: add warnings about transferring Buffers and ArrayBuffer

Signed-off-by: James M Snell <jasnell@gmail.com>
---
 doc/api/worker_threads.md | 46 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/doc/api/worker_threads.md b/doc/api/worker_threads.md
index b3f4aca313bfac..70f1273f3abf06 100644
--- a/doc/api/worker_threads.md
+++ b/doc/api/worker_threads.md
@@ -396,6 +396,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
@@ -767,6 +812,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