Repository: bytecodealliance/wasmtime
Pull request #7656 (2023-12-08 02:54:43)

[bindgen] Include Version in the export name if needed
<!--
Please make sure you include the following information:

- If this work has been discussed elsewhere, please include a link to that
  conversation. If it was discussed in an issue, just mention "issue #...".

- Explain why this change is needed. If the details are in an issue already,
  this can be brief.

Our development process is documented in the Wasmtime book:
https://docs.wasmtime.dev/contributing-development-process.html

Please ensure all communication follows the code of conduct:
https://github.com/bytecodealliance/wasmtime/blob/main/CODE_OF_CONDUCT.md
-->

When exporting multiple versions of the same package the version name needs to be included.

Before this change the generator would produce:

```
pub fn test_dep_test(&self) -> &exports::test::dep0_1_0::test::Test { &self.interface1 } 
pub fn test_dep_test(&self) -> &exports::test::dep0_2_0::test::Test { &self.interface2 }
```

now it will produce: 

```
pub fn test_dep_0_1_0_test(&self) -> &exports::test::dep0_1_0::test::Test { &self.interface1 } 
pub fn test_dep_0_2_0_test(&self) -> &exports::test::dep0_2_0::test::Test { &self.interface2 }
```

Found in https://github.com/bytecodealliance/wit-bindgen/pull/787/files#r1416724258
Discussed in https://bytecodealliance.zulipchat.com/#narrow/stream/327223-wit-bindgen/topic/Host.20Exports.20across.20versions


alexcrichton: Personally at least, yes, I think all bindings generators should drop versions unless there's an ambiguity. Helps promotes the use of versions I think without causing all the generated bindings to look terrible ideally. I haven't gotten around to implementing this much elsewhere other than the Wasmtime host and Rust guest generators though.

Patch:
diff --git a/crates/wasi-preview1-component-adapter/src/descriptors.rs b/crates/wasi-preview1-component-adapter/src/descriptors.rs
index 0c9cab019..23e0a45d4 100644
--- a/crates/wasi-preview1-component-adapter/src/descriptors.rs
+++ b/crates/wasi-preview1-component-adapter/src/descriptors.rs
@@ -20,6 +20,8 @@ pub enum Descriptor {
 
     /// Input and/or output wasi-streams, along with stream metadata.
     Streams(Streams),
+
+    Bad,
 }
 
 /// Input and/or output wasi-streams, along with a stream type that
@@ -358,7 +360,7 @@ impl Descriptors {
     ) -> Result<&mut Streams, Errno> {
         match self.get_mut(fd)? {
             Descriptor::Streams(streams) => Ok(streams),
-            Descriptor::Closed(_) => Err(error),
+            Descriptor::Closed(_) | Descriptor::Bad => Err(error),
         }
     }
 
@@ -420,14 +422,14 @@ impl Descriptors {
     pub fn get_read_stream(&self, fd: Fd) -> Result<&InputStream, Errno> {
         match self.get(fd)? {
             Descriptor::Streams(streams) => streams.get_read_stream(),
-            Descriptor::Closed(_) => Err(wasi::ERRNO_BADF),
+            Descriptor::Closed(_) | Descriptor::Bad => Err(wasi::ERRNO_BADF),
         }
     }
 
     pub fn get_write_stream(&self, fd: Fd) -> Result<&OutputStream, Errno> {
         match self.get(fd)? {
             Descriptor::Streams(streams) => streams.get_write_stream(),
-            Descriptor::Closed(_) => Err(wasi::ERRNO_BADF),
+            Descriptor::Closed(_) | Descriptor::Bad => Err(wasi::ERRNO_BADF),
         }
     }
 }
diff --git a/crates/wasi-preview1-component-adapter/src/lib.rs b/crates/wasi-preview1-component-adapter/src/lib.rs
index b19f8c948..59561f3ef 100644
--- a/crates/wasi-preview1-component-adapter/src/lib.rs
+++ b/crates/wasi-preview1-component-adapter/src/lib.rs
@@ -145,6 +145,26 @@ impl<T, E> TrappingUnwrap<T> for Result<T, E> {
     }
 }
 
+/// Allocate a file descriptor which will generate an `ERRNO_BADF` if passed to
+/// any WASI Preview 1 function implemented by this adapter.
+///
+/// This is intended for use by `wasi-libc` during its incremental transition
+/// from WASI Preview 1 to Preview 2.  It will use this function to reserve
+/// descriptors for its own use, valid only for use with libc functions.
+#[no_mangle]
+pub unsafe extern "C" fn adapter_open_badfd(fd: *mut u32) -> bool {
+    State::with(|state| {
+        *fd = state.descriptors_mut().open(Descriptor::Bad)?;
+        Ok(())
+    }) == wasi::ERRNO_SUCCESS
+}
+
+/// Close a descriptor previously opened using `adapter_open_badfd`.
+#[no_mangle]
+pub unsafe extern "C" fn adapter_close_badfd(fd: u32) -> bool {
+    State::with(|state| state.descriptors_mut().close(fd)) == wasi::ERRNO_SUCCESS
+}
+
 #[no_mangle]
 pub unsafe extern "C" fn reset_adapter_state() {
     let state = get_state_ptr();
@@ -525,6 +545,10 @@ pub unsafe extern "C" fn fd_allocate(fd: Fd, _offset: Filesize, _len: Filesize)
 #[no_mangle]
 pub unsafe extern "C" fn fd_close(fd: Fd) -> Errno {
     State::with(|state| {
+        if let Descriptor::Bad = state.descriptors().get(fd)? {
+            return Err(wasi::ERRNO_BADF);
+        }
+
         // If there's a dirent cache entry for this file descriptor then drop
         // it since the descriptor is being closed and future calls to
         // `fd_readdir` should return an error.
@@ -669,7 +693,7 @@ pub unsafe extern "C" fn fd_fdstat_get(fd: Fd, stat: *mut Fdstat) -> Errno {
                     });
                     Ok(())
                 }
-                Descriptor::Closed(_) => Err(ERRNO_BADF),
+                Descriptor::Closed(_) | Descriptor::Bad => Err(ERRNO_BADF),
             }
         })
     }
@@ -716,7 +740,7 @@ pub unsafe extern "C" fn fd_fdstat_set_rights(
         let ds = state.descriptors();
         match ds.get(fd)? {
             Descriptor::Streams(..) => Ok(()),
-            Descriptor::Closed(..) => Err(wasi::ERRNO_BADF),
+            Descriptor::Closed(..) | Descriptor::Bad => Err(wasi::ERRNO_BADF),
         }
     })
 }
@@ -1028,7 +1052,7 @@ pub unsafe extern "C" fn fd_read(
                 forget(data);
                 Ok(())
             }
-            Descriptor::Closed(_) => Err(ERRNO_BADF),
+            Descriptor::Closed(_) | Descriptor::Bad => Err(ERRNO_BADF),
         }
     })
 }
@@ -1446,7 +1470,7 @@ pub unsafe extern "C" fn fd_write(
                 *nwritten = nbytes;
                 Ok(())
             }
-            Descriptor::Closed(_) => Err(ERRNO_BADF),
+            Descriptor::Closed(_) | Descriptor::Bad => Err(ERRNO_BADF),
         }
     })
 }
diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs
index eca7fd391..2c1422f59 100644
--- a/crates/wit-bindgen/src/lib.rs
+++ b/crates/wit-bindgen/src/lib.rs
@@ -474,7 +474,7 @@ impl Wasmtime {
                         format!(
                             "{}_{}_{snake}",
                             pkgname.namespace.to_snake_case(),
-                            pkgname.name.to_snake_case()
+                            self.name_package_module(resolve, iface.package.unwrap())
                         ),
                     ),
                     None => (format!("exports::{snake}::{camel}"), snake.clone()),


Test patch:
diff --git a/crates/component-macro/tests/codegen/multiversion/root.wit b/crates/component-macro/tests/codegen/multiversion/root.wit
index 52225f02b..b3bb3c80d 100644
--- a/crates/component-macro/tests/codegen/multiversion/root.wit
+++ b/crates/component-macro/tests/codegen/multiversion/root.wit
@@ -3,5 +3,6 @@ package foo:bar;
 world foo {
   import my:dep/a@0.1.0;
   import my:dep/a@0.2.0;
+  export my:dep/a@0.1.0;
   export my:dep/a@0.2.0;
 }
diff --git a/crates/test-programs/src/bin/preview2_adapter_badfd.rs b/crates/test-programs/src/bin/preview2_adapter_badfd.rs
new file mode 100644
index 000000000..7baa33717
--- /dev/null
+++ b/crates/test-programs/src/bin/preview2_adapter_badfd.rs
@@ -0,0 +1,46 @@
+fn main() {
+    #[link(wasm_import_module = "wasi_snapshot_preview1")]
+    extern "C" {
+        #[cfg_attr(target_arch = "wasm32", link_name = "adapter_open_badfd")]
+        fn adapter_open_badfd(fd: *mut u32) -> bool;
+
+        #[cfg_attr(target_arch = "wasm32", link_name = "adapter_close_badfd")]
+        fn adapter_close_badfd(fd: u32) -> bool;
+    }
+
+    unsafe {
+        let mut fd = 0;
+        assert!(adapter_open_badfd(&mut fd));
+
+        assert_eq!(wasi::fd_close(fd), Err(wasi::ERRNO_BADF));
+
+        assert_eq!(wasi::fd_fdstat_get(fd).map(drop), Err(wasi::ERRNO_BADF));
+
+        assert_eq!(wasi::fd_fdstat_set_rights(fd, 0, 0), Err(wasi::ERRNO_BADF));
+
+        let mut buffer = [0_u8; 1];
+        assert_eq!(
+            wasi::fd_read(
+                fd,
+                &[wasi::Iovec {
+                    buf: buffer.as_mut_ptr(),
+                    buf_len: 1
+                }]
+            ),
+            Err(wasi::ERRNO_BADF)
+        );
+
+        assert_eq!(
+            wasi::fd_write(
+                fd,
+                &[wasi::Ciovec {
+                    buf: buffer.as_ptr(),
+                    buf_len: 1
+                }]
+            ),
+            Err(wasi::ERRNO_BADF)
+        );
+
+        assert!(adapter_close_badfd(fd));
+    }
+}
diff --git a/crates/wasi/tests/all/async_.rs b/crates/wasi/tests/all/async_.rs
index 49ba0c52a..f47997e0e 100644
--- a/crates/wasi/tests/all/async_.rs
+++ b/crates/wasi/tests/all/async_.rs
@@ -354,3 +354,7 @@ async fn preview2_stream_pollable_traps() {
         "resource has children"
     )
 }
+#[test_log::test(tokio::test(flavor = "multi_thread"))]
+async fn preview2_adapter_badfd() {
+    run(PREVIEW2_ADAPTER_BADFD_COMPONENT, false).await.unwrap()
+}
diff --git a/crates/wasi/tests/all/sync.rs b/crates/wasi/tests/all/sync.rs
index c005ac35e..ce0c2e161 100644
--- a/crates/wasi/tests/all/sync.rs
+++ b/crates/wasi/tests/all/sync.rs
@@ -293,3 +293,7 @@ fn preview2_stream_pollable_traps() {
         "resource has children"
     )
 }
+#[test_log::test]
+fn preview2_adapter_badfd() {
+    run(PREVIEW2_ADAPTER_BADFD_COMPONENT, false).unwrap()
+}