{"record":{"id":"3e59bde5669dd6ef","repo":"swc-project/swc","slug":"should-able-to-write-into-memory-view","errorCode":null,"errorMessage":"Should able to write into memory view","messagePattern":"Should able to write into memory view","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/swc_plugin_runner/src/memory_interop.rs","lineNumber":38,"sourceCode":"#[cfg_attr(debug_assertions, tracing::instrument(level = \"info\", skip_all))]\npub fn write_into_memory_view<F>(\n    view: &mut dyn runtime::Caller<'_>,\n    serialized_bytes: &PluginSerializedBytes,\n    get_allocated_ptr: F,\n) -> (u32, u32)\nwhere\n    F: Fn(&mut dyn runtime::Caller<'_>, usize) -> u32,\n{\n    let serialized_len = serialized_bytes.as_slice().len();\n\n    let ptr_start = get_allocated_ptr(view, serialized_len);\n    let serialized_size = serialized_len\n        .try_into()\n        .expect(\"Should be able to convert to i32\");\n\n    // Note: it's important to get a view from memory _after_ alloc completes\n    view.write_buf(ptr_start, serialized_bytes.as_slice())\n        .expect(\"Should able to write into memory view\");\n\n    (ptr_start, serialized_size)\n}\n\n/// Set `return` value to pass into guest from functions returning values with\n/// non-deterministic size like `Vec<Comment>`. Guest pre-allocates a struct to\n/// contain ptr to the value, host in here allocates guest memory for the actual\n/// value then returns its ptr with length to the preallocated struct.\n#[cfg_attr(debug_assertions, tracing::instrument(level = \"info\", skip_all))]\npub fn allocate_return_values_into_guest(\n    caller: &mut dyn runtime::Caller<'_>,\n    allocated_ret_ptr: u32,\n    serialized_bytes: &PluginSerializedBytes,\n) {\n    let serialized_bytes_len: usize = serialized_bytes.as_slice().len();\n    let serialized_bytes_len = serialized_bytes_len\n        .try_into()\n        .expect(\"Should be able to convert size\");","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_plugin_runner/src/memory_interop.rs#L20-L56","documentation":"After the guest allocator returns a pointer, the host writes the serialized program bytes into the plugin's wasm memory via view.write_buf(ptr_start, bytes). The expect panics when that write crosses the guest memory bounds - the allocator returned a bad pointer, the guest could not grow its memory (wasm max / store limits), or the pointer was computed against a different memory snapshot.","triggerScenarios":"write_into_memory_view during PluginTransformExecutor::run: guest alloc 'succeeds' but ptr+len exceeds current memory size; guest memory.grow failed so the region is not mapped; plugin's allocator is corrupted or from an ABI-mismatched build.","commonSituations":"Very large files plus plugins that force big serialized AST copies; plugin built with mismatched swc_core (allocator protocol differs); wasm store memory limits configured in the embedding runtime.","solutions":["Align the plugin's swc_core version with the host swc version and rebuild with wasm32-wasi --release.","Reduce the payload: transform per module, keep files a reasonable size, avoid plugins on giant generated files.","Capture the panic boundary with catch_unwind/subprocess isolation so the build reports the file instead of aborting.","Check the plugin does not override or break the allocator (no custom global allocator in the guest)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Wrap the whole plugin transform (alloc + write into guest memory) so an\n// out-of-bounds write is a per-file error, not a process abort.\nlet out = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    compiler.process_js_file(&fm, &handler, &config_with_plugins)\n}));\nlet out = match out {\n    Ok(r) => r,\n    Err(_) => {\n        tracing::error!(file = %fm.name, \"plugin guest memory write failed; retrying without plugins\");\n        compiler.process_js_file(&fm, &handler, &config_without_plugins)\n    }\n};","preventionTips":["Match plugin swc_core and host swc versions exactly on every upgrade.","Keep per-file sizes moderate; huge files multiply serialized-copy pressure on guest memory.","Run plugin transforms in a dedicated worker process for hard isolation.","Watch for wasm store memory limits configured by your embedding runtime."],"tags":["wasm","plugin","memory","panic","swc-plugin-runner"],"backgroundTag":"wasm-memory-out-of-bounds","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}