Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 8759db9

Browse filesBrowse files
legendecasaduh95
authored andcommitted
buffer: disallow ArrayBuffer transfer on pooled buffer
PR-URL: #61372 Fixes: #61362 Refs: v8/v8@c5ff7c4 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
1 parent 780e65c commit 8759db9
Copy full SHA for 8759db9

6 files changed

+45Lines changed: 45 additions & 0 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎doc/api/worker_threads.md‎

Copy file name to clipboardExpand all lines: doc/api/worker_threads.md
+2Lines changed: 2 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ In particular, this makes sense for objects that can be cloned, rather than
256256
transferred, and which are used by other objects on the sending side.
257257
For example, Node.js marks the `ArrayBuffer`s it uses for its
258258
[`Buffer` pool][`Buffer.allocUnsafe()`] with this.
259+
`ArrayBuffer.prototype.transfer()` is disallowed on such array buffer
260+
instances.
259261
260262
This operation cannot be undone.
261263
Collapse file

‎lib/buffer.js‎

Copy file name to clipboardExpand all lines: lib/buffer.js
+14Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,13 @@ const {
143143
utf8Write,
144144
} = require('internal/buffer');
145145

146+
const {
147+
namespace: {
148+
addDeserializeCallback,
149+
isBuildingSnapshot,
150+
},
151+
} = require('internal/v8/startup_snapshot');
152+
146153
FastBuffer.prototype.constructor = Buffer;
147154
Buffer.prototype = FastBuffer.prototype;
148155
addBufferPrototypeMethods(Buffer.prototype);
@@ -173,6 +180,13 @@ function createPool() {
173180
poolOffset = 0;
174181
}
175182
createPool();
183+
if (isBuildingSnapshot()) {
184+
addDeserializeCallback(() => {
185+
// TODO(legendecas): ArrayBuffer.[[ArrayBufferDetachKey]] is not been serialized.
186+
// Remove this callback when snapshot serialization supports it.
187+
createPool();
188+
});
189+
}
176190

177191
function alignPool() {
178192
// Ensure aligned slices
Collapse file

‎lib/internal/buffer.js‎

Copy file name to clipboardExpand all lines: lib/internal/buffer.js
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const {
66
Float64Array,
77
MathFloor,
88
Number,
9+
Symbol,
910
Uint8Array,
1011
} = primordials;
1112

@@ -15,6 +16,8 @@ const {
1516
ERR_OUT_OF_RANGE,
1617
} = require('internal/errors').codes;
1718
const { validateNumber } = require('internal/validators');
19+
const { isArrayBuffer } = require('util/types');
20+
1821
const {
1922
asciiSlice,
2023
base64Slice,
@@ -31,6 +34,7 @@ const {
3134
ucs2Write,
3235
utf8WriteStatic,
3336
createUnsafeArrayBuffer,
37+
setDetachKey,
3438
} = internalBinding('buffer');
3539

3640
const {
@@ -1068,12 +1072,17 @@ function addBufferPrototypeMethods(proto) {
10681072
proto.utf8Write = function(string, offset, length) { return utf8Write(this, string, offset, length); };
10691073
}
10701074

1075+
const kDetachKey = Symbol('detach_key_for_untransferable_arraybuffer');
10711076
// This would better be placed in internal/worker/io.js, but that doesn't work
10721077
// because Buffer needs this and that would introduce a cyclic dependency.
10731078
function markAsUntransferable(obj) {
10741079
if ((typeof obj !== 'object' && typeof obj !== 'function') || obj === null)
10751080
return; // This object is a primitive and therefore already untransferable.
10761081
obj[untransferable_object_private_symbol] = true;
1082+
1083+
if (isArrayBuffer(obj)) {
1084+
setDetachKey(obj, kDetachKey);
1085+
}
10771086
}
10781087

10791088
// This simply checks if the object is marked as untransferable and doesn't
Collapse file

‎src/node_buffer.cc‎

Copy file name to clipboardExpand all lines: src/node_buffer.cc
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,15 @@ static void Atob(const FunctionCallbackInfo<Value>& args) {
13771377
args.GetReturnValue().Set(error_code);
13781378
}
13791379

1380+
static void SetDetachKey(const FunctionCallbackInfo<Value>& args) {
1381+
CHECK_EQ(args.Length(), 2);
1382+
CHECK(args[0]->IsArrayBuffer());
1383+
1384+
Local<ArrayBuffer> ab = args[0].As<ArrayBuffer>();
1385+
Local<Value> key = args[1];
1386+
ab->SetDetachKey(key);
1387+
}
1388+
13801389
namespace {
13811390

13821391
std::pair<void*, size_t> DecomposeBufferToParts(Local<Value> buffer) {
@@ -1661,6 +1670,8 @@ void Initialize(Local<Object> target,
16611670
"utf8WriteStatic",
16621671
SlowWriteString<UTF8>,
16631672
&fast_write_string_utf8);
1673+
1674+
SetMethod(context, target, "setDetachKey", SetDetachKey);
16641675
}
16651676

16661677
} // anonymous namespace
@@ -1715,6 +1726,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
17151726

17161727
registry->Register(Atob);
17171728
registry->Register(Btoa);
1729+
1730+
registry->Register(SetDetachKey);
17181731
}
17191732

17201733
} // namespace Buffer
Collapse file

‎test/parallel/test-bootstrap-modules.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-bootstrap-modules.js
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ expected.beforePreExec = new Set([
5151
'NativeModule events',
5252
'Internal Binding buffer',
5353
'Internal Binding string_decoder',
54+
'NativeModule util/types',
5455
'NativeModule internal/buffer',
5556
'NativeModule buffer',
5657
'Internal Binding messaging',
Collapse file

‎test/parallel/test-buffer-pool-untransferable.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-buffer-pool-untransferable.js
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,9 @@ assert.throws(() => port1.postMessage(a, [ a.buffer ]), {
2121
// Verify that the pool ArrayBuffer has not actually been transferred:
2222
assert.strictEqual(a.buffer, b.buffer);
2323
assert.strictEqual(a.length, length);
24+
25+
// Verify that ArrayBuffer.prototype.transfer() also throws.
26+
assert.throws(() => a.buffer.transfer(), {
27+
name: 'TypeError',
28+
});
29+
assert.strictEqual(a.buffer, b.buffer);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.