Skip to content

Commit 4b3bd89

Browse files
committed
src,lib: mark URL/URLSearchParams as untransferrable
1 parent 4765038 commit 4b3bd89

File tree

13 files changed

+149
-56
lines changed

13 files changed

+149
-56
lines changed

lib/buffer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ const {
8585
normalizeEncoding,
8686
kIsEncodingSymbol,
8787
defineLazyProperties,
88+
markAsUntransferable,
8889
} = require('internal/util');
8990
const {
9091
isAnyArrayBuffer,
@@ -123,7 +124,6 @@ const validateOffset = (value, name, min = 0, max = kMaxLength) =>
123124

124125
const {
125126
FastBuffer,
126-
markAsUntransferable,
127127
addBufferPrototypeMethods,
128128
createUnsafeBuffer,
129129
} = require('internal/buffer');

lib/internal/buffer.js

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,6 @@ const {
3333
getZeroFillToggle,
3434
} = internalBinding('buffer');
3535

36-
const {
37-
privateSymbols: {
38-
untransferable_object_private_symbol,
39-
},
40-
} = internalBinding('util');
41-
4236
// Temporary buffers to convert numbers.
4337
const float32Array = new Float32Array(1);
4438
const uInt8Float32Array = new Uint8Array(float32Array.buffer);
@@ -1045,14 +1039,6 @@ function addBufferPrototypeMethods(proto) {
10451039
proto.utf8Write = utf8Write;
10461040
}
10471041

1048-
// This would better be placed in internal/worker/io.js, but that doesn't work
1049-
// because Buffer needs this and that would introduce a cyclic dependency.
1050-
function markAsUntransferable(obj) {
1051-
if ((typeof obj !== 'object' && typeof obj !== 'function') || obj === null)
1052-
return; // This object is a primitive and therefore already untransferable.
1053-
obj[untransferable_object_private_symbol] = true;
1054-
}
1055-
10561042
// A toggle used to access the zero fill setting of the array buffer allocator
10571043
// in C++.
10581044
// |zeroFill| can be undefined when running inside an isolate where we
@@ -1078,7 +1064,6 @@ function reconnectZeroFillToggle() {
10781064
module.exports = {
10791065
FastBuffer,
10801066
addBufferPrototypeMethods,
1081-
markAsUntransferable,
10821067
createUnsafeBuffer,
10831068
readUInt16BE,
10841069
readUInt32BE,

lib/internal/url.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ const {
4545
toUSVString,
4646
kEnumerableProperty,
4747
SideEffectFreeRegExpPrototypeSymbolReplace,
48+
markAsUncloneable,
4849
} = require('internal/util');
4950

5051
const {
@@ -376,6 +377,8 @@ class URLSearchParams {
376377
init = toUSVString(init);
377378
this.#searchParams = init ? parseParams(init) : [];
378379
}
380+
381+
markAsUncloneable(this);
379382
}
380383

381384
[inspect.custom](recurseTimes, ctx) {
@@ -720,6 +723,8 @@ class URL {
720723
}
721724

722725
this.#updateContext(href);
726+
727+
markAsUncloneable(this);
723728
}
724729

725730
[inspect.custom](depth, opts) {

lib/internal/util.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ const {
5757
privateSymbols: {
5858
arrow_message_private_symbol,
5959
decorated_private_symbol,
60+
transfer_mode_private_symbol,
61+
},
62+
constants: {
63+
kUncloneable,
64+
kCloneable,
6065
},
6166
sleep: _sleep,
6267
toUSVString: _toUSVString,
@@ -789,6 +794,24 @@ function setupCoverageHooks(dir) {
789794
return coverageDirectory;
790795
}
791796

797+
// This would better be placed in internal/worker/io.js, but that doesn't work
798+
// because Buffer needs this and that would introduce a cyclic dependency.
799+
// Mark the object as untransferable. If object occurs in the transfer list of
800+
// a port.postMessage() call, it is ignored.
801+
function markAsUntransferable(obj) {
802+
if ((typeof obj !== 'object' && typeof obj !== 'function') || obj === null)
803+
return; // This value is a primitive and therefore already cloneable.
804+
obj[transfer_mode_private_symbol] = kCloneable;
805+
}
806+
807+
// Mark the object as uncloneable. If object occurs in the value of a
808+
// port.postMessage() call, an error is thrown.
809+
function markAsUncloneable(obj) {
810+
if ((typeof obj !== 'object' && typeof obj !== 'function') || obj === null)
811+
return; // This value is a primitive and therefore already cloneable.
812+
obj[transfer_mode_private_symbol] = kUncloneable;
813+
}
814+
792815
module.exports = {
793816
getLazy,
794817
assertCrypto,
@@ -818,6 +841,8 @@ module.exports = {
818841
join,
819842
lazyDOMException,
820843
lazyDOMExceptionClass,
844+
markAsUntransferable,
845+
markAsUncloneable,
821846
normalizeEncoding,
822847
once,
823848
promisify,

lib/worker_threads.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const {
2020

2121
const {
2222
markAsUntransferable,
23-
} = require('internal/buffer');
23+
} = require('internal/util');
2424

2525
module.exports = {
2626
isMainThread,

src/base_object.h

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,11 @@ class BaseObject : public MemoryRetainer {
135135
// method of MessagePorts (and, by extension, Workers).
136136
// GetTransferMode() returns a transfer mode that indicates how to deal with
137137
// the current object:
138-
// - kUntransferable:
139-
// No transfer is possible, either because this type of BaseObject does
140-
// not know how to be transferred, or because it is not in a state in
141-
// which it is possible to do so (e.g. because it has already been
142-
// transferred).
138+
// - kUncloneable:
139+
// No transfer or clone is possible, either because this type of
140+
// BaseObject does not know how to be transferred, or because it is not
141+
// in a state in which it is possible to do so (e.g. because it has
142+
// already been transferred).
143143
// - kTransferable:
144144
// This object can be transferred in a destructive fashion, i.e. will be
145145
// rendered unusable on the sending side of the channel in the process
@@ -160,11 +160,7 @@ class BaseObject : public MemoryRetainer {
160160
// After a successful clone, FinalizeTransferRead() is called on the receiving
161161
// end, and can read deserialize JS data possibly serialized by a previous
162162
// FinalizeTransferWrite() call.
163-
enum class TransferMode {
164-
kUntransferable,
165-
kTransferable,
166-
kCloneable
167-
};
163+
enum class TransferMode : uint8_t { kUncloneable, kTransferable, kCloneable };
168164
virtual TransferMode GetTransferMode() const;
169165
virtual std::unique_ptr<worker::TransferData> TransferForMessaging();
170166
virtual std::unique_ptr<worker::TransferData> CloneForMessaging() const;

src/env_properties.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
V(arrow_message_private_symbol, "node:arrowMessage") \
2222
V(contextify_context_private_symbol, "node:contextify:context") \
2323
V(decorated_private_symbol, "node:decorated") \
24+
V(transfer_mode_private_symbol, "node:transfer_mode") \
2425
V(napi_type_tag, "node:napi:type_tag") \
2526
V(napi_wrapper, "node:napi:wrapper") \
26-
V(untransferable_object_private_symbol, "node:untransferableObject") \
2727
V(exit_info_private_symbol, "node:exit_info_private_symbol") \
2828
V(require_private_symbol, "node:require_private_symbol")
2929

src/node_api.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "async_wrap-inl.h"
22
#include "env-inl.h"
33
#define NAPI_EXPERIMENTAL
4+
#include "base_object.h"
45
#include "js_native_api_v8.h"
56
#include "memory_tracker-inl.h"
67
#include "node_api.h"
@@ -37,9 +38,12 @@ bool node_napi_env__::can_call_into_js() const {
3738

3839
v8::Maybe<bool> node_napi_env__::mark_arraybuffer_as_untransferable(
3940
v8::Local<v8::ArrayBuffer> ab) const {
40-
return ab->SetPrivate(context(),
41-
node_env()->untransferable_object_private_symbol(),
42-
v8::True(isolate));
41+
return ab->SetPrivate(
42+
context(),
43+
node_env()->transfer_mode_private_symbol(),
44+
v8::Integer::New(
45+
isolate,
46+
static_cast<int32_t>(node::BaseObject::TransferMode::kCloneable)));
4347
}
4448

4549
void node_napi_env__::CallFinalizer(napi_finalize cb, void* data, void* hint) {

src/node_buffer.cc

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -459,8 +459,11 @@ MaybeLocal<Object> New(Environment* env,
459459
Local<ArrayBuffer> ab =
460460
CallbackInfo::CreateTrackedArrayBuffer(env, data, length, callback, hint);
461461
if (ab->SetPrivate(env->context(),
462-
env->untransferable_object_private_symbol(),
463-
True(env->isolate())).IsNothing()) {
462+
env->transfer_mode_private_symbol(),
463+
Integer::New(env->isolate(),
464+
static_cast<int32_t>(
465+
BaseObject::TransferMode::kCloneable)))
466+
.IsNothing()) {
464467
return Local<Object>();
465468
}
466469
MaybeLocal<Uint8Array> maybe_ui = Buffer::New(env, ab, 0, length);
@@ -1181,10 +1184,12 @@ void GetZeroFillToggle(const FunctionCallbackInfo<Value>& args) {
11811184
ab = ArrayBuffer::New(env->isolate(), std::move(backing));
11821185
}
11831186

1184-
ab->SetPrivate(
1185-
env->context(),
1186-
env->untransferable_object_private_symbol(),
1187-
True(env->isolate())).Check();
1187+
ab->SetPrivate(env->context(),
1188+
env->transfer_mode_private_symbol(),
1189+
Integer::New(env->isolate(),
1190+
static_cast<int32_t>(
1191+
BaseObject::TransferMode::kCloneable)))
1192+
.Check();
11881193

11891194
args.GetReturnValue().Set(Uint32Array::New(ab, 0, 1));
11901195
}

src/node_file.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -300,12 +300,12 @@ void FileHandle::MemoryInfo(MemoryTracker* tracker) const {
300300
}
301301

302302
FileHandle::TransferMode FileHandle::GetTransferMode() const {
303-
return reading_ || closing_ || closed_ ?
304-
TransferMode::kUntransferable : TransferMode::kTransferable;
303+
return reading_ || closing_ || closed_ ? TransferMode::kUncloneable
304+
: TransferMode::kTransferable;
305305
}
306306

307307
std::unique_ptr<worker::TransferData> FileHandle::TransferForMessaging() {
308-
CHECK_NE(GetTransferMode(), TransferMode::kUntransferable);
308+
CHECK_NE(GetTransferMode(), TransferMode::kUncloneable);
309309
auto ret = std::make_unique<TransferData>(fd_);
310310
closed_ = true;
311311
return ret;

0 commit comments

Comments
 (0)