swc-project/swc · critical

Should able to read memory from given ptr

Error message

Should able to read memory from given ptr

What it means

Thrown by swc_plugin_runner when the host side of the SWC wasm-plugin bridge copies bytes out of the plugin's linear memory: caller.read_buf(bytes_ptr, buf) failed for the (ptr, len) pair the plugin passed to a host-imported function. It means the pointer range is outside the plugin guest's current memory bounds, or points at stale/freed memory. This is a Rust panic (expect), so it aborts the embedding process unless caught.

Source

Thrown at crates/swc_plugin_runner/src/memory_interop.rs:16

use swc_common::plugin::serialized::PluginSerializedBytes;

use crate::runtime;

#[cfg_attr(debug_assertions, tracing::instrument(level = "info", skip_all))]
pub fn copy_bytes_into_host(
    caller: &dyn runtime::Caller<'_>,
    bytes_ptr: i32,
    bytes_ptr_len: i32,
    buf: &mut Vec<u8>,
) {
    let len: usize = bytes_ptr_len.try_into().unwrap();
    buf.resize(len, 0);
    caller
        .read_buf(bytes_ptr as u32, buf)
        .expect("Should able to read memory from given ptr");
}

/// Locate a view from given memory, write serialized bytes into.
#[cfg_attr(debug_assertions, tracing::instrument(level = "info", skip_all))]
pub fn write_into_memory_view<F>(
    view: &mut dyn runtime::Caller<'_>,
    serialized_bytes: &PluginSerializedBytes,
    get_allocated_ptr: F,
) -> (u32, u32)
where
    F: Fn(&mut dyn runtime::Caller<'_>, usize) -> u32,
{
    let serialized_len = serialized_bytes.as_slice().len();

    let ptr_start = get_allocated_ptr(view, serialized_len);
    let serialized_size = serialized_len
        .try_into()
        .expect("Should be able to convert to i32");

View on GitHub (pinned to 5176682b65)

Solutions

  1. Rebuild the plugin against the exact swc_core version required by the swc/@swc/core version you run (check the plugin's compatibility table) and target wasm32-wasi.
  2. Upgrade or pin the host (swc crate or @swc/core npm package) to the version matching the plugin.
  3. Reproduce with debug_assertions enabled to get the tracing spans (copy_bytes_into_host is instrumented) showing which host import received the bad pointer.
  4. Isolate plugin transforms with std::panic::catch_unwind or a subprocess/worker so a buggy plugin cannot abort the whole build.

Example fix

// before: plugin panic kills the whole compiler process
let out = compiler.process_js_file(&fm, &handler, &config)?;

// after: isolate plugin-bearing transforms and degrade gracefully
let out = match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    compiler.process_js_file(&fm, &handler, &config)
})) {
    Ok(Ok(res)) => res,
    Ok(Err(e)) => return Err(e),
    Err(payload) => {
        tracing::error!(?payload, "swc plugin passed a bad ptr; retrying without plugins");
        let cfg_no_plugins = strip_plugins(config);
        compiler.process_js_file(&fm, &handler, &cfg_no_plugins)?
    }
};
Defensive patterns

Strategy: try-catch

Try / catch

// The failure is a host-side panic, so the only catch site is catch_unwind
// (or a subprocess). Isolate every plugin-bearing transform.
use std::panic::{catch_unwind, AssertUnwindSafe};

fn run_with_plugins<T>(f: impl FnOnce() -> anyhow::Result<T>) -> anyhow::Result<T> {
    match catch_unwind(AssertUnwindSafe(f)) {
        Ok(res) => res,
        Err(payload) => {
            let msg = payload
                .downcast_ref::<&str>()
                .map(|s| s.to_string())
                .or_else(|| payload.downcast_ref::<String>().cloned())
                .unwrap_or_else(|| "unknown plugin panic".into());
            anyhow::bail!("swc plugin panicked: {msg}")
        }
    }
}

Prevention

When it happens

Trigger: A plugin calls a host import that takes (ptr, len) arguments (transform result retrieval, comments proxy, source-map proxy, diagnostics) with a pointer that was freed, was computed before a memory.grow, or exceeds the wasm memory size; also when the plugin binary's ABI does not match the host runtime.

Common situations: Plugin compiled with a swc_core version that does not match the host swc version (schema/ABI drift); plugin built for the wrong wasm target; plugin panicking or corrupting its own allocator mid-transform; extremely large serialized payloads overflowing the guest heap.

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/4f6f5591b9b3cf4a. Report an issue: GitHub.