Skip to content

Commit 57f0d76

Browse files
NathanFlurryclaude
andcommitted
Fix flush() to handle VirtualPipe on stdio fds
In nested subshells, fd 1 (stdout) may be replaced with a VirtualPipe from an outer subshell's dup2 operation. When fd_renumber tries to flush fd 1 before replacing it, stdout_mut() returns FsError::NotAFile because VirtualPipe is not Kind::File. This fix makes flush() handle the NotAFile case gracefully for stdio fds, since pipes don't require explicit flushing. This fixes nested backticks in bash command substitution: echo `echo \`echo hi\`` # Previously failed with "Invalid argument" The $() command substitution still fails because bash requires /dev/fd which is not yet implemented in WASIX. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ebf9a02 commit 57f0d76

File tree

1 file changed

+21
-6
lines changed

1 file changed

+21
-6
lines changed

lib/wasix/src/fs/mod.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,14 +1565,29 @@ impl WasiFs {
15651565
match fd {
15661566
__WASI_STDIN_FILENO => (),
15671567
__WASI_STDOUT_FILENO => {
1568-
let mut file =
1569-
WasiInodes::stdout_mut(&self.fd_map).map_err(fs_error_into_wasi_err)?;
1570-
file.flush().await.map_err(map_io_err)?
1568+
// stdout might have been replaced with a pipe in subshells
1569+
// Check the Kind first before trying to flush as a File
1570+
match WasiInodes::stdout_mut(&self.fd_map) {
1571+
Ok(mut file) => file.flush().await.map_err(map_io_err)?,
1572+
Err(FsError::NotAFile) => {
1573+
// fd 1 was replaced with a non-File (e.g., VirtualPipe)
1574+
// Pipes don't need explicit flushing, so just succeed
1575+
()
1576+
}
1577+
Err(e) => return Err(fs_error_into_wasi_err(e)),
1578+
}
15711579
}
15721580
__WASI_STDERR_FILENO => {
1573-
let mut file =
1574-
WasiInodes::stderr_mut(&self.fd_map).map_err(fs_error_into_wasi_err)?;
1575-
file.flush().await.map_err(map_io_err)?
1581+
// stderr might have been replaced with a pipe in subshells
1582+
match WasiInodes::stderr_mut(&self.fd_map) {
1583+
Ok(mut file) => file.flush().await.map_err(map_io_err)?,
1584+
Err(FsError::NotAFile) => {
1585+
// fd 2 was replaced with a non-File (e.g., VirtualPipe)
1586+
// Pipes don't need explicit flushing, so just succeed
1587+
()
1588+
}
1589+
Err(e) => return Err(fs_error_into_wasi_err(e)),
1590+
}
15761591
}
15771592
_ => {
15781593
let fd = self.get_fd(fd)?;

0 commit comments

Comments
 (0)