Skip to content

Commit 81df668

Browse files
addaleaxjasnell
authored andcommitted
worker: do not crash when JSTransferable lists untransferable value
This can currently be triggered when posting a closing FileHandle. Refs: #34746 (comment) PR-URL: #34766 Reviewed-By: Richard Lau <[email protected]> Reviewed-By: David Carlier <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 5835367 commit 81df668

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

src/node_messaging.cc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -343,18 +343,20 @@ class SerializerDelegate : public ValueSerializer::Delegate {
343343

344344
private:
345345
Maybe<bool> WriteHostObject(BaseObjectPtr<BaseObject> host_object) {
346+
BaseObject::TransferMode mode = host_object->GetTransferMode();
347+
if (mode == BaseObject::TransferMode::kUntransferable) {
348+
ThrowDataCloneError(env_->clone_unsupported_type_str());
349+
return Nothing<bool>();
350+
}
351+
346352
for (uint32_t i = 0; i < host_objects_.size(); i++) {
347353
if (host_objects_[i] == host_object) {
348354
serializer->WriteUint32(i);
349355
return Just(true);
350356
}
351357
}
352358

353-
BaseObject::TransferMode mode = host_object->GetTransferMode();
354-
if (mode == BaseObject::TransferMode::kUntransferable) {
355-
ThrowDataCloneError(env_->clone_unsupported_type_str());
356-
return Nothing<bool>();
357-
} else if (mode == BaseObject::TransferMode::kTransferable) {
359+
if (mode == BaseObject::TransferMode::kTransferable) {
358360
THROW_ERR_MISSING_TRANSFERABLE_IN_TRANSFER_LIST(env_);
359361
return Nothing<bool>();
360362
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Flags: --expose-internals --no-warnings
2+
'use strict';
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const {
6+
JSTransferable, kTransfer, kTransferList
7+
} = require('internal/worker/js_transferable');
8+
const { MessageChannel } = require('worker_threads');
9+
10+
// Transferring a JSTransferable that refers to another, untransferable, value
11+
// in its transfer list should not crash hard.
12+
13+
class OuterTransferable extends JSTransferable {
14+
constructor() {
15+
super();
16+
// Create a detached MessagePort at this.inner
17+
const c = new MessageChannel();
18+
this.inner = c.port1;
19+
c.port2.postMessage(this.inner, [ this.inner ]);
20+
}
21+
22+
[kTransferList] = common.mustCall(() => {
23+
return [ this.inner ];
24+
});
25+
26+
[kTransfer] = common.mustCall(() => {
27+
return {
28+
data: { inner: this.inner },
29+
deserializeInfo: 'does-not:matter'
30+
};
31+
});
32+
}
33+
34+
const { port1 } = new MessageChannel();
35+
const ot = new OuterTransferable();
36+
assert.throws(() => {
37+
port1.postMessage(ot, [ot]);
38+
}, { name: 'DataCloneError' });

0 commit comments

Comments
 (0)