wasmerio/wasmer · error

Failed to convert size to offset

Error message

Failed to convert size to offset

What it means

write_dl_error copies a dlopen error message plus a NUL terminator into guest memory. The computed length (err_len + 1, always positive and bounded by err_buf_len which is a u64 widened to usize) must be convertible to the memory's Offset type (u32 for memory32); if not, the code panics with "Failed to convert size to offset". With a 4GiB-1 guest buffer in memory32 this can occur, though offset conversion normally bounds it.

Source

Thrown at lib/wasix/src/syscalls/wasix/dlopen.rs:98

    let err_buf_len = err_buf_len as usize;

    // The message is always written with a trailing NUL, so a zero-length
    // buffer leaves no room for anything.
    if err_buf_len == 0 {
        return Ok(());
    }

    // Reserve one byte for the trailing NUL.
    let max_err_len = err_buf_len - 1;
    let mut err_len = err.len();

    if err_len > max_err_len {
        err_len = max_err_len;
        err = &err[..err_len];
    }

    let Ok(err_len_offset) = M::Offset::try_from(err_len + 1) else {
        panic!("Failed to convert size to offset")
    };
    let mut err_buf = err_buf.slice(memory, err_len_offset)?.access()?;
    let dst = err_buf.as_mut();
    dst[..err_len].copy_from_slice(err.as_bytes());
    dst[err_len] = 0;

    Ok(())
}

#[cfg(all(test, not(target_arch = "wasm32")))]
mod tests {
    use super::write_dl_error;
    use wasmer::{Memory, Memory32, MemoryType, Store, WasmPtr};

    #[test]
    fn write_dl_error_zero_len_buffer_writes_nothing() {
        let mut store = Store::default();
        let memory = Memory::new(&mut store, MemoryType::new(1, None, false)).unwrap();

View on GitHub (pinned to 8c4b9ee9d3)

Solutions

  1. Pass a sane err_buf_len (the real byte size of your error buffer) to dlopen/dlsym.
  2. Validate err_buf_len in the guest before the call; keep it within the memory's addressable size.
  3. If you maintain the runtime, return Errno::Inval/Overflow instead of panicking on the try_from failure.
  4. Check whether a signed-to-unsigned conversion bug in the guest is producing the huge length.

Example fix

// before (guest C)
dlopen(path, flags, err_buf, (size_t)-1, ...);
// after
char err_buf[256]; dlopen(path, flags, err_buf, sizeof(err_buf), ...);
Defensive patterns

Strategy: validation

Validate before calling

// Guest side, before calling dlopen
if (err_buf_len == 0 || err_buf_len > (1ULL << 31)) {
    err_buf_len = sizeof(err_buf); // clamp to the real buffer size
}

Prevention

When it happens

Trigger: A dlopen/dlsym error occurs and the guest supplied an err_buf_len so large that err_len + 1 cannot be represented as M::Offset (only feasible with 64-bit lengths on a 32-bit memory, i.e. err_buf_len near u64::MAX).

Common situations: Guest passing a bogus/huge err_buf_len (e.g. usize::MAX or -1 as u32 wrap) when calling dlopen on a failing module load; memory32 environments where the slice cannot be created.

Related errors


AI-assisted analysis of wasmerio/wasmer@8c4b9ee9d3 (2026-09-01). Data as JSON: /api/errors/0bd8de27a84ccc9f. Report an issue: GitHub.