mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-11-28 16:21:04 -05:00
fix: crash on x86_64 systems that support memory protection keys (#1318)
Co-authored-by: Matt Mastracci <matthew@mastracci.com>
This commit is contained in:
parent
6eb4b811df
commit
53e048ffc7
8 changed files with 124 additions and 5 deletions
|
@ -1,9 +1,11 @@
|
||||||
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
|
||||||
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "support.h"
|
#include "support.h"
|
||||||
#include "unicode/locid.h"
|
#include "unicode/locid.h"
|
||||||
|
@ -17,9 +19,12 @@
|
||||||
#include "v8/include/v8.h"
|
#include "v8/include/v8.h"
|
||||||
#include "v8/src/api/api-inl.h"
|
#include "v8/src/api/api-inl.h"
|
||||||
#include "v8/src/api/api.h"
|
#include "v8/src/api/api.h"
|
||||||
|
#include "v8/src/base/debug/stack_trace.h"
|
||||||
|
#include "v8/src/base/sys-info.h"
|
||||||
#include "v8/src/execution/isolate-utils-inl.h"
|
#include "v8/src/execution/isolate-utils-inl.h"
|
||||||
#include "v8/src/execution/isolate-utils.h"
|
#include "v8/src/execution/isolate-utils.h"
|
||||||
#include "v8/src/flags/flags.h"
|
#include "v8/src/flags/flags.h"
|
||||||
|
#include "v8/src/libplatform/default-platform.h"
|
||||||
#include "v8/src/objects/objects-inl.h"
|
#include "v8/src/objects/objects-inl.h"
|
||||||
#include "v8/src/objects/objects.h"
|
#include "v8/src/objects/objects.h"
|
||||||
#include "v8/src/objects/smi.h"
|
#include "v8/src/objects/smi.h"
|
||||||
|
@ -2579,6 +2584,49 @@ v8::StartupData v8__SnapshotCreator__CreateBlob(
|
||||||
return self->CreateBlob(function_code_handling);
|
return self->CreateBlob(function_code_handling);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UnprotectedDefaultPlatform : public v8::platform::DefaultPlatform {
|
||||||
|
using IdleTaskSupport = v8::platform::IdleTaskSupport;
|
||||||
|
using InProcessStackDumping = v8::platform::InProcessStackDumping;
|
||||||
|
using PriorityMode = v8::platform::PriorityMode;
|
||||||
|
using TracingController = v8::TracingController;
|
||||||
|
|
||||||
|
static constexpr int kMaxThreadPoolSize = 16;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit UnprotectedDefaultPlatform(
|
||||||
|
int thread_pool_size, IdleTaskSupport idle_task_support,
|
||||||
|
std::unique_ptr<TracingController> tracing_controller = {},
|
||||||
|
PriorityMode priority_mode = PriorityMode::kDontApply)
|
||||||
|
: v8::platform::DefaultPlatform(thread_pool_size, idle_task_support,
|
||||||
|
std::move(tracing_controller),
|
||||||
|
priority_mode) {}
|
||||||
|
|
||||||
|
static std::unique_ptr<v8::Platform> New(
|
||||||
|
int thread_pool_size, IdleTaskSupport idle_task_support,
|
||||||
|
InProcessStackDumping in_process_stack_dumping,
|
||||||
|
std::unique_ptr<TracingController> tracing_controller = {},
|
||||||
|
PriorityMode priority_mode = PriorityMode::kDontApply) {
|
||||||
|
// This implementation is semantically equivalent to the implementation of
|
||||||
|
// `v8::platform::NewDefaultPlatform()`.
|
||||||
|
DCHECK_GE(thread_pool_size, 0);
|
||||||
|
if (thread_pool_size < 1) {
|
||||||
|
thread_pool_size =
|
||||||
|
std::max(v8::base::SysInfo::NumberOfProcessors() - 1, 1);
|
||||||
|
}
|
||||||
|
thread_pool_size = std::min(thread_pool_size, kMaxThreadPoolSize);
|
||||||
|
if (in_process_stack_dumping == InProcessStackDumping::kEnabled) {
|
||||||
|
v8::base::debug::EnableInProcessStackDumping();
|
||||||
|
}
|
||||||
|
return std::make_unique<UnprotectedDefaultPlatform>(
|
||||||
|
thread_pool_size, idle_task_support, std::move(tracing_controller),
|
||||||
|
priority_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::ThreadIsolatedAllocator* GetThreadIsolatedAllocator() override {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
v8::Platform* v8__Platform__NewDefaultPlatform(int thread_pool_size,
|
v8::Platform* v8__Platform__NewDefaultPlatform(int thread_pool_size,
|
||||||
bool idle_task_support) {
|
bool idle_task_support) {
|
||||||
return v8::platform::NewDefaultPlatform(
|
return v8::platform::NewDefaultPlatform(
|
||||||
|
@ -2589,6 +2637,16 @@ v8::Platform* v8__Platform__NewDefaultPlatform(int thread_pool_size,
|
||||||
.release();
|
.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v8::Platform* v8__Platform__NewUnprotectedDefaultPlatform(
|
||||||
|
int thread_pool_size, bool idle_task_support) {
|
||||||
|
return UnprotectedDefaultPlatform::New(
|
||||||
|
thread_pool_size,
|
||||||
|
idle_task_support ? v8::platform::IdleTaskSupport::kEnabled
|
||||||
|
: v8::platform::IdleTaskSupport::kDisabled,
|
||||||
|
v8::platform::InProcessStackDumping::kDisabled, nullptr)
|
||||||
|
.release();
|
||||||
|
}
|
||||||
|
|
||||||
v8::Platform* v8__Platform__NewSingleThreadedDefaultPlatform(
|
v8::Platform* v8__Platform__NewSingleThreadedDefaultPlatform(
|
||||||
bool idle_task_support) {
|
bool idle_task_support) {
|
||||||
return v8::platform::NewSingleThreadedDefaultPlatform(
|
return v8::platform::NewSingleThreadedDefaultPlatform(
|
||||||
|
|
|
@ -120,6 +120,7 @@ pub use module::*;
|
||||||
pub use object::*;
|
pub use object::*;
|
||||||
pub use platform::new_default_platform;
|
pub use platform::new_default_platform;
|
||||||
pub use platform::new_single_threaded_default_platform;
|
pub use platform::new_single_threaded_default_platform;
|
||||||
|
pub use platform::new_unprotected_default_platform;
|
||||||
pub use platform::Platform;
|
pub use platform::Platform;
|
||||||
pub use primitives::*;
|
pub use primitives::*;
|
||||||
pub use private::*;
|
pub use private::*;
|
||||||
|
|
|
@ -14,6 +14,10 @@ extern "C" {
|
||||||
thread_pool_size: int,
|
thread_pool_size: int,
|
||||||
idle_task_support: bool,
|
idle_task_support: bool,
|
||||||
) -> *mut Platform;
|
) -> *mut Platform;
|
||||||
|
fn v8__Platform__NewUnprotectedDefaultPlatform(
|
||||||
|
thread_pool_size: int,
|
||||||
|
idle_task_support: bool,
|
||||||
|
) -> *mut Platform;
|
||||||
fn v8__Platform__NewSingleThreadedDefaultPlatform(
|
fn v8__Platform__NewSingleThreadedDefaultPlatform(
|
||||||
idle_task_support: bool,
|
idle_task_support: bool,
|
||||||
) -> *mut Platform;
|
) -> *mut Platform;
|
||||||
|
@ -58,6 +62,16 @@ pub struct Platform(Opaque);
|
||||||
/// If |idle_task_support| is enabled then the platform will accept idle
|
/// If |idle_task_support| is enabled then the platform will accept idle
|
||||||
/// tasks (IdleTasksEnabled will return true) and will rely on the embedder
|
/// tasks (IdleTasksEnabled will return true) and will rely on the embedder
|
||||||
/// calling v8::platform::RunIdleTasks to process the idle tasks.
|
/// calling v8::platform::RunIdleTasks to process the idle tasks.
|
||||||
|
///
|
||||||
|
/// The default platform for v8 may include restrictions and caveats on thread
|
||||||
|
/// creation and initialization. This platform should only be used in cases
|
||||||
|
/// where v8 can be reliably initialized on the application's main thread, or
|
||||||
|
/// the parent thread to all threads in the system that will use v8.
|
||||||
|
///
|
||||||
|
/// One example of a restriction is the use of Memory Protection Keys (pkeys) on
|
||||||
|
/// modern Linux systems using modern Intel/AMD processors. This particular
|
||||||
|
/// technology requires that all threads using v8 are created as descendent
|
||||||
|
/// threads of the thread that called `v8::Initialize`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new_default_platform(
|
pub fn new_default_platform(
|
||||||
thread_pool_size: u32,
|
thread_pool_size: u32,
|
||||||
|
@ -66,6 +80,18 @@ pub fn new_default_platform(
|
||||||
Platform::new(thread_pool_size, idle_task_support)
|
Platform::new(thread_pool_size, idle_task_support)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a platform that is identical to the default platform, but does not
|
||||||
|
/// enforce thread-isolated allocations. This may reduce security in some cases,
|
||||||
|
/// so this method should be used with caution in cases where the threading
|
||||||
|
/// guarantees of `new_default_platform` cannot be upheld (generally for tests).
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn new_unprotected_default_platform(
|
||||||
|
thread_pool_size: u32,
|
||||||
|
idle_task_support: bool,
|
||||||
|
) -> UniqueRef<Platform> {
|
||||||
|
Platform::new_unprotected(thread_pool_size, idle_task_support)
|
||||||
|
}
|
||||||
|
|
||||||
/// The same as new_default_platform() but disables the worker thread pool.
|
/// The same as new_default_platform() but disables the worker thread pool.
|
||||||
/// It must be used with the --single-threaded V8 flag.
|
/// It must be used with the --single-threaded V8 flag.
|
||||||
///
|
///
|
||||||
|
@ -88,6 +114,16 @@ impl Platform {
|
||||||
/// If |idle_task_support| is enabled then the platform will accept idle
|
/// If |idle_task_support| is enabled then the platform will accept idle
|
||||||
/// tasks (IdleTasksEnabled will return true) and will rely on the embedder
|
/// tasks (IdleTasksEnabled will return true) and will rely on the embedder
|
||||||
/// calling v8::platform::RunIdleTasks to process the idle tasks.
|
/// calling v8::platform::RunIdleTasks to process the idle tasks.
|
||||||
|
///
|
||||||
|
/// The default platform for v8 may include restrictions and caveats on thread
|
||||||
|
/// creation and initialization. This platform should only be used in cases
|
||||||
|
/// where v8 can be reliably initialized on the application's main thread, or
|
||||||
|
/// the parent thread to all threads in the system that will use v8.
|
||||||
|
///
|
||||||
|
/// One example of a restriction is the use of Memory Protection Keys (pkeys)
|
||||||
|
/// on modern Linux systems using modern Intel/AMD processors. This particular
|
||||||
|
/// technology requires that all threads using v8 are created as descendent
|
||||||
|
/// threads of the thread that called `v8::Initialize`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
thread_pool_size: u32,
|
thread_pool_size: u32,
|
||||||
|
@ -101,6 +137,24 @@ impl Platform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a platform that is identical to the default platform, but does not
|
||||||
|
/// enforce thread-isolated allocations. This may reduce security in some
|
||||||
|
/// cases, so this method should be used with caution in cases where the
|
||||||
|
/// threading guarantees of `new_default_platform` cannot be upheld (generally
|
||||||
|
/// for tests).
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn new_unprotected(
|
||||||
|
thread_pool_size: u32,
|
||||||
|
idle_task_support: bool,
|
||||||
|
) -> UniqueRef<Self> {
|
||||||
|
unsafe {
|
||||||
|
UniqueRef::from_raw(v8__Platform__NewUnprotectedDefaultPlatform(
|
||||||
|
thread_pool_size.min(16) as i32,
|
||||||
|
idle_task_support,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The same as new() but disables the worker thread pool.
|
/// The same as new() but disables the worker thread pool.
|
||||||
/// It must be used with the --single-threaded V8 flag.
|
/// It must be used with the --single-threaded V8 flag.
|
||||||
///
|
///
|
||||||
|
|
|
@ -15,7 +15,7 @@ fn setup() {
|
||||||
START.call_once(|| {
|
START.call_once(|| {
|
||||||
v8::V8::set_flags_from_string("--expose_gc");
|
v8::V8::set_flags_from_string("--expose_gc");
|
||||||
v8::V8::initialize_platform(
|
v8::V8::initialize_platform(
|
||||||
v8::new_default_platform(0, false).make_shared(),
|
v8::new_unprotected_default_platform(0, false).make_shared(),
|
||||||
);
|
);
|
||||||
v8::V8::initialize();
|
v8::V8::initialize();
|
||||||
});
|
});
|
||||||
|
|
|
@ -55,7 +55,7 @@ mod setup {
|
||||||
"--no_freeze_flags_after_init --expose_gc --harmony-import-assertions --harmony-shadow-realm --allow_natives_syntax --turbo_fast_api_calls",
|
"--no_freeze_flags_after_init --expose_gc --harmony-import-assertions --harmony-shadow-realm --allow_natives_syntax --turbo_fast_api_calls",
|
||||||
);
|
);
|
||||||
v8::V8::initialize_platform(
|
v8::V8::initialize_platform(
|
||||||
v8::new_default_platform(0, false).make_shared(),
|
v8::new_unprotected_default_platform(0, false).make_shared(),
|
||||||
);
|
);
|
||||||
v8::V8::initialize();
|
v8::V8::initialize();
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,7 +18,9 @@ fn set_entropy_source() {
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
|
|
||||||
v8::V8::initialize_platform(v8::new_default_platform(0, false).make_shared());
|
v8::V8::initialize_platform(
|
||||||
|
v8::new_unprotected_default_platform(0, false).make_shared(),
|
||||||
|
);
|
||||||
v8::V8::initialize();
|
v8::V8::initialize();
|
||||||
|
|
||||||
// Assumes that every isolate creates a PRNG from scratch, which is currently true.
|
// Assumes that every isolate creates a PRNG from scratch, which is currently true.
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
#[test]
|
#[test]
|
||||||
fn set_flags_from_string() {
|
fn set_flags_from_string() {
|
||||||
v8::V8::set_flags_from_string("--use_strict");
|
v8::V8::set_flags_from_string("--use_strict");
|
||||||
v8::V8::initialize_platform(v8::new_default_platform(0, false).make_shared());
|
v8::V8::initialize_platform(
|
||||||
|
v8::new_unprotected_default_platform(0, false).make_shared(),
|
||||||
|
);
|
||||||
v8::V8::initialize();
|
v8::V8::initialize();
|
||||||
let isolate = &mut v8::Isolate::new(Default::default());
|
let isolate = &mut v8::Isolate::new(Default::default());
|
||||||
let scope = &mut v8::HandleScope::new(isolate);
|
let scope = &mut v8::HandleScope::new(isolate);
|
||||||
|
|
|
@ -3,7 +3,9 @@ fn atomics_pump_message_loop() {
|
||||||
v8::V8::set_flags_from_string(
|
v8::V8::set_flags_from_string(
|
||||||
"--allow-natives-syntax --harmony-sharedarraybuffer",
|
"--allow-natives-syntax --harmony-sharedarraybuffer",
|
||||||
);
|
);
|
||||||
v8::V8::initialize_platform(v8::new_default_platform(0, false).make_shared());
|
v8::V8::initialize_platform(
|
||||||
|
v8::new_unprotected_default_platform(0, false).make_shared(),
|
||||||
|
);
|
||||||
v8::V8::initialize();
|
v8::V8::initialize();
|
||||||
let isolate = &mut v8::Isolate::new(Default::default());
|
let isolate = &mut v8::Isolate::new(Default::default());
|
||||||
let scope = &mut v8::HandleScope::new(isolate);
|
let scope = &mut v8::HandleScope::new(isolate);
|
||||||
|
|
Loading…
Reference in a new issue