0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-01 20:25:12 -05:00

fix(core): nuke Deno.core.ops pre-snapshot (#13970)

To avoid OOB & other ExternalReference snapshot serialization issues

Co-authored-by: Bert Belder <bertbelder@gmail.com>
This commit is contained in:
Aaron O'Mullan 2022-03-15 22:50:17 +01:00 committed by GitHub
parent 163e1d6192
commit 07d8431f10
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 99 additions and 85 deletions

View file

@ -14,6 +14,7 @@ use crate::PromiseId;
use crate::ZeroCopyBuf;
use anyhow::Error;
use log::debug;
use once_cell::sync::Lazy;
use serde::Deserialize;
use serde::Serialize;
use serde_v8::to_v8;
@ -29,88 +30,77 @@ use v8::SharedArrayBuffer;
use v8::ValueDeserializerHelper;
use v8::ValueSerializerHelper;
pub fn external_references(
ops: &[OpPair],
op_state: Rc<RefCell<OpState>>,
) -> v8::ExternalReferences {
let mut refs = vec![
v8::ExternalReference {
function: ref_op.map_fn_to(),
},
v8::ExternalReference {
function: unref_op.map_fn_to(),
},
v8::ExternalReference {
function: set_macrotask_callback.map_fn_to(),
},
v8::ExternalReference {
function: set_nexttick_callback.map_fn_to(),
},
v8::ExternalReference {
function: set_promise_reject_callback.map_fn_to(),
},
v8::ExternalReference {
function: set_uncaught_exception_callback.map_fn_to(),
},
v8::ExternalReference {
function: run_microtasks.map_fn_to(),
},
v8::ExternalReference {
function: has_tick_scheduled.map_fn_to(),
},
v8::ExternalReference {
function: set_has_tick_scheduled.map_fn_to(),
},
v8::ExternalReference {
function: eval_context.map_fn_to(),
},
v8::ExternalReference {
function: queue_microtask.map_fn_to(),
},
v8::ExternalReference {
function: create_host_object.map_fn_to(),
},
v8::ExternalReference {
function: encode.map_fn_to(),
},
v8::ExternalReference {
function: decode.map_fn_to(),
},
v8::ExternalReference {
function: serialize.map_fn_to(),
},
v8::ExternalReference {
function: deserialize.map_fn_to(),
},
v8::ExternalReference {
function: get_promise_details.map_fn_to(),
},
v8::ExternalReference {
function: get_proxy_details.map_fn_to(),
},
v8::ExternalReference {
function: is_proxy.map_fn_to(),
},
v8::ExternalReference {
function: memory_usage.map_fn_to(),
},
v8::ExternalReference {
function: call_console.map_fn_to(),
},
v8::ExternalReference {
function: set_wasm_streaming_callback.map_fn_to(),
},
];
let op_refs = ops
.iter()
.map(|(_, opref)| v8::ExternalReference { function: *opref });
refs.extend(op_refs);
let raw_op_state = Rc::as_ptr(&op_state) as *mut c_void;
refs.push(v8::ExternalReference {
pointer: raw_op_state,
pub static EXTERNAL_REFERENCES: Lazy<v8::ExternalReferences> =
Lazy::new(|| {
v8::ExternalReferences::new(&[
v8::ExternalReference {
function: ref_op.map_fn_to(),
},
v8::ExternalReference {
function: unref_op.map_fn_to(),
},
v8::ExternalReference {
function: set_macrotask_callback.map_fn_to(),
},
v8::ExternalReference {
function: set_nexttick_callback.map_fn_to(),
},
v8::ExternalReference {
function: set_promise_reject_callback.map_fn_to(),
},
v8::ExternalReference {
function: set_uncaught_exception_callback.map_fn_to(),
},
v8::ExternalReference {
function: run_microtasks.map_fn_to(),
},
v8::ExternalReference {
function: has_tick_scheduled.map_fn_to(),
},
v8::ExternalReference {
function: set_has_tick_scheduled.map_fn_to(),
},
v8::ExternalReference {
function: eval_context.map_fn_to(),
},
v8::ExternalReference {
function: queue_microtask.map_fn_to(),
},
v8::ExternalReference {
function: create_host_object.map_fn_to(),
},
v8::ExternalReference {
function: encode.map_fn_to(),
},
v8::ExternalReference {
function: decode.map_fn_to(),
},
v8::ExternalReference {
function: serialize.map_fn_to(),
},
v8::ExternalReference {
function: deserialize.map_fn_to(),
},
v8::ExternalReference {
function: get_promise_details.map_fn_to(),
},
v8::ExternalReference {
function: get_proxy_details.map_fn_to(),
},
v8::ExternalReference {
function: is_proxy.map_fn_to(),
},
v8::ExternalReference {
function: memory_usage.map_fn_to(),
},
v8::ExternalReference {
function: call_console.map_fn_to(),
},
v8::ExternalReference {
function: set_wasm_streaming_callback.map_fn_to(),
},
])
});
v8::ExternalReferences::new(&refs)
}
pub fn script_origin<'a>(
s: &mut v8::HandleScope<'a>,

View file

@ -297,13 +297,12 @@ impl JsRuntime {
let op_state = Rc::new(RefCell::new(op_state));
let refs = bindings::external_references(&ops, op_state.clone());
let refs: &'static v8::ExternalReferences = Box::leak(Box::new(refs));
let global_context;
let (mut isolate, maybe_snapshot_creator) = if options.will_snapshot {
// TODO(ry) Support loading snapshots before snapshotting.
assert!(options.startup_snapshot.is_none());
let mut creator = v8::SnapshotCreator::new(Some(refs));
let mut creator =
v8::SnapshotCreator::new(Some(&bindings::EXTERNAL_REFERENCES));
let isolate = unsafe { creator.get_owned_isolate() };
let mut isolate = JsRuntime::setup_isolate(isolate);
{
@ -319,7 +318,7 @@ impl JsRuntime {
.create_params
.take()
.unwrap_or_else(v8::Isolate::create_params)
.external_references(&**refs);
.external_references(&**bindings::EXTERNAL_REFERENCES);
let snapshot_loaded = if let Some(snapshot) = options.startup_snapshot {
params = match snapshot {
Snapshot::Static(data) => params.snapshot_blob(data),
@ -518,6 +517,18 @@ impl JsRuntime {
v8::Global::new(scope, cb)
}
fn grab_obj<'s>(
scope: &mut v8::HandleScope<'s>,
code: &str,
) -> v8::Local<'s, v8::Object> {
let scope = &mut v8::EscapableHandleScope::new(scope);
let code = v8::String::new(scope, code).unwrap();
let script = v8::Script::compile(scope, code, None).unwrap();
let v8_value = script.run(scope).unwrap();
let obj = v8::Local::<v8::Object>::try_from(v8_value).unwrap();
scope.escape(obj)
}
/// Grabs a reference to core.js' opresolve & syncOpsCache()
fn init_cbs(&mut self) {
let mut scope = self.handle_scope();
@ -594,6 +605,19 @@ impl JsRuntime {
/// be a different type if `RuntimeOptions::js_error_create_fn` has been set.
pub fn snapshot(&mut self) -> v8::StartupData {
assert!(self.snapshot_creator.is_some());
// Nuke Deno.core.ops.* to avoid ExternalReference snapshotting issues
// TODO(@AaronO): make ops stable across snapshots
{
let scope = &mut self.handle_scope();
let obj = Self::grab_obj(scope, "Deno.core.ops");
let names = obj.get_own_property_names(scope).unwrap();
for i in 0..names.length() {
let key = names.get_index(scope, i).unwrap();
obj.delete(scope, key);
}
}
let state = Self::state(self.v8_isolate());
// Note: create_blob() method must not be called from within a HandleScope.