Fix undefined behavior in the editor wasm bridge (#414)

* removed possible undifined behavior

* changed naming of Editor -> JsEditorHandle

* fix rust formatting

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
mfish33
2021-12-20 17:55:31 -05:00
committed by Keavon Chambers
co-authored by Keavon Chambers
parent 1e57f658dc
commit 14f0bb489e
3 changed files with 32 additions and 15 deletions
+2 -2
View File
@@ -4,7 +4,7 @@ import { createJsDispatcher } from "@/dispatcher/js-dispatcher";
import { JsMessageType } from "@/dispatcher/js-messages"; import { JsMessageType } from "@/dispatcher/js-messages";
export type WasmInstance = typeof import("@/../wasm/pkg"); export type WasmInstance = typeof import("@/../wasm/pkg");
export type RustEditorInstance = InstanceType<WasmInstance["Editor"]>; export type RustEditorInstance = InstanceType<WasmInstance["JsEditorHandle"]>;
let wasmImport: WasmInstance | null = null; let wasmImport: WasmInstance | null = null;
export async function initWasm() { export async function initWasm() {
@@ -65,7 +65,7 @@ export function createEditorState() {
dispatcher.handleJsMessage(messageType, data, rawWasm, instance); dispatcher.handleJsMessage(messageType, data, rawWasm, instance);
}; };
const instance = new rawWasm.Editor(rustCallback); const instance = new rawWasm.JsEditorHandle(rustCallback);
return { return {
dispatcher, dispatcher,
+25 -12
View File
@@ -2,37 +2,40 @@
// It serves as a thin wrapper over the editor backend API that relies // It serves as a thin wrapper over the editor backend API that relies
// on the dispatcher messaging system and more complex Rust data types. // on the dispatcher messaging system and more complex Rust data types.
use std::cell::{Cell, UnsafeCell}; use std::cell::Cell;
use crate::helpers::Error; use crate::helpers::Error;
use crate::type_translators::{translate_blend_mode, translate_key, translate_tool_type}; use crate::type_translators::{translate_blend_mode, translate_key, translate_tool_type};
use crate::EDITOR_HAS_CRASHED; use crate::{EDITOR_HAS_CRASHED, EDITOR_INSTANCES};
use editor::consts::FILE_SAVE_SUFFIX; use editor::consts::FILE_SAVE_SUFFIX;
use editor::input::input_preprocessor::ModifierKeys; use editor::input::input_preprocessor::ModifierKeys;
use editor::input::mouse::{EditorMouseState, ScrollDelta, ViewportBounds}; use editor::input::mouse::{EditorMouseState, ScrollDelta, ViewportBounds};
use editor::message_prelude::*;
use editor::misc::EditorError; use editor::misc::EditorError;
use editor::tool::{tool_options::ToolOptions, tools, ToolType}; use editor::tool::{tool_options::ToolOptions, tools, ToolType};
use editor::Color; use editor::Color;
use editor::LayerId; use editor::LayerId;
use editor::{message_prelude::*, Editor};
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
// To avoid wasm-bindgen from checking mutable reference issues using WasmRefCell // To avoid wasm-bindgen from checking mutable reference issues using WasmRefCell
// we must make all methods take a non mutable reference to self. Not doing this creates // we must make all methods take a non mutable reference to self. Not doing this creates
// an issue when rust calls into JS which calls back to rust in the same call stack. // an issue when rust calls into JS which calls back to rust in the same call stack.
#[wasm_bindgen] #[wasm_bindgen]
pub struct Editor { pub struct JsEditorHandle {
editor: UnsafeCell<editor::Editor>, editor_id: u64,
instance_received_crashed: Cell<bool>, instance_received_crashed: Cell<bool>,
handle_response: js_sys::Function, handle_response: js_sys::Function,
} }
#[wasm_bindgen] #[wasm_bindgen]
impl Editor { impl JsEditorHandle {
#[wasm_bindgen(constructor)] #[wasm_bindgen(constructor)]
pub fn new(handle_response: js_sys::Function) -> Editor { pub fn new(handle_response: js_sys::Function) -> JsEditorHandle {
Editor { let editor_id = generate_uuid();
editor: UnsafeCell::new(editor::Editor::new()), let editor = Editor::new();
EDITOR_INSTANCES.with(|instances| instances.borrow_mut().insert(editor_id, editor));
JsEditorHandle {
editor_id,
instance_received_crashed: Cell::new(false), instance_received_crashed: Cell::new(false),
handle_response, handle_response,
} }
@@ -50,9 +53,13 @@ impl Editor {
return; return;
} }
let editor = unsafe { self.editor.get().as_mut().unwrap() }; let responses = EDITOR_INSTANCES.with(|instances| {
// Dispatch the message and receive a vector of FrontendMessage responses instances
let responses = editor.handle_message(message.into()); .borrow_mut()
.get_mut(&self.editor_id)
.expect("EDITOR_INSTANCES does not contain the current editor_id")
.handle_message(message.into())
});
for response in responses.into_iter() { for response in responses.into_iter() {
// Send each FrontendMessage to the JavaScript frontend // Send each FrontendMessage to the JavaScript frontend
self.handle_response(response); self.handle_response(response);
@@ -432,6 +439,12 @@ impl Editor {
} }
} }
impl Drop for JsEditorHandle {
fn drop(&mut self) {
EDITOR_INSTANCES.with(|instances| instances.borrow_mut().remove(&self.editor_id));
}
}
/// Access a handle to WASM memory /// Access a handle to WASM memory
#[wasm_bindgen] #[wasm_bindgen]
pub fn wasm_memory() -> JsValue { pub fn wasm_memory() -> JsValue {
+5 -1
View File
@@ -6,12 +6,16 @@ pub mod type_translators;
use editor::message_prelude::FrontendMessage; use editor::message_prelude::FrontendMessage;
use logging::WasmLog; use logging::WasmLog;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap;
use std::panic; use std::panic;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
// Set up the persistent editor backend state // Set up the persistent editor backend state
static LOGGER: WasmLog = WasmLog; static LOGGER: WasmLog = WasmLog;
thread_local! { pub static EDITOR_HAS_CRASHED: RefCell<Option<FrontendMessage>> = RefCell::new(None); } thread_local! {
pub static EDITOR_HAS_CRASHED: RefCell<Option<FrontendMessage>> = RefCell::new(None);
pub static EDITOR_INSTANCES: RefCell<HashMap<u64, editor::Editor>> = RefCell::new(HashMap::new());
}
// Initialize the backend // Initialize the backend
#[wasm_bindgen(start)] #[wasm_bindgen(start)]