1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 07:14:47 -05:00

fix(ext/kv): stricter structured clone serializer (#18914)

This commit is contained in:
Luca Casonato 2023-04-29 17:43:07 +02:00 committed by GitHub
parent 10ae5ee265
commit 1066490847
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 3 deletions

View file

@ -123,6 +123,36 @@ dbTest("set and get recursive object", async (db) => {
assert(resultValue.a === resultValue); assert(resultValue.a === resultValue);
}); });
// invalid values (as per structured clone algorithm with _for storage_, NOT JSON)
const INVALID_VALUE_CASES = [
{ name: "function", value: () => {} },
{ name: "symbol", value: Symbol() },
{ name: "WeakMap", value: new WeakMap() },
{ name: "WeakSet", value: new WeakSet() },
{
name: "WebAssembly.Module",
value: new WebAssembly.Module(
new Uint8Array([0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00]),
),
},
{
name: "SharedArrayBuffer",
value: new SharedArrayBuffer(3),
},
];
for (const { name, value } of INVALID_VALUE_CASES) {
dbTest(`set and get ${name} value (invalid)`, async (db) => {
await assertRejects(
async () => await db.set(["a"], value),
Error,
);
const res = await db.get(["a"]);
assertEquals(res.key, ["a"]);
assertEquals(res.value, null);
});
}
const keys = [ const keys = [
["a"], ["a"],
["a", "b"], ["a", "b"],

View file

@ -211,6 +211,7 @@ fn op_decode<'a>(
struct SerializeDeserialize<'a> { struct SerializeDeserialize<'a> {
host_objects: Option<v8::Local<'a, v8::Array>>, host_objects: Option<v8::Local<'a, v8::Array>>,
error_callback: Option<v8::Local<'a, v8::Function>>, error_callback: Option<v8::Local<'a, v8::Function>>,
for_storage: bool,
} }
impl<'a> v8::ValueSerializerImpl for SerializeDeserialize<'a> { impl<'a> v8::ValueSerializerImpl for SerializeDeserialize<'a> {
@ -238,6 +239,9 @@ impl<'a> v8::ValueSerializerImpl for SerializeDeserialize<'a> {
scope: &mut v8::HandleScope<'s>, scope: &mut v8::HandleScope<'s>,
shared_array_buffer: v8::Local<'s, v8::SharedArrayBuffer>, shared_array_buffer: v8::Local<'s, v8::SharedArrayBuffer>,
) -> Option<u32> { ) -> Option<u32> {
if self.for_storage {
return None;
}
let state_rc = JsRuntime::state(scope); let state_rc = JsRuntime::state(scope);
let state = state_rc.borrow_mut(); let state = state_rc.borrow_mut();
if let Some(shared_array_buffer_store) = &state.shared_array_buffer_store { if let Some(shared_array_buffer_store) = &state.shared_array_buffer_store {
@ -254,6 +258,11 @@ impl<'a> v8::ValueSerializerImpl for SerializeDeserialize<'a> {
scope: &mut v8::HandleScope<'_>, scope: &mut v8::HandleScope<'_>,
module: v8::Local<v8::WasmModuleObject>, module: v8::Local<v8::WasmModuleObject>,
) -> Option<u32> { ) -> Option<u32> {
if self.for_storage {
let message = v8::String::new(scope, "Wasm modules cannot be stored")?;
self.throw_data_clone_error(scope, message);
return None;
}
let state_rc = JsRuntime::state(scope); let state_rc = JsRuntime::state(scope);
let state = state_rc.borrow_mut(); let state = state_rc.borrow_mut();
if let Some(compiled_wasm_module_store) = &state.compiled_wasm_module_store if let Some(compiled_wasm_module_store) = &state.compiled_wasm_module_store
@ -293,6 +302,9 @@ impl<'a> v8::ValueDeserializerImpl for SerializeDeserialize<'a> {
scope: &mut v8::HandleScope<'s>, scope: &mut v8::HandleScope<'s>,
transfer_id: u32, transfer_id: u32,
) -> Option<v8::Local<'s, v8::SharedArrayBuffer>> { ) -> Option<v8::Local<'s, v8::SharedArrayBuffer>> {
if self.for_storage {
return None;
}
let state_rc = JsRuntime::state(scope); let state_rc = JsRuntime::state(scope);
let state = state_rc.borrow_mut(); let state = state_rc.borrow_mut();
if let Some(shared_array_buffer_store) = &state.shared_array_buffer_store { if let Some(shared_array_buffer_store) = &state.shared_array_buffer_store {
@ -310,6 +322,9 @@ impl<'a> v8::ValueDeserializerImpl for SerializeDeserialize<'a> {
scope: &mut v8::HandleScope<'s>, scope: &mut v8::HandleScope<'s>,
clone_id: u32, clone_id: u32,
) -> Option<v8::Local<'s, v8::WasmModuleObject>> { ) -> Option<v8::Local<'s, v8::WasmModuleObject>> {
if self.for_storage {
return None;
}
let state_rc = JsRuntime::state(scope); let state_rc = JsRuntime::state(scope);
let state = state_rc.borrow_mut(); let state = state_rc.borrow_mut();
if let Some(compiled_wasm_module_store) = &state.compiled_wasm_module_store if let Some(compiled_wasm_module_store) = &state.compiled_wasm_module_store
@ -337,7 +352,7 @@ impl<'a> v8::ValueDeserializerImpl for SerializeDeserialize<'a> {
} }
} }
let message = let message: v8::Local<v8::String> =
v8::String::new(scope, "Failed to deserialize host object").unwrap(); v8::String::new(scope, "Failed to deserialize host object").unwrap();
let error = v8::Exception::error(scope, message); let error = v8::Exception::error(scope, message);
scope.throw_exception(error); scope.throw_exception(error);
@ -350,6 +365,8 @@ impl<'a> v8::ValueDeserializerImpl for SerializeDeserialize<'a> {
struct SerializeDeserializeOptions<'a> { struct SerializeDeserializeOptions<'a> {
host_objects: Option<serde_v8::Value<'a>>, host_objects: Option<serde_v8::Value<'a>>,
transferred_array_buffers: Option<serde_v8::Value<'a>>, transferred_array_buffers: Option<serde_v8::Value<'a>>,
#[serde(default)]
for_storage: bool,
} }
#[op(v8)] #[op(v8)]
@ -385,6 +402,7 @@ fn op_serialize(
let serialize_deserialize = Box::new(SerializeDeserialize { let serialize_deserialize = Box::new(SerializeDeserialize {
host_objects, host_objects,
error_callback, error_callback,
for_storage: options.for_storage,
}); });
let mut value_serializer = let mut value_serializer =
v8::ValueSerializer::new(scope, serialize_deserialize); v8::ValueSerializer::new(scope, serialize_deserialize);
@ -464,6 +482,7 @@ fn op_deserialize<'a>(
let serialize_deserialize = Box::new(SerializeDeserialize { let serialize_deserialize = Box::new(SerializeDeserialize {
host_objects, host_objects,
error_callback: None, error_callback: None,
for_storage: options.for_storage,
}); });
let mut value_deserializer = let mut value_deserializer =
v8::ValueDeserializer::new(scope, serialize_deserialize, &zero_copy); v8::ValueDeserializer::new(scope, serialize_deserialize, &zero_copy);

View file

@ -312,7 +312,7 @@ function deserializeValue(entry: RawKvEntry): Deno.KvEntry<unknown> {
case "v8": case "v8":
return { return {
...entry, ...entry,
value: core.deserialize(value), value: core.deserialize(value, { forStorage: true }),
}; };
case "bytes": case "bytes":
return { return {
@ -343,7 +343,7 @@ function serializeValue(value: unknown): RawValue {
} else { } else {
return { return {
kind: "v8", kind: "v8",
value: core.serialize(value), value: core.serialize(value, { forStorage: true }),
}; };
} }
} }