Repository: wasmerio/wasmer (language: rust)

Issue:
WASIX: Working Directory mismatch 
There seems to be a problem with working directory handling in the runtime and in the WASIX libc.

To illustrate:

`wasmer --dir .` is supposed to mount the current dir at `/home` , and to set the working dir to `/home`.

```
wasmer run wasmer/python --dir . -- -c "import os; print(os.getcwd())"
> `/home`
```

This works correctly!

But:
`wasmer run wasmer/python --dir . -- -c "import os; os.makedirs('./test123)"`

This succeeds, but the directory is not created on the host file system.

Investigation reveals that `os.getcwd()` here leads to the `getcwd()` syscall being invoked, so it returns the expected value.
But the path_create syscall invoked actually uses the path `/test123`, so apth resolution logic in libc assumes the CWD to be `/`.



Discussion / hints:

Fix patch:
diff --git a/lib/wasix/src/runners/wasi.rs b/lib/wasix/src/runners/wasi.rs
index 5441ec2405d..445dea45818 100644
--- a/lib/wasix/src/runners/wasi.rs
+++ b/lib/wasix/src/runners/wasi.rs
@@ -262,6 +262,18 @@ impl WasiRunner {
             None
         };
 
+        if self.wasi.is_home_mapped {
+            builder.set_current_dir(MAPPED_CURRENT_DIR_DEFAULT_PATH);
+        }
+
+        if let Some(current_dir) = &self.wasi.current_dir {
+            builder.set_current_dir(current_dir.clone());
+        }
+
+        if let Some(cwd) = &wasi.cwd {
+            builder.set_current_dir(cwd);
+        }
+
         self.wasi
             .prepare_webc_env(&mut builder, container_fs, wasi, root_fs)?;
 
@@ -275,13 +287,6 @@ impl WasiRunner {
             builder.set_stderr(Box::new(stderr.clone()));
         }
 
-        if self.wasi.is_home_mapped {
-            builder.set_current_dir(MAPPED_CURRENT_DIR_DEFAULT_PATH);
-        }
-        if let Some(current_dir) = &self.wasi.current_dir {
-            builder.set_current_dir(current_dir.clone());
-        }
-
         Ok(builder)
     }
 
@@ -377,10 +382,6 @@ impl crate::runners::Runner for WasiRunner {
             }
         }
 
-        if let Some(cwd) = &wasi.cwd {
-            env.set_current_dir(cwd);
-        }
-
         let env = env.build()?;
         let store = runtime.new_store();
 
diff --git a/lib/wasix/src/runners/wasi_common.rs b/lib/wasix/src/runners/wasi_common.rs
index 7bdf41b3a6f..3606f131e55 100644
--- a/lib/wasix/src/runners/wasi_common.rs
+++ b/lib/wasix/src/runners/wasi_common.rs
@@ -73,7 +73,8 @@ impl CommonWasiOptions {
 
         if self.mounts.iter().all(|m| m.guest != ".") {
             // The user hasn't mounted "." to anything, so let's map it to "/"
-            builder.add_map_dir(".", "/")?;
+            let path = builder.get_current_dir().unwrap_or(PathBuf::from("/"));
+            builder.add_map_dir(".", path)?;
         }
 
         builder.set_fs(Box::new(fs));
diff --git a/lib/wasix/src/state/builder.rs b/lib/wasix/src/state/builder.rs
index 56b05f0419c..f41326cca91 100644
--- a/lib/wasix/src/state/builder.rs
+++ b/lib/wasix/src/state/builder.rs
@@ -579,6 +579,10 @@ impl WasiEnvBuilder {
         self.journals.push(journal);
     }
 
+    pub fn get_current_dir(&mut self) -> Option<PathBuf> {
+        self.current_dir.clone()
+    }
+
     pub fn set_current_dir(&mut self, dir: impl Into<PathBuf>) {
         self.current_dir = Some(dir.into());
     }


Test patch:
diff --git a/tests/wasix/create-dir-at-cwd-with-chdir/main.c b/tests/wasix/create-dir-at-cwd-with-chdir/main.c
new file mode 100644
index 00000000000..e98c7133e89
--- /dev/null
+++ b/tests/wasix/create-dir-at-cwd-with-chdir/main.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+// the difference between this test and the one in create-dir-at-cwd is the
+// presence of chdir.
+
+// this will force chdir to be linked with this binary which in turn will change 
+// the behavior of rel_path logic the libc. 
+//
+// for more info see: libc-find-relpath.h in wasix-libc
+int (*dummy_chdir_ref)(const char *path) = chdir;
+
+int main() {
+    int status = EXIT_FAILURE;
+
+    const char *dirName1 = "test1";
+    if (mkdir(dirName1, 0755) != 0) {
+        goto end;
+    }
+
+    const char *dirName2 = "./test2";
+    if (mkdir(dirName2, 0755) != 0) {
+        goto end;
+    }
+
+    status = EXIT_SUCCESS;
+
+end:
+    printf("%d", status);
+    return 0;
+}
diff --git a/tests/wasix/create-dir-at-cwd-with-chdir/run.sh b/tests/wasix/create-dir-at-cwd-with-chdir/run.sh
new file mode 100755
index 00000000000..66be3793d6b
--- /dev/null
+++ b/tests/wasix/create-dir-at-cwd-with-chdir/run.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+$WASMER -q run main.wasm --dir . > output
+
+rmdir test1 test2 2>/dev/null && printf "0" | diff -u output - 1>/dev/null
diff --git a/tests/wasix/create-dir-at-cwd/main.c b/tests/wasix/create-dir-at-cwd/main.c
new file mode 100644
index 00000000000..5e36441ef2e
--- /dev/null
+++ b/tests/wasix/create-dir-at-cwd/main.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+int main() {
+    int status = EXIT_FAILURE;
+
+    const char *dirName1 = "test1";
+    if (mkdir(dirName1, 0755) != 0) {
+        goto end;
+    }
+
+    const char *dirName2 = "./test2";
+    if (mkdir(dirName2, 0755) != 0) {
+        goto end;
+    }
+
+    status = EXIT_SUCCESS;
+
+end:
+    printf("%d", status);
+    return 0;
+}
diff --git a/tests/wasix/create-dir-at-cwd/run.sh b/tests/wasix/create-dir-at-cwd/run.sh
new file mode 100755
index 00000000000..66be3793d6b
--- /dev/null
+++ b/tests/wasix/create-dir-at-cwd/run.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+$WASMER -q run main.wasm --dir . > output
+
+rmdir test1 test2 2>/dev/null && printf "0" | diff -u output - 1>/dev/null