@@ -6,84 +6,27 @@ Subject: support V8 sandboxed pointers
66This refactors several allocators to allocate within the V8 memory cage,
77allowing them to be compatible with the V8_SANDBOXED_POINTERS feature.
88
9- diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js
10- index 4c459b58b5a048d9d8a4f15f4011e7cce68089f4..6fb4c8d4567aee5b313ad621ea42699a196f18c7 100644
11- --- a/lib/internal/bootstrap/pre_execution.js
12- +++ b/lib/internal/bootstrap/pre_execution.js
13- @@ -14,7 +14,6 @@ const {
14- getOptionValue,
15- getEmbedderOptions,
16- } = require('internal/options');
17- -const { reconnectZeroFillToggle } = require('internal/buffer');
18- const {
19- defineOperation,
20- emitExperimentalWarning,
21- @@ -26,10 +25,6 @@ const { ERR_MANIFEST_ASSERT_INTEGRITY } = require('internal/errors').codes;
22- const assert = require('internal/assert');
23-
24- function prepareMainThreadExecution(expandArgv1 = false) {
25- - // TODO(joyeecheung): this is also necessary for workers when they deserialize
26- - // this toggle from the snapshot.
27- - reconnectZeroFillToggle();
28- -
29- // Patch the process object with legacy properties and normalizations
30- patchProcessObject(expandArgv1);
31- setupTraceCategoryState();
32- diff --git a/lib/internal/buffer.js b/lib/internal/buffer.js
33- index bd38cf48a7fc6e8d61d8f11fa15c34aee182cbe3..1aa071cdc071dcdaf5c3b4bed0d3d76e5871731d 100644
34- --- a/lib/internal/buffer.js
35- +++ b/lib/internal/buffer.js
36- @@ -30,7 +30,7 @@ const {
37- hexWrite,
38- ucs2Write,
39- utf8Write,
40- - getZeroFillToggle
41- + setZeroFillToggle
42- } = internalBinding('buffer');
43- const {
44- untransferable_object_private_symbol,
45- @@ -1055,24 +1055,15 @@ function markAsUntransferable(obj) {
46- // in C++.
47- // |zeroFill| can be undefined when running inside an isolate where we
48- // do not own the ArrayBuffer allocator. Zero fill is always on in that case.
49- -let zeroFill = getZeroFillToggle();
50- function createUnsafeBuffer(size) {
51- - zeroFill[0] = 0;
52- + setZeroFillToggle(false);
53- try {
54- return new FastBuffer(size);
55- } finally {
56- - zeroFill[0] = 1;
57- + setZeroFillToggle(true)
58- }
59- }
60-
61- -// The connection between the JS land zero fill toggle and the
62- -// C++ one in the NodeArrayBufferAllocator gets lost if the toggle
63- -// is deserialized from the snapshot, because V8 owns the underlying
64- -// memory of this toggle. This resets the connection.
65- -function reconnectZeroFillToggle() {
66- - zeroFill = getZeroFillToggle();
67- -}
68- -
69- module.exports = {
70- FastBuffer,
71- addBufferPrototypeMethods,
72- @@ -1080,5 +1071,4 @@ module.exports = {
73- createUnsafeBuffer,
74- readUInt16BE,
75- readUInt32BE,
76- - reconnectZeroFillToggle
77- };
789diff --git a/src/api/environment.cc b/src/api/environment.cc
79- index 2abf5994405e8da2a04d1b23b75ccd3658398474..024d612a04d83583b397549589d994e32cf0107f 100644
10+ index 2abf5994405e8da2a04d1b23b75ccd3658398474..b06e8529bb8ca2fa6d7f0735531bbbf39da6af12 100644
8011--- a/src/api/environment.cc
8112+++ b/src/api/environment.cc
82- @@ -83,16 +83,16 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
13+ @@ -80,19 +80,27 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
14+ return result;
15+ }
16+
17+ +NodeArrayBufferAllocator::NodeArrayBufferAllocator() {
18+ + zero_fill_field_ = static_cast<uint32_t*>(allocator_->Allocate(sizeof(*zero_fill_field_)));
19+ +}
20+ +
21+ +NodeArrayBufferAllocator::~NodeArrayBufferAllocator() {
22+ + allocator_->Free(zero_fill_field_, sizeof(*zero_fill_field_));
23+ +}
24+ +
8325 void* NodeArrayBufferAllocator::Allocate(size_t size) {
8426 void* ret;
85- if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
27+ - if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
8628- ret = UncheckedCalloc(size);
29+ + if (*zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
8730+ ret = allocator_->Allocate(size);
8831 else
8932- ret = UncheckedMalloc(size);
@@ -99,7 +42,7 @@ index 2abf5994405e8da2a04d1b23b75ccd3658398474..024d612a04d83583b397549589d994e3
9942 if (LIKELY(ret != nullptr))
10043 total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
10144 return ret;
102- @@ -100,7 +100 ,7 @@ void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
45+ @@ -100,7 +108 ,7 @@ void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
10346
10447 void* NodeArrayBufferAllocator::Reallocate(
10548 void* data, size_t old_size, size_t size) {
@@ -108,7 +51,7 @@ index 2abf5994405e8da2a04d1b23b75ccd3658398474..024d612a04d83583b397549589d994e3
10851 if (LIKELY(ret != nullptr) || UNLIKELY(size == 0))
10952 total_mem_usage_.fetch_add(size - old_size, std::memory_order_relaxed);
11053 return ret;
111- @@ -108,7 +108 ,7 @@ void* NodeArrayBufferAllocator::Reallocate(
54+ @@ -108,7 +116 ,7 @@ void* NodeArrayBufferAllocator::Reallocate(
11255
11356 void NodeArrayBufferAllocator::Free(void* data, size_t size) {
11457 total_mem_usage_.fetch_sub(size, std::memory_order_relaxed);
@@ -209,65 +152,6 @@ index c431159e6f77f8c86844bcadb86012b056d03372..9f57ac58d826cb0aae422ddca54e2136
209152
210153 v8::Local<v8::ArrayBuffer> ToArrayBuffer(Environment* env);
211154
212- diff --git a/src/node_buffer.cc b/src/node_buffer.cc
213- index 215bd8003aabe17e43ac780c723cfe971b437eae..eb00eb6f592e20f3c17a529f30b09673774eb1c1 100644
214- --- a/src/node_buffer.cc
215- +++ b/src/node_buffer.cc
216- @@ -1175,33 +1175,14 @@ void SetBufferPrototype(const FunctionCallbackInfo<Value>& args) {
217- env->set_buffer_prototype_object(proto);
218- }
219-
220- -void GetZeroFillToggle(const FunctionCallbackInfo<Value>& args) {
221- +void SetZeroFillToggle(const FunctionCallbackInfo<Value>& args) {
222- Environment* env = Environment::GetCurrent(args);
223- NodeArrayBufferAllocator* allocator = env->isolate_data()->node_allocator();
224- Local<ArrayBuffer> ab;
225- - // It can be a nullptr when running inside an isolate where we
226- - // do not own the ArrayBuffer allocator.
227- - if (allocator == nullptr) {
228- - // Create a dummy Uint32Array - the JS land can only toggle the C++ land
229- - // setting when the allocator uses our toggle. With this the toggle in JS
230- - // land results in no-ops.
231- - ab = ArrayBuffer::New(env->isolate(), sizeof(uint32_t));
232- - } else {
233- + if (allocator != nullptr) {
234- uint32_t* zero_fill_field = allocator->zero_fill_field();
235- - std::unique_ptr<BackingStore> backing =
236- - ArrayBuffer::NewBackingStore(zero_fill_field,
237- - sizeof(*zero_fill_field),
238- - [](void*, size_t, void*) {},
239- - nullptr);
240- - ab = ArrayBuffer::New(env->isolate(), std::move(backing));
241- + *zero_fill_field = args[0]->BooleanValue(env->isolate());
242- }
243- -
244- - ab->SetPrivate(
245- - env->context(),
246- - env->untransferable_object_private_symbol(),
247- - True(env->isolate())).Check();
248- -
249- - args.GetReturnValue().Set(Uint32Array::New(ab, 0, 1));
250- }
251-
252- void DetachArrayBuffer(const FunctionCallbackInfo<Value>& args) {
253- @@ -1310,7 +1291,7 @@ void Initialize(Local<Object> target,
254- env->SetMethod(target, "ucs2Write", StringWrite<UCS2>);
255- env->SetMethod(target, "utf8Write", StringWrite<UTF8>);
256-
257- - env->SetMethod(target, "getZeroFillToggle", GetZeroFillToggle);
258- + env->SetMethod(target, "setZeroFillToggle", SetZeroFillToggle);
259- }
260-
261- } // anonymous namespace
262- @@ -1350,7 +1331,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
263- registry->Register(StringWrite<HEX>);
264- registry->Register(StringWrite<UCS2>);
265- registry->Register(StringWrite<UTF8>);
266- - registry->Register(GetZeroFillToggle);
267- + registry->Register(SetZeroFillToggle);
268-
269- registry->Register(DetachArrayBuffer);
270- registry->Register(CopyArrayBuffer);
271155diff --git a/src/node_i18n.cc b/src/node_i18n.cc
272156index c537a247f55ff070da1988fc8b7309b5692b5c18..59bfb597849cd5a94800d6c83b238ef77245243e 100644
273157--- a/src/node_i18n.cc
@@ -282,12 +166,26 @@ index c537a247f55ff070da1988fc8b7309b5692b5c18..59bfb597849cd5a94800d6c83b238ef7
282166 return ret;
283167
284168diff --git a/src/node_internals.h b/src/node_internals.h
285- index d37be23cd63e82d4040777bd0e17ed449ec0b15b..0b66996f11c66800a7e21ee84fa101450b856227 100644
169+ index d37be23cd63e82d4040777bd0e17ed449ec0b15b..eb84760593ff5fb5aa6a8104e8714099f24a67a0 100644
286170--- a/src/node_internals.h
287171+++ b/src/node_internals.h
288- @@ -118,6 +118,8 @@ class NodeArrayBufferAllocator : public ArrayBufferAllocator {
172+ @@ -97,7 +97,9 @@ bool InitializePrimordials(v8::Local<v8::Context> context);
173+
174+ class NodeArrayBufferAllocator : public ArrayBufferAllocator {
175+ public:
176+ - inline uint32_t* zero_fill_field() { return &zero_fill_field_; }
177+ + NodeArrayBufferAllocator();
178+ + ~NodeArrayBufferAllocator() override;
179+ + inline uint32_t* zero_fill_field() { return zero_fill_field_; }
180+
181+ void* Allocate(size_t size) override; // Defined in src/node.cc
182+ void* AllocateUninitialized(size_t size) override;
183+ @@ -116,8 +118,10 @@ class NodeArrayBufferAllocator : public ArrayBufferAllocator {
184+ }
185+
289186 private:
290- uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land.
187+ - uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land.
188+ + uint32_t* zero_fill_field_ = nullptr; // Boolean but exposed as uint32 to JS land.
291189 std::atomic<size_t> total_mem_usage_ {0};
292190+
293191+ std::unique_ptr<v8::ArrayBuffer::Allocator> allocator_{v8::ArrayBuffer::Allocator::NewDefaultAllocator()};
0 commit comments