Skip to content

Commit 2aa2331

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

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
@@ -342,18 +342,20 @@ class SerializerDelegate : public ValueSerializer::Delegate {
342342

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

352-
BaseObject::TransferMode mode = host_object->GetTransferMode();
353-
if (mode == BaseObject::TransferMode::kUntransferable) {
354-
ThrowDataCloneError(env_->clone_unsupported_type_str());
355-
return Nothing<bool>();
356-
} else if (mode == BaseObject::TransferMode::kTransferable) {
358+
if (mode == BaseObject::TransferMode::kTransferable) {
357359
// TODO(addaleax): This message code is too specific. Fix that in a
358360
// semver-major follow-up.
359361
THROW_ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST(env_);
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)