diff --git a/static/js/wasm-terminal.js b/static/js/wasm-terminal.js index 91e23a2e6..894bbf943 100644 --- a/static/js/wasm-terminal.js +++ b/static/js/wasm-terminal.js @@ -285,6 +285,27 @@ async function runCommand(argv, stdinData = "") { return 0; }; + // Workaround: browser_wasi_shim Filestat.write_bytes() only writes the + // defined fields and skips padding bytes (e.g. bytes 17-23 between the + // 1-byte filetype and the 8-byte nlink). Rust allocates the stat buffer + // with MaybeUninit (uninitialized stack memory), so those padding bytes + // contain garbage that corrupts the struct when Rust reads it back. + // Fix: patch write_bytes to zero padding before writing fields. + // Monkey-patch write_bytes to also write the padding/nlink fields that + // the original skips. The original writes filetype as a single byte at + // ptr+16 but leaves bytes 17-23 untouched. On WASM those bytes come from + // uninitialized stack memory (MaybeUninit) and corrupt the struct. + wasiShim.wasi.Filestat.prototype.write_bytes = function(view, ptr) { + view.setBigUint64(ptr, this.dev, true); + view.setBigUint64(ptr + 8, this.ino, true); + view.setBigUint64(ptr + 16, BigInt(this.filetype), true); // zero-extends, clearing padding + view.setBigUint64(ptr + 24, this.nlink, true); + view.setBigUint64(ptr + 32, this.size, true); + view.setBigUint64(ptr + 40, this.atim, true); + view.setBigUint64(ptr + 48, this.mtim, true); + view.setBigUint64(ptr + 56, this.ctim, true); + }; + let exitCode = 0; try { const result = await WebAssembly.instantiate(wasmModule, { diff --git a/static/js/wasm-terminal.test.html b/static/js/wasm-terminal.test.html index e90393af1..9547ad24c 100644 --- a/static/js/wasm-terminal.test.html +++ b/static/js/wasm-terminal.test.html @@ -453,6 +453,10 @@ async function runTests() { lsAl.includes(".."), true); assert("ls -al does not show 1970 date", lsAl.includes("1970"), false); + // File sizes should be reasonable (< 1000 bytes for sample files) + const sizeMatch = lsAl.match(/(\d+)\s+\w+\s+\d+.*csv\.txt/); + assert("csv.txt size is reasonable", + sizeMatch && parseInt(sizeMatch[1]) < 1000, true); // ===== UTF-8 / multibyte WASM tests ===== section("UTF-8 multibyte WASM");