Repository: bytecodealliance/wasmtime
Pull request #9418 (2024-10-09 15:13:02)

[main] Fix backtraces through empty sequences of Wasm frames
This fixes a bug where we would not properly handle contiguous sequences of Wasm frames that are empty. This was mistakenly believed to be an impossible scenario, and before the tail-calls proposal it was impossible, however it can now happen after the following series of events:

* Host calls into Wasm, pushing the entry trampoline frame.

* Entry trampoline calls the actual Wasm function, pushing a Wasm frame.

* Wasm function tail calls to an imported host function, *replacing* the Wasm frame with the exit trampoline's frame.

Now we have a stack like `[host, entry trampoline, exit trampoline]`, which has zero Wasm frames between the entry and exit trampolines. If the host function that the exit trampoline calls out to attempts to capture a backtrace, then -- before this commit -- we would fail an internal assertion and panic. That panic would then unwind to the first Rust frame that is called by Wasm. With Rust 1.81 and later, Rust automatically inserts a panic handler that prevents the unwind from continuing into external/foreign code, which is undefined behavior, and aborts the process. Rust versions before 1.81 would attempt to continue unwinding, hitting undefined behavior.

This commit fixes the backtrace capturing machinery to handle empty sequences of Wasm frames, passes the assertion, and avoids unwinding into external/foreign code.

<!--
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
-->



Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 2bc6313f6..2b4e75f9a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3773,10 +3773,10 @@ dependencies = [
  "wasmtime-explorer",
  "wasmtime-test-macros",
  "wasmtime-wasi",
+ "wasmtime-wasi-config",
  "wasmtime-wasi-http",
  "wasmtime-wasi-keyvalue",
  "wasmtime-wasi-nn",
- "wasmtime-wasi-runtime-config",
  "wasmtime-wasi-threads",
  "wasmtime-wast",
  "wast 219.0.0",
@@ -4050,6 +4050,17 @@ dependencies = [
  "windows-sys 0.59.0",
 ]
 
+[[package]]
+name = "wasmtime-wasi-config"
+version = "27.0.0"
+dependencies = [
+ "anyhow",
+ "test-programs-artifacts",
+ "tokio",
+ "wasmtime",
+ "wasmtime-wasi",
+]
+
 [[package]]
 name = "wasmtime-wasi-http"
 version = "27.0.0"
@@ -4107,17 +4118,6 @@ dependencies = [
  "windows",
 ]
 
-[[package]]
-name = "wasmtime-wasi-runtime-config"
-version = "27.0.0"
-dependencies = [
- "anyhow",
- "test-programs-artifacts",
- "tokio",
- "wasmtime",
- "wasmtime-wasi",
-]
-
 [[package]]
 name = "wasmtime-wasi-threads"
 version = "27.0.0"
diff --git a/Cargo.toml b/Cargo.toml
index d80e7f55b..e628b0ad0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -53,7 +53,7 @@ wasmtime-wast = { workspace = true, optional = true }
 wasi-common = { workspace = true, default-features = true, features = ["exit", "tokio"], optional = true }
 wasmtime-wasi = { workspace = true, default-features = true, optional = true }
 wasmtime-wasi-nn = { workspace = true, optional = true }
-wasmtime-wasi-runtime-config = { workspace = true, optional = true }
+wasmtime-wasi-config = { workspace = true, optional = true }
 wasmtime-wasi-keyvalue = { workspace = true, optional = true }
 wasmtime-wasi-threads = { workspace = true, optional = true }
 wasmtime-wasi-http = { workspace = true, optional = true }
@@ -210,7 +210,7 @@ wasmtime-wast = { path = "crates/wast", version = "=27.0.0" }
 wasmtime-wasi = { path = "crates/wasi", version = "27.0.0", default-features = false }
 wasmtime-wasi-http = { path = "crates/wasi-http", version = "=27.0.0", default-features = false }
 wasmtime-wasi-nn = { path = "crates/wasi-nn", version = "27.0.0" }
-wasmtime-wasi-runtime-config = { path = "crates/wasi-runtime-config", version = "27.0.0" }
+wasmtime-wasi-config = { path = "crates/wasi-config", version = "27.0.0" }
 wasmtime-wasi-keyvalue = { path = "crates/wasi-keyvalue", version = "27.0.0" }
 wasmtime-wasi-threads = { path = "crates/wasi-threads", version = "27.0.0" }
 wasmtime-component-util = { path = "crates/component-util", version = "=27.0.0" }
@@ -375,7 +375,7 @@ default = [
   "wasi-nn",
   "wasi-threads",
   "wasi-http",
-  "wasi-runtime-config",
+  "wasi-config",
   "wasi-keyvalue",
 
   # Most features of Wasmtime are enabled by default.
@@ -424,7 +424,7 @@ disable-logging = ["log/max_level_off", "tracing/max_level_off"]
 wasi-nn = ["dep:wasmtime-wasi-nn"]
 wasi-threads = ["dep:wasmtime-wasi-threads", "threads"]
 wasi-http = ["component-model", "dep:wasmtime-wasi-http", "dep:tokio", "dep:hyper"]
-wasi-runtime-config = ["dep:wasmtime-wasi-runtime-config"]
+wasi-config = ["dep:wasmtime-wasi-config"]
 wasi-keyvalue = ["dep:wasmtime-wasi-keyvalue"]
 pooling-allocator = ["wasmtime/pooling-allocator", "wasmtime-cli-flags/pooling-allocator"]
 component-model = [
diff --git a/ci/vendor-wit.sh b/ci/vendor-wit.sh
index 1e83d720b..80b276f8e 100755
--- a/ci/vendor-wit.sh
+++ b/ci/vendor-wit.sh
@@ -55,7 +55,7 @@ make_vendor "wasi-http" "
   http@v0.2.2
 "
 
-make_vendor "wasi-runtime-config" "runtime-config@c667fe6"
+make_vendor "wasi-config" "config@f4d699b"
 
 make_vendor "wasi-keyvalue" "keyvalue@219ea36"
 
diff --git a/crates/cli-flags/src/lib.rs b/crates/cli-flags/src/lib.rs
index 015a9b678..aa2383ecd 100644
--- a/crates/cli-flags/src/lib.rs
+++ b/crates/cli-flags/src/lib.rs
@@ -305,8 +305,8 @@ wasmtime_option_group! {
         pub threads: Option<bool>,
         /// Enable support for WASI HTTP API (experimental)
         pub http: Option<bool>,
-        /// Enable support for WASI runtime config API (experimental)
-        pub runtime_config: Option<bool>,
+        /// Enable support for WASI config API (experimental)
+        pub config: Option<bool>,
         /// Enable support for WASI key-value API (experimental)
         pub keyvalue: Option<bool>,
         /// Inherit environment variables and file descriptors following the
@@ -346,8 +346,8 @@ wasmtime_option_group! {
         ///
         /// This option can be further overwritten with `--env` flags.
         pub inherit_env: Option<bool>,
-        /// Pass a wasi runtime config variable to the program.
-        pub runtime_config_var: Vec<KeyValuePair>,
+        /// Pass a wasi config variable to the program.
+        pub config_var: Vec<KeyValuePair>,
         /// Preset data for the In-Memory provider of WASI key-value API.
         pub keyvalue_in_memory_data: Vec<KeyValuePair>,
     }
diff --git a/crates/wasi-runtime-config/Cargo.toml b/crates/wasi-config/Cargo.toml
similarity index 82%
rename from crates/wasi-runtime-config/Cargo.toml
rename to crates/wasi-config/Cargo.toml
index 03df5d5bb..81bd61ef7 100644
--- a/crates/wasi-runtime-config/Cargo.toml
+++ b/crates/wasi-config/Cargo.toml
@@ -1,12 +1,12 @@
 [package]
-name = "wasmtime-wasi-runtime-config"
+name = "wasmtime-wasi-config"
 version.workspace = true
 authors.workspace = true
 edition.workspace = true
 rust-version.workspace = true
 repository = "https://github.com/bytecodealliance/wasmtime"
 license = "Apache-2.0 WITH LLVM-exception"
-description = "Wasmtime implementation of the wasi-runtime-config API"
+description = "Wasmtime implementation of the wasi-config API"
 
 [lints]
 workspace = true
diff --git a/crates/wasi-runtime-config/src/lib.rs b/crates/wasi-config/src/lib.rs
similarity index 63%
rename from crates/wasi-runtime-config/src/lib.rs
rename to crates/wasi-config/src/lib.rs
index 615e7b873..8d6906dfd 100644
--- a/crates/wasi-runtime-config/src/lib.rs
+++ b/crates/wasi-config/src/lib.rs
@@ -1,8 +1,8 @@
-//! # Wasmtime's [wasi-runtime-config] Implementation
+//! # Wasmtime's [wasi-config] Implementation
 //!
-//! This crate provides a Wasmtime host implementation of the [wasi-runtime-config]
+//! This crate provides a Wasmtime host implementation of the [wasi-config]
 //! API. With this crate, the runtime can run components that call APIs in
-//! [wasi-runtime-config] and provide configuration variables for the component.
+//! [wasi-config] and provide configuration variables for the component.
 //!
 //! # Examples
 //!
@@ -18,7 +18,7 @@
 //!     Config, Engine, Result, Store,
 //! };
 //! use wasmtime_wasi::{WasiCtx, WasiCtxBuilder, WasiView};
-//! use wasmtime_wasi_runtime_config::{WasiRuntimeConfig, WasiRuntimeConfigVariables};
+//! use wasmtime_wasi_config::{WasiConfig, WasiConfigVariables};
 //!
 //! #[tokio::main]
 //! async fn main() -> Result<()> {
@@ -29,7 +29,7 @@
 //!     let mut store = Store::new(&engine, Ctx {
 //!         table: ResourceTable::new(),
 //!         wasi_ctx: WasiCtxBuilder::new().build(),
-//!         wasi_runtime_config_vars: WasiRuntimeConfigVariables::from_iter(vec![
+//!         wasi_config_vars: WasiConfigVariables::from_iter(vec![
 //!             ("config_key1", "value1"),
 //!             ("config_key2", "value2"),
 //!         ]),
@@ -37,9 +37,9 @@
 //!
 //!     let mut linker = Linker::<Ctx>::new(&engine);
 //!     wasmtime_wasi::add_to_linker_async(&mut linker)?;
-//!     // add `wasi-runtime-config` world's interfaces to the linker
-//!     wasmtime_wasi_runtime_config::add_to_linker(&mut linker, |h: &mut Ctx| {
-//!         WasiRuntimeConfig::from(&h.wasi_runtime_config_vars)
+//!     // add `wasi-config` world's interfaces to the linker
+//!     wasmtime_wasi_config::add_to_linker(&mut linker, |h: &mut Ctx| {
+//!         WasiConfig::from(&h.wasi_config_vars)
 //!     })?;
 //!
 //!     // ... use `linker` to instantiate within `store` ...
@@ -50,7 +50,7 @@
 //! struct Ctx {
 //!     table: ResourceTable,
 //!     wasi_ctx: WasiCtx,
-//!     wasi_runtime_config_vars: WasiRuntimeConfigVariables,
+//!     wasi_config_vars: WasiConfigVariables,
 //! }
 //!
 //! impl WasiView for Ctx {
@@ -59,7 +59,7 @@
 //! }
 //! ```
 //!
-//! [wasi-runtime-config]: https://github.com/WebAssembly/wasi-runtime-config
+//! [wasi-config]: https://github.com/WebAssembly/wasi-config
 //! [wasi:cli]: https://docs.rs/wasmtime-wasi/latest
 //! [wasi:http]: https://docs.rs/wasmtime-wasi-http/latest
 
@@ -75,13 +75,13 @@ mod gen_ {
         trappable_imports: true,
     });
 }
-use self::gen_::wasi::config::runtime as generated;
+use self::gen_::wasi::config::store as generated;
 
-/// Capture the state necessary for use in the `wasi-runtime-config` API implementation.
+/// Capture the state necessary for use in the `wasi-config` API implementation.
 #[derive(Default)]
-pub struct WasiRuntimeConfigVariables(HashMap<String, String>);
+pub struct WasiConfigVariables(HashMap<String, String>);
 
-impl<S: Into<String>> FromIterator<(S, S)> for WasiRuntimeConfigVariables {
+impl<S: Into<String>> FromIterator<(S, S)> for WasiConfigVariables {
     fn from_iter<I: IntoIterator<Item = (S, S)>>(iter: I) -> Self {
         Self(
             iter.into_iter()
@@ -91,7 +91,7 @@ impl<S: Into<String>> FromIterator<(S, S)> for WasiRuntimeConfigVariables {
     }
 }
 
-impl WasiRuntimeConfigVariables {
+impl WasiConfigVariables {
     /// Create a new runtime configuration.
     pub fn new() -> Self {
         Default::default()
@@ -104,30 +104,30 @@ impl WasiRuntimeConfigVariables {
     }
 }
 
-/// A wrapper capturing the needed internal `wasi-runtime-config` state.
-pub struct WasiRuntimeConfig<'a> {
-    vars: &'a WasiRuntimeConfigVariables,
+/// A wrapper capturing the needed internal `wasi-config` state.
+pub struct WasiConfig<'a> {
+    vars: &'a WasiConfigVariables,
 }
 
-impl<'a> From<&'a WasiRuntimeConfigVariables> for WasiRuntimeConfig<'a> {
-    fn from(vars: &'a WasiRuntimeConfigVariables) -> Self {
+impl<'a> From<&'a WasiConfigVariables> for WasiConfig<'a> {
+    fn from(vars: &'a WasiConfigVariables) -> Self {
         Self { vars }
     }
 }
 
-impl<'a> WasiRuntimeConfig<'a> {
-    /// Create a new view into the `wasi-runtime-config` state.
-    pub fn new(vars: &'a WasiRuntimeConfigVariables) -> Self {
+impl<'a> WasiConfig<'a> {
+    /// Create a new view into the `wasi-config` state.
+    pub fn new(vars: &'a WasiConfigVariables) -> Self {
         Self { vars }
     }
 }
 
-impl generated::Host for WasiRuntimeConfig<'_> {
-    fn get(&mut self, key: String) -> Result<Result<Option<String>, generated::ConfigError>> {
+impl generated::Host for WasiConfig<'_> {
+    fn get(&mut self, key: String) -> Result<Result<Option<String>, generated::Error>> {
         Ok(Ok(self.vars.0.get(&key).map(|s| s.to_owned())))
     }
 
-    fn get_all(&mut self) -> Result<Result<Vec<(String, String)>, generated::ConfigError>> {
+    fn get_all(&mut self) -> Result<Result<Vec<(String, String)>, generated::Error>> {
         Ok(Ok(self
             .vars
             .0
@@ -137,10 +137,10 @@ impl generated::Host for WasiRuntimeConfig<'_> {
     }
 }
 
-/// Add all the `wasi-runtime-config` world's interfaces to a [`wasmtime::component::Linker`].
+/// Add all the `wasi-config` world's interfaces to a [`wasmtime::component::Linker`].
 pub fn add_to_linker<T>(
     l: &mut wasmtime::component::Linker<T>,
-    f: impl Fn(&mut T) -> WasiRuntimeConfig<'_> + Send + Sync + Copy + 'static,
+    f: impl Fn(&mut T) -> WasiConfig<'_> + Send + Sync + Copy + 'static,
 ) -> Result<()> {
     generated::add_to_linker_get_host(l, f)?;
     Ok(())
diff --git a/crates/wasi-runtime-config/wit/deps/runtime-config/runtime_config.wit b/crates/wasi-config/wit/deps/config/store.wit
similarity index 60%
rename from crates/wasi-runtime-config/wit/deps/runtime-config/runtime_config.wit
rename to crates/wasi-config/wit/deps/config/store.wit
index 29d53b1ac..794379a75 100644
--- a/crates/wasi-runtime-config/wit/deps/runtime-config/runtime_config.wit
+++ b/crates/wasi-config/wit/deps/config/store.wit
@@ -1,6 +1,6 @@
-interface runtime {
-    /// An error type that encapsulates the different errors that can occur fetching config
-    variant config-error {
+interface store {
+    /// An error type that encapsulates the different errors that can occur fetching configuration values.
+    variant error {
         /// This indicates an error from an "upstream" config source. 
         /// As this could be almost _anything_ (such as Vault, Kubernetes ConfigMaps, KeyValue buckets, etc), 
         /// the error message is a string.
@@ -14,12 +14,17 @@ interface runtime {
         io(string),
     }
 
-    /// Gets a single opaque config value set at the given key if it exists
+    /// Gets a configuration value of type `string` associated with the `key`. 
+    /// 
+    /// The value is returned as an `option<string>`. If the key is not found,
+    /// `Ok(none)` is returned. If an error occurs, an `Err(error)` is returned.
     get: func(
         /// A string key to fetch
         key: string
-    ) -> result<option<string>, config-error>;
+    ) -> result<option<string>, error>;
 
-    /// Gets a list of all set config data
-    get-all: func() -> result<list<tuple<string, string>>, config-error>;
+    /// Gets a list of configuration key-value pairs of type `string`.
+    /// 
+    /// If an error occurs, an `Err(error)` is returned.
+    get-all: func() -> result<list<tuple<string, string>>, error>;
 }
diff --git a/crates/wasi-config/wit/deps/config/world.wit b/crates/wasi-config/wit/deps/config/world.wit
new file mode 100644
index 000000000..f92f080a5
--- /dev/null
+++ b/crates/wasi-config/wit/deps/config/world.wit
@@ -0,0 +1,6 @@
+package wasi:config@0.2.0-draft;
+
+world imports {
+    /// The interface for wasi:config/store
+    import store;
+}
\ No newline at end of file
diff --git a/crates/wasi-runtime-config/wit/world.wit b/crates/wasi-config/wit/world.wit
similarity index 100%
rename from crates/wasi-runtime-config/wit/world.wit
rename to crates/wasi-config/wit/world.wit
diff --git a/crates/wasi-keyvalue/src/lib.rs b/crates/wasi-keyvalue/src/lib.rs
index c45e501f8..4d53a9acf 100644
--- a/crates/wasi-keyvalue/src/lib.rs
+++ b/crates/wasi-keyvalue/src/lib.rs
@@ -37,7 +37,7 @@
 //!
 //!     let mut linker = Linker::<Ctx>::new(&engine);
 //!     wasmtime_wasi::add_to_linker_async(&mut linker)?;
-//!     // add `wasi-runtime-config` world's interfaces to the linker
+//!     // add `wasi-keyvalue` world's interfaces to the linker
 //!     wasmtime_wasi_keyvalue::add_to_linker(&mut linker, |h: &mut Ctx| {
 //!         WasiKeyValue::new(&h.wasi_keyvalue_ctx, &mut h.table)
 //!     })?;
diff --git a/crates/wasi-runtime-config/wit/deps/runtime-config/world.wit b/crates/wasi-runtime-config/wit/deps/runtime-config/world.wit
deleted file mode 100644
index 378c4a779..000000000
--- a/crates/wasi-runtime-config/wit/deps/runtime-config/world.wit
+++ /dev/null
@@ -1,6 +0,0 @@
-package wasi:config@0.2.0-draft;
-
-world imports {
-    /// The runtime interface for config
-    import runtime;
-}
\ No newline at end of file
diff --git a/crates/wasmtime/src/runtime/vm/traphandlers/backtrace.rs b/crates/wasmtime/src/runtime/vm/traphandlers/backtrace.rs
index cf589aaf3..0c610a352 100644
--- a/crates/wasmtime/src/runtime/vm/traphandlers/backtrace.rs
+++ b/crates/wasmtime/src/runtime/vm/traphandlers/backtrace.rs
@@ -178,6 +178,26 @@ impl Backtrace {
 
         arch::assert_entry_sp_is_aligned(trampoline_sp);
 
+        // It is possible that the contiguous sequence of Wasm frames is
+        // empty. This is rare, but can happen if:
+        //
+        // * Host calls into Wasm, pushing the entry trampoline frame
+        //
+        // * Entry trampoline calls the actual Wasm function, pushing a Wasm frame
+        //
+        // * Wasm function tail calls to an imported host function, *replacing*
+        //   the Wasm frame with the exit trampoline's frame
+        //
+        // Now we have a stack like `[host, entry trampoline, exit trampoline]`
+        // which has a contiguous sequence of Wasm frames that are empty.
+        //
+        // Therefore, check if we've reached the entry trampoline's SP as the
+        // first thing we do.
+        if arch::reached_entry_sp(fp, trampoline_sp) {
+            log::trace!("=== Empty contiguous sequence of Wasm frames ===");
+            return ControlFlow::Continue(());
+        }
+
         loop {
             // At the start of each iteration of the loop, we know that `fp` is
             // a frame pointer from Wasm code. Therefore, we know it is not
diff --git a/docs/stability-tiers.md b/docs/stability-tiers.md
index 7fedfa984..42886dc71 100644
--- a/docs/stability-tiers.md
+++ b/docs/stability-tiers.md
@@ -98,14 +98,14 @@ For explanations of what each tier means see below.
 | WebAssembly Proposal | [`gc`]                            | Complete implementation     |
 | WASI Proposal        | [`wasi-nn`]                       | More expansive CI testing   |
 | WASI Proposal        | [`wasi-threads`]                  | More CI, unstable proposal  |
-| WASI Proposal        | [`wasi-runtime-config`]           | unstable proposal           |
+| WASI Proposal        | [`wasi-config`]                   | unstable proposal           |
 | WASI Proposal        | [`wasi-keyvalue`]                 | unstable proposal           |
 | *misc*               | Non-Wasmtime Cranelift usage [^1] | CI testing, full-time maintainer |
 | *misc*               | DWARF debugging [^2]              | CI testing, full-time maintainer, improved quality |
 
 [`wasi-nn`]: https://github.com/WebAssembly/wasi-nn
 [`wasi-threads`]: https://github.com/WebAssembly/wasi-threads
-[`wasi-runtime-config`]: https://github.com/WebAssembly/wasi-runtime-config
+[`wasi-config`]: https://github.com/WebAssembly/wasi-config
 [`wasi-keyvalue`]: https://github.com/WebAssembly/wasi-keyvalue
 [`gc`]: https://github.com/WebAssembly/gc
 
diff --git a/scripts/publish.rs b/scripts/publish.rs
index df0bb1248..3a3542086 100644
--- a/scripts/publish.rs
+++ b/scripts/publish.rs
@@ -67,7 +67,7 @@ const CRATES_TO_PUBLISH: &[&str] = &[
     "wasmtime-wasi",
     "wasmtime-wasi-http",
     "wasmtime-wasi-nn",
-    "wasmtime-wasi-runtime-config",
+    "wasmtime-wasi-config",
     "wasmtime-wasi-keyvalue",
     "wasmtime-wasi-threads",
     "wasmtime-wast",
@@ -88,7 +88,7 @@ const PUBLIC_CRATES: &[&str] = &[
     "wasmtime",
     "wasmtime-wasi",
     "wasmtime-wasi-nn",
-    "wasmtime-wasi-runtime-config",
+    "wasmtime-wasi-config",
     "wasmtime-wasi-keyvalue",
     "wasmtime-wasi-threads",
     "wasmtime-cli",
diff --git a/src/commands/run.rs b/src/commands/run.rs
index e8c731c32..c9abf2739 100644
--- a/src/commands/run.rs
+++ b/src/commands/run.rs
@@ -23,12 +23,12 @@ use wasmtime_wasi_nn::wit::WasiNnView;
 #[cfg(feature = "wasi-threads")]
 use wasmtime_wasi_threads::WasiThreadsCtx;
 
+#[cfg(feature = "wasi-config")]
+use wasmtime_wasi_config::{WasiConfig, WasiConfigVariables};
 #[cfg(feature = "wasi-http")]
 use wasmtime_wasi_http::WasiHttpCtx;
 #[cfg(feature = "wasi-keyvalue")]
 use wasmtime_wasi_keyvalue::{WasiKeyValue, WasiKeyValueCtx, WasiKeyValueCtxBuilder};
-#[cfg(feature = "wasi-runtime-config")]
-use wasmtime_wasi_runtime_config::{WasiRuntimeConfig, WasiRuntimeConfigVariables};
 
 fn parse_preloads(s: &str) -> Result<(String, PathBuf)> {
     let parts: Vec<&str> = s.splitn(2, '=').collect();
@@ -695,33 +695,33 @@ impl RunCommand {
             }
         }
 
-        if self.run.common.wasi.runtime_config == Some(true) {
-            #[cfg(not(feature = "wasi-runtime-config"))]
+        if self.run.common.wasi.config == Some(true) {
+            #[cfg(not(feature = "wasi-config"))]
             {
-                bail!("Cannot enable wasi-runtime-config when the binary is not compiled with this feature.");
+                bail!(
+                    "Cannot enable wasi-config when the binary is not compiled with this feature."
+                );
             }
-            #[cfg(all(feature = "wasi-runtime-config", feature = "component-model"))]
+            #[cfg(all(feature = "wasi-config", feature = "component-model"))]
             {
                 match linker {
                     CliLinker::Core(_) => {
-                        bail!("Cannot enable wasi-runtime-config for core wasm modules");
+                        bail!("Cannot enable wasi-config for core wasm modules");
                     }
                     CliLinker::Component(linker) => {
-                        let vars = WasiRuntimeConfigVariables::from_iter(
+                        let vars = WasiConfigVariables::from_iter(
                             self.run
                                 .common
                                 .wasi
-                                .runtime_config_var
+                                .config_var
                                 .iter()
                                 .map(|v| (v.key.clone(), v.value.clone())),
                         );
 
-                        wasmtime_wasi_runtime_config::add_to_linker(linker, |h| {
-                            WasiRuntimeConfig::new(
-                                Arc::get_mut(h.wasi_runtime_config.as_mut().unwrap()).unwrap(),
-                            )
+                        wasmtime_wasi_config::add_to_linker(linker, |h| {
+                            WasiConfig::new(Arc::get_mut(h.wasi_config.as_mut().unwrap()).unwrap())
                         })?;
-                        store.data_mut().wasi_runtime_config = Some(Arc::new(vars));
+                        store.data_mut().wasi_config = Some(Arc::new(vars));
                     }
                 }
             }
@@ -911,8 +911,8 @@ struct Host {
     #[cfg(feature = "profiling")]
     guest_profiler: Option<Arc<wasmtime::GuestProfiler>>,
 
-    #[cfg(feature = "wasi-runtime-config")]
-    wasi_runtime_config: Option<Arc<WasiRuntimeConfigVariables>>,
+    #[cfg(feature = "wasi-config")]
+    wasi_config: Option<Arc<WasiConfigVariables>>,
     #[cfg(feature = "wasi-keyvalue")]
     wasi_keyvalue: Option<Arc<WasiKeyValueCtx>>,
 }
diff --git a/src/commands/serve.rs b/src/commands/serve.rs
index 227e49dfc..f3b4643f2 100644
--- a/src/commands/serve.rs
+++ b/src/commands/serve.rs
@@ -17,12 +17,12 @@ use wasmtime_wasi_http::bindings::ProxyPre;
 use wasmtime_wasi_http::io::TokioIo;
 use wasmtime_wasi_http::{body::HyperOutgoingBody, WasiHttpCtx, WasiHttpView};
 
+#[cfg(feature = "wasi-config")]
+use wasmtime_wasi_config::{WasiConfig, WasiConfigVariables};
 #[cfg(feature = "wasi-keyvalue")]
 use wasmtime_wasi_keyvalue::{WasiKeyValue, WasiKeyValueCtx, WasiKeyValueCtxBuilder};
 #[cfg(feature = "wasi-nn")]
 use wasmtime_wasi_nn::wit::WasiNnCtx;
-#[cfg(feature = "wasi-runtime-config")]
-use wasmtime_wasi_runtime_config::{WasiRuntimeConfig, WasiRuntimeConfigVariables};
 
 struct Host {
     table: wasmtime::component::ResourceTable,
@@ -34,8 +34,8 @@ struct Host {
     #[cfg(feature = "wasi-nn")]
     nn: Option<WasiNnCtx>,
 
-    #[cfg(feature = "wasi-runtime-config")]
-    wasi_runtime_config: Option<WasiRuntimeConfigVariables>,
+    #[cfg(feature = "wasi-config")]
+    wasi_config: Option<WasiConfigVariables>,
 
     #[cfg(feature = "wasi-keyvalue")]
     wasi_keyvalue: Option<WasiKeyValueCtx>,
@@ -157,8 +157,8 @@ impl ServeCommand {
 
             #[cfg(feature = "wasi-nn")]
             nn: None,
-            #[cfg(feature = "wasi-runtime-config")]
-            wasi_runtime_config: None,
+            #[cfg(feature = "wasi-config")]
+            wasi_config: None,
             #[cfg(feature = "wasi-keyvalue")]
             wasi_keyvalue: None,
         };
@@ -179,18 +179,18 @@ impl ServeCommand {
             }
         }
 
-        if self.run.common.wasi.runtime_config == Some(true) {
-            #[cfg(feature = "wasi-runtime-config")]
+        if self.run.common.wasi.config == Some(true) {
+            #[cfg(feature = "wasi-config")]
             {
-                let vars = WasiRuntimeConfigVariables::from_iter(
+                let vars = WasiConfigVariables::from_iter(
                     self.run
                         .common
                         .wasi
-                        .runtime_config_var
+                        .config_var
                         .iter()
                         .map(|v| (v.key.clone(), v.value.clone())),
                 );
-                host.wasi_runtime_config.replace(vars);
+                host.wasi_config.replace(vars);
             }
         }
 
@@ -275,15 +275,15 @@ impl ServeCommand {
             }
         }
 
-        if self.run.common.wasi.runtime_config == Some(true) {
-            #[cfg(not(feature = "wasi-runtime-config"))]
+        if self.run.common.wasi.config == Some(true) {
+            #[cfg(not(feature = "wasi-config"))]
             {
-                bail!("support for wasi-runtime-config was disabled at compile time");
+                bail!("support for wasi-config was disabled at compile time");
             }
-            #[cfg(feature = "wasi-runtime-config")]
+            #[cfg(feature = "wasi-config")]
             {
-                wasmtime_wasi_runtime_config::add_to_linker(linker, |h| {
-                    WasiRuntimeConfig::from(h.wasi_runtime_config.as_ref().unwrap())
+                wasmtime_wasi_config::add_to_linker(linker, |h| {
+                    WasiConfig::from(h.wasi_config.as_ref().unwrap())
                 })?;
             }
         }
diff --git a/supply-chain/config.toml b/supply-chain/config.toml
index b122a00ee..d327cfb24 100644
--- a/supply-chain/config.toml
+++ b/supply-chain/config.toml
@@ -160,9 +160,6 @@ audit-as-crates-io = true
 [policy.wasmtime-wasi-nn]
 audit-as-crates-io = true
 
-[policy.wasmtime-wasi-runtime-config]
-audit-as-crates-io = true
-
 [policy.wasmtime-wasi-threads]
 audit-as-crates-io = true
 
diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock
index 8204d0246..1a7fafb5d 100644
--- a/supply-chain/imports.lock
+++ b/supply-chain/imports.lock
@@ -2341,18 +2341,6 @@ when = "2024-09-24"
 user-id = 73222
 user-login = "wasmtime-publish"
 
-[[publisher.wasmtime-wasi-runtime-config]]
-version = "24.0.0"
-when = "2024-08-20"
-user-id = 73222
-user-login = "wasmtime-publish"
-
-[[publisher.wasmtime-wasi-runtime-config]]
-version = "25.0.1"
-when = "2024-09-24"
-user-id = 73222
-user-login = "wasmtime-publish"
-
 [[publisher.wasmtime-wasi-threads]]
 version = "23.0.1"
 when = "2024-07-22"


Test patch:
diff --git a/crates/test-programs/artifacts/build.rs b/crates/test-programs/artifacts/build.rs
index 018b5cce9..f5966a67e 100644
--- a/crates/test-programs/artifacts/build.rs
+++ b/crates/test-programs/artifacts/build.rs
@@ -76,7 +76,7 @@ fn build_and_generate_tests() {
             s if s.starts_with("nn_") => "nn",
             s if s.starts_with("piped_") => "piped",
             s if s.starts_with("dwarf_") => "dwarf",
-            s if s.starts_with("runtime_config_") => "runtime_config",
+            s if s.starts_with("config_") => "config",
             s if s.starts_with("keyvalue_") => "keyvalue",
             // If you're reading this because you hit this panic, either add it
             // to a test suite above or add a new "suite". The purpose of the
diff --git a/crates/test-programs/src/bin/cli_serve_runtime_config.rs b/crates/test-programs/src/bin/cli_serve_config.rs
similarity index 90%
rename from crates/test-programs/src/bin/cli_serve_runtime_config.rs
rename to crates/test-programs/src/bin/cli_serve_config.rs
index d56227dc4..a302660de 100644
--- a/crates/test-programs/src/bin/cli_serve_runtime_config.rs
+++ b/crates/test-programs/src/bin/cli_serve_config.rs
@@ -1,6 +1,6 @@
 use test_programs::proxy;
 use test_programs::wasi::{
-    config::runtime,
+    config::store,
     http::types::{Fields, IncomingRequest, OutgoingBody, OutgoingResponse, ResponseOutparam},
 };
 
@@ -17,7 +17,7 @@ impl proxy::exports::wasi::http::incoming_handler::Guest for T {
         ResponseOutparam::set(outparam, Ok(resp));
 
         let out = body.write().expect("outgoing stream");
-        let config = runtime::get("hello").unwrap().unwrap();
+        let config = store::get("hello").unwrap().unwrap();
         out.blocking_write_and_flush(config.as_bytes())
             .expect("writing response");
 
diff --git a/crates/test-programs/src/bin/config_get.rs b/crates/test-programs/src/bin/config_get.rs
new file mode 100644
index 000000000..302b9b136
--- /dev/null
+++ b/crates/test-programs/src/bin/config_get.rs
@@ -0,0 +1,8 @@
+use test_programs::wasi::config::store;
+
+fn main() {
+    let v = store::get("hello").unwrap().unwrap();
+    assert_eq!(v, "world");
+    let config = store::get_all().unwrap();
+    assert_eq!(config, [("hello".to_string(), "world".to_string())])
+}
diff --git a/crates/test-programs/src/bin/runtime_config_get.rs b/crates/test-programs/src/bin/runtime_config_get.rs
deleted file mode 100644
index e3013cdb2..000000000
--- a/crates/test-programs/src/bin/runtime_config_get.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-use test_programs::wasi::config::runtime;
-
-fn main() {
-    let v = runtime::get("hello").unwrap().unwrap();
-    assert_eq!(v, "world");
-    let config = runtime::get_all().unwrap();
-    assert_eq!(config, [("hello".to_string(), "world".to_string())])
-}
diff --git a/crates/test-programs/src/lib.rs b/crates/test-programs/src/lib.rs
index 57e81dda1..bdd9f1cba 100644
--- a/crates/test-programs/src/lib.rs
+++ b/crates/test-programs/src/lib.rs
@@ -16,7 +16,7 @@ wit_bindgen::generate!({
     ",
     path: [
         "../wasi-http/wit",
-        "../wasi-runtime-config/wit",
+        "../wasi-config/wit",
         "../wasi-keyvalue/wit",
     ],
     world: "wasmtime:test/test",
diff --git a/crates/wasi-runtime-config/tests/main.rs b/crates/wasi-config/tests/main.rs
similarity index 68%
rename from crates/wasi-runtime-config/tests/main.rs
rename to crates/wasi-config/tests/main.rs
index 5c07bc9e3..544bc03cd 100644
--- a/crates/wasi-runtime-config/tests/main.rs
+++ b/crates/wasi-config/tests/main.rs
@@ -1,16 +1,16 @@
 use anyhow::{anyhow, Result};
-use test_programs_artifacts::{foreach_runtime_config, RUNTIME_CONFIG_GET_COMPONENT};
+use test_programs_artifacts::{foreach_config, CONFIG_GET_COMPONENT};
 use wasmtime::{
     component::{Component, Linker, ResourceTable},
     Store,
 };
 use wasmtime_wasi::{add_to_linker_async, bindings::Command, WasiCtx, WasiCtxBuilder, WasiView};
-use wasmtime_wasi_runtime_config::{WasiRuntimeConfig, WasiRuntimeConfigVariables};
+use wasmtime_wasi_config::{WasiConfig, WasiConfigVariables};
 
 struct Ctx {
     table: ResourceTable,
     wasi_ctx: WasiCtx,
-    wasi_runtime_config_vars: WasiRuntimeConfigVariables,
+    wasi_config_vars: WasiConfigVariables,
 }
 
 impl WasiView for Ctx {
@@ -32,8 +32,8 @@ async fn run_wasi(path: &str, ctx: Ctx) -> Result<()> {
 
     let mut linker = Linker::new(&engine);
     add_to_linker_async(&mut linker)?;
-    wasmtime_wasi_runtime_config::add_to_linker(&mut linker, |h: &mut Ctx| {
-        WasiRuntimeConfig::from(&h.wasi_runtime_config_vars)
+    wasmtime_wasi_config::add_to_linker(&mut linker, |h: &mut Ctx| {
+        WasiConfig::from(&h.wasi_config_vars)
     })?;
 
     let command = Command::instantiate_async(&mut store, &component, &linker).await?;
@@ -51,18 +51,16 @@ macro_rules! assert_test_exists {
     };
 }
 
-foreach_runtime_config!(assert_test_exists);
+foreach_config!(assert_test_exists);
 
 #[tokio::test(flavor = "multi_thread")]
-async fn runtime_config_get() -> Result<()> {
+async fn config_get() -> Result<()> {
     run_wasi(
-        RUNTIME_CONFIG_GET_COMPONENT,
+        CONFIG_GET_COMPONENT,
         Ctx {
             table: ResourceTable::new(),
             wasi_ctx: WasiCtxBuilder::new().build(),
-            wasi_runtime_config_vars: WasiRuntimeConfigVariables::from_iter(vec![(
-                "hello", "world",
-            )]),
+            wasi_config_vars: WasiConfigVariables::from_iter(vec![("hello", "world")]),
         },
     )
     .await
diff --git a/tests/all/cli_tests.rs b/tests/all/cli_tests.rs
index 675c91b94..b7ea967c7 100644
--- a/tests/all/cli_tests.rs
+++ b/tests/all/cli_tests.rs
@@ -1923,11 +1923,11 @@ stderr [1] :: after empty
     }
 
     #[tokio::test]
-    async fn cli_serve_runtime_config() -> Result<()> {
-        let server = WasmtimeServe::new(CLI_SERVE_RUNTIME_CONFIG_COMPONENT, |cmd| {
+    async fn cli_serve_config() -> Result<()> {
+        let server = WasmtimeServe::new(CLI_SERVE_CONFIG_COMPONENT, |cmd| {
             cmd.arg("-Scli");
-            cmd.arg("-Sruntime-config");
-            cmd.arg("-Sruntime-config-var=hello=world");
+            cmd.arg("-Sconfig");
+            cmd.arg("-Sconfig-var=hello=world");
         })?;
 
         let resp = server
@@ -1945,12 +1945,12 @@ stderr [1] :: after empty
     }
 
     #[test]
-    fn cli_runtime_config() -> Result<()> {
+    fn cli_config() -> Result<()> {
         run_wasmtime(&[
             "run",
-            "-Sruntime-config",
-            "-Sruntime-config-var=hello=world",
-            RUNTIME_CONFIG_GET_COMPONENT,
+            "-Sconfig",
+            "-Sconfig-var=hello=world",
+            CONFIG_GET_COMPONENT,
         ])?;
         Ok(())
     }
diff --git a/tests/all/module.rs b/tests/all/module.rs
index 17c1680fa..61852409d 100644
--- a/tests/all/module.rs
+++ b/tests/all/module.rs
@@ -304,6 +304,7 @@ fn cross_engine_module_exports() -> Result<()> {
 /// Smoke test for registering and unregistering modules (and their rec group
 /// entries) concurrently.
 #[wasmtime_test(wasm_features(gc, function_references))]
+#[cfg_attr(miri, ignore)]
 fn concurrent_type_registry_modifications(config: &mut Config) -> Result<()> {
     let _ = env_logger::try_init();
 
@@ -446,6 +447,7 @@ fn concurrent_type_registry_modifications(config: &mut Config) -> Result<()> {
 }
 
 #[wasmtime_test(wasm_features(function_references))]
+#[cfg_attr(miri, ignore)]
 fn concurrent_type_modifications_and_checks(config: &mut Config) -> Result<()> {
     const THREADS_CHECKING: usize = 4;
 
diff --git a/tests/all/traps.rs b/tests/all/traps.rs
index bfd39e0a5..f5368a48f 100644
--- a/tests/all/traps.rs
+++ b/tests/all/traps.rs
@@ -5,6 +5,7 @@ use std::panic::{self, AssertUnwindSafe};
 use std::process::Command;
 use std::sync::{Arc, Mutex};
 use wasmtime::*;
+use wasmtime_test_macros::wasmtime_test;
 
 #[test]
 fn test_trap_return() -> Result<()> {
@@ -1679,3 +1680,113 @@ fn async_stack_size_ignored_if_disabled() -> Result<()> {
 
     Ok(())
 }
+
+#[wasmtime_test(wasm_features(tail_call))]
+fn tail_call_to_imported_function(config: &mut Config) -> Result<()> {
+    let engine = Engine::new(config)?;
+
+    let module = Module::new(
+        &engine,
+        r#"
+            (module
+              (import "" "" (func (result i32)))
+
+              (func (export "run") (result i32)
+                return_call 0
+              )
+            )
+        "#,
+    )?;
+
+    let mut store = Store::new(&engine, ());
+    let host_func = Func::wrap(&mut store, || -> Result<i32> { bail!("whoopsie") });
+    let instance = Instance::new(&mut store, &module, &[host_func.into()])?;
+
+    let run = instance.get_typed_func::<(), i32>(&mut store, "run")?;
+    let err = run.call(&mut store, ()).unwrap_err();
+    assert!(err.to_string().contains("whoopsie"));
+
+    Ok(())
+}
+
+#[wasmtime_test(wasm_features(tail_call))]
+fn tail_call_to_imported_function_in_start_function(config: &mut Config) -> Result<()> {
+    let engine = Engine::new(config)?;
+
+    let module = Module::new(
+        &engine,
+        r#"
+            (module
+              (import "" "" (func))
+
+              (func $f
+                return_call 0
+              )
+
+              (start $f)
+            )
+        "#,
+    )?;
+
+    let mut store = Store::new(&engine, ());
+    let host_func = Func::wrap(&mut store, || -> Result<()> { bail!("whoopsie") });
+    let err = Instance::new(&mut store, &module, &[host_func.into()]).unwrap_err();
+    assert!(err.to_string().contains("whoopsie"));
+
+    Ok(())
+}
+
+#[wasmtime_test(wasm_features(tail_call, function_references))]
+fn return_call_ref_to_imported_function(config: &mut Config) -> Result<()> {
+    let engine = Engine::new(config)?;
+
+    let module = Module::new(
+        &engine,
+        r#"
+            (module
+              (type (func (result i32)))
+              (func (export "run") (param (ref 0)) (result i32)
+                (return_call_ref 0 (local.get 0))
+              )
+            )
+        "#,
+    )?;
+
+    let mut store = Store::new(&engine, ());
+    let host_func = Func::wrap(&mut store, || -> Result<i32> { bail!("whoopsie") });
+    let instance = Instance::new(&mut store, &module, &[])?;
+
+    let run = instance.get_typed_func::<Func, i32>(&mut store, "run")?;
+    let err = run.call(&mut store, host_func).unwrap_err();
+    assert!(err.to_string().contains("whoopsie"));
+
+    Ok(())
+}
+
+#[wasmtime_test(wasm_features(tail_call, function_references))]
+fn return_call_indirect_to_imported_function(config: &mut Config) -> Result<()> {
+    let engine = Engine::new(config)?;
+
+    let module = Module::new(
+        &engine,
+        r#"
+            (module
+              (import "" "" (func (result i32)))
+              (table 1 funcref (ref.func 0))
+              (func (export "run") (result i32)
+                (return_call_indirect (result i32) (i32.const 0))
+              )
+            )
+        "#,
+    )?;
+
+    let mut store = Store::new(&engine, ());
+    let host_func = Func::wrap(&mut store, || -> Result<i32> { bail!("whoopsie") });
+    let instance = Instance::new(&mut store, &module, &[host_func.into()])?;
+
+    let run = instance.get_typed_func::<(), i32>(&mut store, "run")?;
+    let err = run.call(&mut store, ()).unwrap_err();
+    assert!(err.to_string().contains("whoopsie"));
+
+    Ok(())
+}