|
@@ -6,84 +6,27 @@ Subject: support V8 sandboxed pointers
|
|
|
This refactors several allocators to allocate within the V8 memory cage,
|
|
|
allowing them to be compatible with the V8_SANDBOXED_POINTERS feature.
|
|
|
|
|
|
-diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js
|
|
|
-index 4c459b58b5a048d9d8a4f15f4011e7cce68089f4..6fb4c8d4567aee5b313ad621ea42699a196f18c7 100644
|
|
|
---- a/lib/internal/bootstrap/pre_execution.js
|
|
|
-+++ b/lib/internal/bootstrap/pre_execution.js
|
|
|
-@@ -14,7 +14,6 @@ const {
|
|
|
- getOptionValue,
|
|
|
- getEmbedderOptions,
|
|
|
- } = require('internal/options');
|
|
|
--const { reconnectZeroFillToggle } = require('internal/buffer');
|
|
|
- const {
|
|
|
- defineOperation,
|
|
|
- emitExperimentalWarning,
|
|
|
-@@ -26,10 +25,6 @@ const { ERR_MANIFEST_ASSERT_INTEGRITY } = require('internal/errors').codes;
|
|
|
- const assert = require('internal/assert');
|
|
|
-
|
|
|
- function prepareMainThreadExecution(expandArgv1 = false) {
|
|
|
-- // TODO(joyeecheung): this is also necessary for workers when they deserialize
|
|
|
-- // this toggle from the snapshot.
|
|
|
-- reconnectZeroFillToggle();
|
|
|
--
|
|
|
- // Patch the process object with legacy properties and normalizations
|
|
|
- patchProcessObject(expandArgv1);
|
|
|
- setupTraceCategoryState();
|
|
|
-diff --git a/lib/internal/buffer.js b/lib/internal/buffer.js
|
|
|
-index bd38cf48a7fc6e8d61d8f11fa15c34aee182cbe3..1aa071cdc071dcdaf5c3b4bed0d3d76e5871731d 100644
|
|
|
---- a/lib/internal/buffer.js
|
|
|
-+++ b/lib/internal/buffer.js
|
|
|
-@@ -30,7 +30,7 @@ const {
|
|
|
- hexWrite,
|
|
|
- ucs2Write,
|
|
|
- utf8Write,
|
|
|
-- getZeroFillToggle
|
|
|
-+ setZeroFillToggle
|
|
|
- } = internalBinding('buffer');
|
|
|
- const {
|
|
|
- untransferable_object_private_symbol,
|
|
|
-@@ -1055,24 +1055,15 @@ function markAsUntransferable(obj) {
|
|
|
- // in C++.
|
|
|
- // |zeroFill| can be undefined when running inside an isolate where we
|
|
|
- // do not own the ArrayBuffer allocator. Zero fill is always on in that case.
|
|
|
--let zeroFill = getZeroFillToggle();
|
|
|
- function createUnsafeBuffer(size) {
|
|
|
-- zeroFill[0] = 0;
|
|
|
-+ setZeroFillToggle(false);
|
|
|
- try {
|
|
|
- return new FastBuffer(size);
|
|
|
- } finally {
|
|
|
-- zeroFill[0] = 1;
|
|
|
-+ setZeroFillToggle(true)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
--// The connection between the JS land zero fill toggle and the
|
|
|
--// C++ one in the NodeArrayBufferAllocator gets lost if the toggle
|
|
|
--// is deserialized from the snapshot, because V8 owns the underlying
|
|
|
--// memory of this toggle. This resets the connection.
|
|
|
--function reconnectZeroFillToggle() {
|
|
|
-- zeroFill = getZeroFillToggle();
|
|
|
--}
|
|
|
--
|
|
|
- module.exports = {
|
|
|
- FastBuffer,
|
|
|
- addBufferPrototypeMethods,
|
|
|
-@@ -1080,5 +1071,4 @@ module.exports = {
|
|
|
- createUnsafeBuffer,
|
|
|
- readUInt16BE,
|
|
|
- readUInt32BE,
|
|
|
-- reconnectZeroFillToggle
|
|
|
- };
|
|
|
diff --git a/src/api/environment.cc b/src/api/environment.cc
|
|
|
-index 2abf5994405e8da2a04d1b23b75ccd3658398474..024d612a04d83583b397549589d994e32cf0107f 100644
|
|
|
+index 2abf5994405e8da2a04d1b23b75ccd3658398474..b06e8529bb8ca2fa6d7f0735531bbbf39da6af12 100644
|
|
|
--- a/src/api/environment.cc
|
|
|
+++ b/src/api/environment.cc
|
|
|
-@@ -83,16 +83,16 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
|
|
|
+@@ -80,19 +80,27 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
++NodeArrayBufferAllocator::NodeArrayBufferAllocator() {
|
|
|
++ zero_fill_field_ = static_cast<uint32_t*>(allocator_->Allocate(sizeof(*zero_fill_field_)));
|
|
|
++}
|
|
|
++
|
|
|
++NodeArrayBufferAllocator::~NodeArrayBufferAllocator() {
|
|
|
++ allocator_->Free(zero_fill_field_, sizeof(*zero_fill_field_));
|
|
|
++}
|
|
|
++
|
|
|
void* NodeArrayBufferAllocator::Allocate(size_t size) {
|
|
|
void* ret;
|
|
|
- if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
|
|
|
+- if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
|
|
|
- ret = UncheckedCalloc(size);
|
|
|
++ if (*zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
|
|
|
+ ret = allocator_->Allocate(size);
|
|
|
else
|
|
|
- ret = UncheckedMalloc(size);
|
|
@@ -99,7 +42,7 @@ index 2abf5994405e8da2a04d1b23b75ccd3658398474..024d612a04d83583b397549589d994e3
|
|
|
if (LIKELY(ret != nullptr))
|
|
|
total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
|
|
|
return ret;
|
|
|
-@@ -100,7 +100,7 @@ void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
|
|
|
+@@ -100,7 +108,7 @@ void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
|
|
|
|
|
|
void* NodeArrayBufferAllocator::Reallocate(
|
|
|
void* data, size_t old_size, size_t size) {
|
|
@@ -108,7 +51,7 @@ index 2abf5994405e8da2a04d1b23b75ccd3658398474..024d612a04d83583b397549589d994e3
|
|
|
if (LIKELY(ret != nullptr) || UNLIKELY(size == 0))
|
|
|
total_mem_usage_.fetch_add(size - old_size, std::memory_order_relaxed);
|
|
|
return ret;
|
|
|
-@@ -108,7 +108,7 @@ void* NodeArrayBufferAllocator::Reallocate(
|
|
|
+@@ -108,7 +116,7 @@ void* NodeArrayBufferAllocator::Reallocate(
|
|
|
|
|
|
void NodeArrayBufferAllocator::Free(void* data, size_t size) {
|
|
|
total_mem_usage_.fetch_sub(size, std::memory_order_relaxed);
|
|
@@ -209,65 +152,6 @@ index c431159e6f77f8c86844bcadb86012b056d03372..9f57ac58d826cb0aae422ddca54e2136
|
|
|
|
|
|
v8::Local<v8::ArrayBuffer> ToArrayBuffer(Environment* env);
|
|
|
|
|
|
-diff --git a/src/node_buffer.cc b/src/node_buffer.cc
|
|
|
-index 215bd8003aabe17e43ac780c723cfe971b437eae..eb00eb6f592e20f3c17a529f30b09673774eb1c1 100644
|
|
|
---- a/src/node_buffer.cc
|
|
|
-+++ b/src/node_buffer.cc
|
|
|
-@@ -1175,33 +1175,14 @@ void SetBufferPrototype(const FunctionCallbackInfo<Value>& args) {
|
|
|
- env->set_buffer_prototype_object(proto);
|
|
|
- }
|
|
|
-
|
|
|
--void GetZeroFillToggle(const FunctionCallbackInfo<Value>& args) {
|
|
|
-+void SetZeroFillToggle(const FunctionCallbackInfo<Value>& args) {
|
|
|
- Environment* env = Environment::GetCurrent(args);
|
|
|
- NodeArrayBufferAllocator* allocator = env->isolate_data()->node_allocator();
|
|
|
- Local<ArrayBuffer> ab;
|
|
|
-- // It can be a nullptr when running inside an isolate where we
|
|
|
-- // do not own the ArrayBuffer allocator.
|
|
|
-- if (allocator == nullptr) {
|
|
|
-- // Create a dummy Uint32Array - the JS land can only toggle the C++ land
|
|
|
-- // setting when the allocator uses our toggle. With this the toggle in JS
|
|
|
-- // land results in no-ops.
|
|
|
-- ab = ArrayBuffer::New(env->isolate(), sizeof(uint32_t));
|
|
|
-- } else {
|
|
|
-+ if (allocator != nullptr) {
|
|
|
- uint32_t* zero_fill_field = allocator->zero_fill_field();
|
|
|
-- std::unique_ptr<BackingStore> backing =
|
|
|
-- ArrayBuffer::NewBackingStore(zero_fill_field,
|
|
|
-- sizeof(*zero_fill_field),
|
|
|
-- [](void*, size_t, void*) {},
|
|
|
-- nullptr);
|
|
|
-- ab = ArrayBuffer::New(env->isolate(), std::move(backing));
|
|
|
-+ *zero_fill_field = args[0]->BooleanValue(env->isolate());
|
|
|
- }
|
|
|
--
|
|
|
-- ab->SetPrivate(
|
|
|
-- env->context(),
|
|
|
-- env->untransferable_object_private_symbol(),
|
|
|
-- True(env->isolate())).Check();
|
|
|
--
|
|
|
-- args.GetReturnValue().Set(Uint32Array::New(ab, 0, 1));
|
|
|
- }
|
|
|
-
|
|
|
- void DetachArrayBuffer(const FunctionCallbackInfo<Value>& args) {
|
|
|
-@@ -1310,7 +1291,7 @@ void Initialize(Local<Object> target,
|
|
|
- env->SetMethod(target, "ucs2Write", StringWrite<UCS2>);
|
|
|
- env->SetMethod(target, "utf8Write", StringWrite<UTF8>);
|
|
|
-
|
|
|
-- env->SetMethod(target, "getZeroFillToggle", GetZeroFillToggle);
|
|
|
-+ env->SetMethod(target, "setZeroFillToggle", SetZeroFillToggle);
|
|
|
- }
|
|
|
-
|
|
|
- } // anonymous namespace
|
|
|
-@@ -1350,7 +1331,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
|
|
- registry->Register(StringWrite<HEX>);
|
|
|
- registry->Register(StringWrite<UCS2>);
|
|
|
- registry->Register(StringWrite<UTF8>);
|
|
|
-- registry->Register(GetZeroFillToggle);
|
|
|
-+ registry->Register(SetZeroFillToggle);
|
|
|
-
|
|
|
- registry->Register(DetachArrayBuffer);
|
|
|
- registry->Register(CopyArrayBuffer);
|
|
|
diff --git a/src/node_i18n.cc b/src/node_i18n.cc
|
|
|
index c537a247f55ff070da1988fc8b7309b5692b5c18..59bfb597849cd5a94800d6c83b238ef77245243e 100644
|
|
|
--- a/src/node_i18n.cc
|
|
@@ -282,12 +166,26 @@ index c537a247f55ff070da1988fc8b7309b5692b5c18..59bfb597849cd5a94800d6c83b238ef7
|
|
|
return ret;
|
|
|
|
|
|
diff --git a/src/node_internals.h b/src/node_internals.h
|
|
|
-index d37be23cd63e82d4040777bd0e17ed449ec0b15b..0b66996f11c66800a7e21ee84fa101450b856227 100644
|
|
|
+index d37be23cd63e82d4040777bd0e17ed449ec0b15b..eb84760593ff5fb5aa6a8104e8714099f24a67a0 100644
|
|
|
--- a/src/node_internals.h
|
|
|
+++ b/src/node_internals.h
|
|
|
-@@ -118,6 +118,8 @@ class NodeArrayBufferAllocator : public ArrayBufferAllocator {
|
|
|
+@@ -97,7 +97,9 @@ bool InitializePrimordials(v8::Local<v8::Context> context);
|
|
|
+
|
|
|
+ class NodeArrayBufferAllocator : public ArrayBufferAllocator {
|
|
|
+ public:
|
|
|
+- inline uint32_t* zero_fill_field() { return &zero_fill_field_; }
|
|
|
++ NodeArrayBufferAllocator();
|
|
|
++ ~NodeArrayBufferAllocator() override;
|
|
|
++ inline uint32_t* zero_fill_field() { return zero_fill_field_; }
|
|
|
+
|
|
|
+ void* Allocate(size_t size) override; // Defined in src/node.cc
|
|
|
+ void* AllocateUninitialized(size_t size) override;
|
|
|
+@@ -116,8 +118,10 @@ class NodeArrayBufferAllocator : public ArrayBufferAllocator {
|
|
|
+ }
|
|
|
+
|
|
|
private:
|
|
|
- uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land.
|
|
|
+- uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land.
|
|
|
++ uint32_t* zero_fill_field_ = nullptr; // Boolean but exposed as uint32 to JS land.
|
|
|
std::atomic<size_t> total_mem_usage_ {0};
|
|
|
+
|
|
|
+ std::unique_ptr<v8::ArrayBuffer::Allocator> allocator_{v8::ArrayBuffer::Allocator::NewDefaultAllocator()};
|