wasmer icon indicating copy to clipboard operation
wasmer copied to clipboard

[MemFS] `fstat` reports incorrect file information

Open YuAo opened this issue 3 years ago • 5 comments

fstat reports incorrect file information when the file is rewritten.

wasmer 2.2.1 | N/A | x86_64

Steps to reproduce

fstat reported outdated file info when a file is rewritten or deleted and created again.

main.c

extern void fstat_bug(void) {
    int fd = open("/test.txt", O_RDONLY);
    struct stat fileInfo = {0};
    fstat(fd, &fileInfo);
    printf("File size: %lld", fileInfo.st_size);
    close(fd);
}

js


// Load WASM.
await init();
let wasi = new WASI({
    env: {},
    args: []
});
const moduleData = fetch(new URL('./main.wasm', import.meta.url));
const module = await WebAssembly.compileStreaming(moduleData);
const instance = await wasi.instantiate(module, {});

// 1️⃣ Create text.txt with 1 byte content.
const fileA = wasi.fs.open("/test.txt", { write: true, create: true, truncate: true });
fileA.writeString("a");

instance.exports.fstat_bug();
// ✅ File size should be 1.
console.log(wasi.getStdoutString()); // File size: 1

// 2️⃣ Remove text.txt
wasi.fs.removeFile("/test.txt");

// 3️⃣ Create a new text.txt with 3 bytes.
const fileAAA = wasi.fs.open("/test.txt", { write: true, create: true, truncate: true });
fileAAA.writeString("aaa");

instance.exports.fstat_bug();
// ❌ File size should be 3 but got 1.
console.log(wasi.getStdoutString()); // File size: 1

Expected behavior

fstat reports correct file size.

Actual behavior

fstat reports incorrect file size.

Additional context

  • If fstat is called only once at the very end the result is correct. Looks like a cache invalidation issue?

    // 1️⃣ Create text.txt with 1 byte content.
    const fileA = wasi.fs.open("/test.txt", { write: true, create: true, truncate: true });
    fileA.writeString("a");
    
    // 2️⃣ Remove text.txt
    wasi.fs.removeFile("/test.txt");
    
    // 3️⃣ Create a new text.txt with 3 bytes.
    const fileAAA = wasi.fs.open("/test.txt", { write: true, create: true, truncate: true });
    fileAAA.writeString("aaa");
    
    instance.exports.fstat_bug();
    // ✅ File size should be 3.
    console.log(wasi.getStdoutString()); // File size: 3
    
  • The file's content can be read correctly.

YuAo avatar Apr 17 '22 06:04 YuAo

After some investigation, I think this is related to how WasiFs and the js MemFS work.

MemFS (in wasmer-js package) operates the fs_backing of the WasiFs directly. When a file is updated by MemFS, its cache (WasiFs.inodes) in WasiFs does not update.

A naive approach to fix the file size issue is to call state.fs.filestat_resync_size(out_fd) in the end of pub fn path_open.

// wasi/src/syscalls/mod.rs
pub fn path_open(...) {
    ...
    let out_fd = wasi_try!(state.fs.create_fd(
        adjusted_rights,
        fs_rights_inheriting,
        fs_flags,
        open_flags,
        inode
    ));

    state.fs.filestat_resync_size(out_fd);
    
    fd_cell.set(out_fd);
    ...
}

However I don't think this solves the main problem. File operations like remove, rename, etc., should also be synced and fixes like this are error-prone.

Maybe it's better to let MemFS call methods of WasiFs instead of directly use its backing fs, or create a more robust synchronization mechanism.

YuAo avatar Apr 18 '22 04:04 YuAo

Thanks for the bug report! This seems to be an issue in the file system. This requires further investigation. We would like to keep WasiFS and MemFS separated, they should not rely on each other. Would you like to help us resolve this?

heyjdp avatar Apr 27 '22 16:04 heyjdp

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Apr 28 '23 11:04 stale[bot]

Should check if this is still relevant.

theduke avatar Apr 28 '23 11:04 theduke