windmill-labs/windmill · error

fwrite is not supported

Error message

fwrite is not supported

What it means

`fwrite` (write blocks of memory to a FILE*) is an unimplemented libc shim in the R parser WASM runtime that panics on entry. The sandbox provides no stream output, so any binary/structured write to a FILE* aborts the WASM execution.

Source

Thrown at backend/parsers/windmill-parser-r/src/wasm_libc.rs:266

#[no_mangle]
pub unsafe extern "C" fn fdopen(_fd: c_int, _mode: *const c_void) -> *mut c_void {
    panic!("fdopen is not supported");
}

#[no_mangle]
pub unsafe extern "C" fn fclose(_file: *mut c_void) -> c_int {
    panic!("fclose is not supported");
}

#[no_mangle]
pub unsafe extern "C" fn fwrite(
    _ptr: *const c_void,
    _size: usize,
    _nmemb: usize,
    _stream: *mut c_void,
) -> usize {
    panic!("fwrite is not supported");
}

#[no_mangle]
pub unsafe extern "C" fn vsnprintf(
    _buf: *mut c_char,
    _size: usize,
    _format: *const c_char,
    _args: ...
) -> c_int {
    panic!("vsnprintf is not supported");
}

#[no_mangle]
pub extern "C" fn clock_gettime(ptr: usize, new_size: usize) {
    panic!("clock_gettime is not supported");
}

// int snprintf( char* restrict buffer, size_t bufsz, const char* restrict format, ... );

View on GitHub (pinned to e474e8803c)

Solutions

  1. Rewrite the producing code to return data through supported channels instead of stream writes
  2. Implement fwrite in wasm_libc.rs to forward the buffer to the host output
  3. Remove or replace the dependency that performs binary stream writes
  4. Convert output to string-based calls (if printf-family variants are supported) before writing

Example fix

// before (stub)
#[no_mangle]
pub unsafe extern "C" fn fwrite(_ptr: *const c_void, _size: usize, _nmemb: usize, _stream: *mut c_void) -> usize {
    panic!("fwrite is not supported");
}
// after (forward buffer to host stdout)
#[no_mangle]
pub unsafe extern "C" fn fwrite(ptr: *const c_void, size: usize, nmemb: usize, _stream: *mut c_void) -> usize {
    let bytes = std::slice::from_raw_parts(ptr as *const u8, size.saturating_mul(nmemb));
    use std::io::Write;
    let n = std::io::stdout().write(bytes).unwrap_or(0);
    n as usize
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Reject binary stream writes before running in the sandbox
if (/\b(fwrite|writeBin|saveRDS)\s*\(/.test(rSource)) {
  throw new Error("binary stream writes (fwrite) are unsupported in the R parser WASM");
}

Type guard

fn fwrite_target_is_host(stream: *mut c_void) -> bool { false } // no valid FILE* exists; all fwrite targets would panic

Try / catch

match std::panic::catch_unwind(|| run_wasm_r(source)) {
    Ok(v) => v,
    Err(p) if panic_msg(&p).contains("fwrite is not supported") => {
        // re-serialize output via a supported channel (return value / string output) and retry
        run_wasm_r(&rewrite_stream_writes_to_return_value(source))
    }
    Err(p) => std::panic::resume_unwind(p),
}

Prevention

When it happens

Trigger: Calling the exported `fwrite` shim at backend/parsers/windmill-parser-r/src/wasm_libc.rs:266, reached when compiled code serializes data or writes buffers to stdout/stderr/files via fwrite.

Common situations: R code calls writeBin/saveRDS-style paths compiled to fwrite; C dependencies dump binary buffers; logging libraries write records with fwrite.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/88657cc58b9a664b. Report an issue: GitHub.