Repository: bytecodealliance/wasmtime
Pull request #9365 (2024-10-03 18:57:45)

Release Wasmtime 23.0.3
This is an [automated pull request][process] from CI to create a patch release for Wasmtime 23.0.3, requested by @alexcrichton.

It's recommended that maintainers double-check that [RELEASES.md] is up-to-date and that there are no known issues before merging this PR. When this PR is merged a release tag will automatically be created, crates will be published, and CI artifacts will be produced.

[RELEASES.md]: https://github.com/bytecodealliance/wasmtime/blob/release-23.0.3/RELEASES.md
[process]: https://docs.wasmtime.dev/contributing-release-process.html


alexcrichton: This is in preparation for the upcoming [security release](https://groups.google.com/a/bytecodealliance.org/g/sec-announce/c/7SjEU_qSE4U)
github-actions[bot]: #### Subscribe to Label Action

cc @cfallin, @fitzgen, @saulecabrera

<details>
This issue or pull request has been labeled: "cranelift", "cranelift:meta", "cranelift:module", "cranelift:wasm", "isle", "wasmtime:c-api", "winch"

Thus the following users have been cc'd because of the following labels:

* cfallin: isle
* fitzgen: isle
* saulecabrera: winch

To subscribe or unsubscribe from this label, edit the <code>.github/subscribe-to-label.json</code> configuration file.

[Learn more.](https://github.com/bytecodealliance/subscribe-to-label-action)
</details>

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index c1927acaf..2fe080de6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -216,7 +216,7 @@ checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
 
 [[package]]
 name = "byte-array-literals"
-version = "23.0.2"
+version = "23.0.3"
 
 [[package]]
 name = "byteorder"
@@ -556,7 +556,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "cranelift-codegen",
  "cranelift-frontend",
@@ -569,14 +569,14 @@ dependencies = [
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-bitset"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "serde",
  "serde_derive",
@@ -584,7 +584,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "anyhow",
  "bumpalo",
@@ -615,25 +615,25 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.110.2"
+version = "0.110.3"
 
 [[package]]
 name = "cranelift-control"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "arbitrary",
 ]
 
 [[package]]
 name = "cranelift-entity"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "cranelift-bitset",
  "serde",
@@ -671,7 +671,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "cranelift-codegen",
  "hashbrown 0.14.3",
@@ -695,7 +695,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-interpreter"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "cranelift-codegen",
  "cranelift-entity",
@@ -709,7 +709,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "codespan-reporting",
  "log",
@@ -718,7 +718,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-jit"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "anyhow",
  "cranelift",
@@ -739,7 +739,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -751,7 +751,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -760,7 +760,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -775,7 +775,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-reader"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -785,7 +785,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-serde"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "clap",
  "cranelift-codegen",
@@ -829,7 +829,7 @@ dependencies = [
 
 [[package]]
 name = "cranelift-wasm"
-version = "0.110.2"
+version = "0.110.3"
 dependencies = [
  "cranelift-codegen",
  "cranelift-entity",
@@ -1044,7 +1044,7 @@ checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
 
 [[package]]
 name = "embedding"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "dlmalloc",
@@ -1846,7 +1846,7 @@ dependencies = [
 
 [[package]]
 name = "min-platform-host"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "libloading",
@@ -3079,7 +3079,7 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
 
 [[package]]
 name = "verify-component-adapter"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "wasmparser",
@@ -3129,7 +3129,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasi-common"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "bitflags 2.4.1",
@@ -3169,7 +3169,7 @@ dependencies = [
 
 [[package]]
 name = "wasi-preview1-component-adapter"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "bitflags 2.4.1",
  "byte-array-literals",
@@ -3363,7 +3363,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "addr2line",
  "anyhow",
@@ -3423,14 +3423,14 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-asm-macros"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "cfg-if",
 ]
 
 [[package]]
 name = "wasmtime-bench-api"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "cap-std",
@@ -3446,14 +3446,14 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-c-api"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "wasmtime-c-api-impl",
 ]
 
 [[package]]
 name = "wasmtime-c-api-impl"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "cap-std",
@@ -3471,7 +3471,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-c-api-macros"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3479,7 +3479,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-cache"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "base64",
@@ -3501,7 +3501,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-cli"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -3567,7 +3567,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-cli-flags"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "clap",
@@ -3580,7 +3580,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-component-macro"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "component-macro-test-helpers",
@@ -3600,11 +3600,11 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-component-util"
-version = "23.0.2"
+version = "23.0.3"
 
 [[package]]
 name = "wasmtime-cranelift"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "cfg-if",
@@ -3626,7 +3626,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-environ"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "clap",
@@ -3668,7 +3668,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-explorer"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "capstone",
@@ -3683,7 +3683,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-fiber"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "backtrace",
@@ -3753,7 +3753,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-jit-debug"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "object 0.36.0",
  "once_cell",
@@ -3763,7 +3763,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-jit-icache-coherence"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "cfg-if",
@@ -3773,7 +3773,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-slab"
-version = "23.0.2"
+version = "23.0.3"
 
 [[package]]
 name = "wasmtime-test-macros"
@@ -3787,7 +3787,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-types"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "cranelift-entity",
@@ -3799,7 +3799,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-versioned-export-macros"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3808,7 +3808,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-wasi"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -3841,7 +3841,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-wasi-http"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -3867,7 +3867,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-wasi-nn"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "cap-std",
@@ -3887,7 +3887,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-wasi-threads"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "log",
@@ -3898,7 +3898,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-wast"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "log",
@@ -3908,7 +3908,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-winch"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -3923,7 +3923,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-wit-bindgen"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "heck 0.4.0",
@@ -3933,7 +3933,7 @@ dependencies = [
 
 [[package]]
 name = "wasmtime-wmemcheck"
-version = "23.0.2"
+version = "23.0.3"
 
 [[package]]
 name = "wast"
@@ -4000,7 +4000,7 @@ dependencies = [
 
 [[package]]
 name = "wiggle"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -4017,7 +4017,7 @@ dependencies = [
 
 [[package]]
 name = "wiggle-generate"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "anyhow",
  "heck 0.4.0",
@@ -4030,7 +4030,7 @@ dependencies = [
 
 [[package]]
 name = "wiggle-macro"
-version = "23.0.2"
+version = "23.0.3"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4085,7 +4085,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "winch-codegen"
-version = "0.21.2"
+version = "0.21.3"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
diff --git a/Cargo.toml b/Cargo.toml
index de5a9a450..0ab7bb029 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -153,7 +153,7 @@ exclude = [
 ]
 
 [workspace.package]
-version = "23.0.2"
+version = "23.0.3"
 authors = ["The Wasmtime Project Developers"]
 edition = "2021"
 # Wasmtime's current policy is that this number can be no larger than the
@@ -176,57 +176,57 @@ all = 'allow'
 
 [workspace.dependencies]
 arbitrary = { version = "1.3.1" }
-wasmtime-wmemcheck = { path = "crates/wmemcheck", version = "=23.0.2" }
-wasmtime = { path = "crates/wasmtime", version = "23.0.2", default-features = false }
-wasmtime-c-api-macros = { path = "crates/c-api-macros", version = "=23.0.2" }
-wasmtime-cache = { path = "crates/cache", version = "=23.0.2" }
-wasmtime-cli-flags = { path = "crates/cli-flags", version = "=23.0.2" }
-wasmtime-cranelift = { path = "crates/cranelift", version = "=23.0.2" }
-wasmtime-winch = { path = "crates/winch", version = "=23.0.2" }
-wasmtime-environ = { path = "crates/environ", version = "=23.0.2" }
-wasmtime-explorer = { path = "crates/explorer", version = "=23.0.2" }
-wasmtime-fiber = { path = "crates/fiber", version = "=23.0.2" }
-wasmtime-types = { path = "crates/types", version = "23.0.2" }
-wasmtime-jit-debug = { path = "crates/jit-debug", version = "=23.0.2" }
-wasmtime-wast = { path = "crates/wast", version = "=23.0.2" }
-wasmtime-wasi = { path = "crates/wasi", version = "23.0.2", default-features = false }
-wasmtime-wasi-http = { path = "crates/wasi-http", version = "=23.0.2", default-features = false }
-wasmtime-wasi-nn = { path = "crates/wasi-nn", version = "23.0.2" }
-wasmtime-wasi-threads = { path = "crates/wasi-threads", version = "23.0.2" }
-wasmtime-component-util = { path = "crates/component-util", version = "=23.0.2" }
-wasmtime-component-macro = { path = "crates/component-macro", version = "=23.0.2" }
-wasmtime-asm-macros = { path = "crates/asm-macros", version = "=23.0.2" }
-wasmtime-versioned-export-macros = { path = "crates/versioned-export-macros", version = "=23.0.2" }
-wasmtime-slab = { path = "crates/slab", version = "=23.0.2" }
+wasmtime-wmemcheck = { path = "crates/wmemcheck", version = "=23.0.3" }
+wasmtime = { path = "crates/wasmtime", version = "23.0.3", default-features = false }
+wasmtime-c-api-macros = { path = "crates/c-api-macros", version = "=23.0.3" }
+wasmtime-cache = { path = "crates/cache", version = "=23.0.3" }
+wasmtime-cli-flags = { path = "crates/cli-flags", version = "=23.0.3" }
+wasmtime-cranelift = { path = "crates/cranelift", version = "=23.0.3" }
+wasmtime-winch = { path = "crates/winch", version = "=23.0.3" }
+wasmtime-environ = { path = "crates/environ", version = "=23.0.3" }
+wasmtime-explorer = { path = "crates/explorer", version = "=23.0.3" }
+wasmtime-fiber = { path = "crates/fiber", version = "=23.0.3" }
+wasmtime-types = { path = "crates/types", version = "23.0.3" }
+wasmtime-jit-debug = { path = "crates/jit-debug", version = "=23.0.3" }
+wasmtime-wast = { path = "crates/wast", version = "=23.0.3" }
+wasmtime-wasi = { path = "crates/wasi", version = "23.0.3", default-features = false }
+wasmtime-wasi-http = { path = "crates/wasi-http", version = "=23.0.3", default-features = false }
+wasmtime-wasi-nn = { path = "crates/wasi-nn", version = "23.0.3" }
+wasmtime-wasi-threads = { path = "crates/wasi-threads", version = "23.0.3" }
+wasmtime-component-util = { path = "crates/component-util", version = "=23.0.3" }
+wasmtime-component-macro = { path = "crates/component-macro", version = "=23.0.3" }
+wasmtime-asm-macros = { path = "crates/asm-macros", version = "=23.0.3" }
+wasmtime-versioned-export-macros = { path = "crates/versioned-export-macros", version = "=23.0.3" }
+wasmtime-slab = { path = "crates/slab", version = "=23.0.3" }
 component-test-util = { path = "crates/misc/component-test-util" }
 component-fuzz-util = { path = "crates/misc/component-fuzz-util" }
-wiggle = { path = "crates/wiggle", version = "=23.0.2", default-features = false }
-wiggle-macro = { path = "crates/wiggle/macro", version = "=23.0.2" }
-wiggle-generate = { path = "crates/wiggle/generate", version = "=23.0.2" }
-wasi-common = { path = "crates/wasi-common", version = "=23.0.2", default-features = false }
+wiggle = { path = "crates/wiggle", version = "=23.0.3", default-features = false }
+wiggle-macro = { path = "crates/wiggle/macro", version = "=23.0.3" }
+wiggle-generate = { path = "crates/wiggle/generate", version = "=23.0.3" }
+wasi-common = { path = "crates/wasi-common", version = "=23.0.3", default-features = false }
 wasmtime-fuzzing = { path = "crates/fuzzing" }
-wasmtime-jit-icache-coherence = { path = "crates/jit-icache-coherence", version = "=23.0.2" }
-wasmtime-wit-bindgen = { path = "crates/wit-bindgen", version = "=23.0.2" }
+wasmtime-jit-icache-coherence = { path = "crates/jit-icache-coherence", version = "=23.0.3" }
+wasmtime-wit-bindgen = { path = "crates/wit-bindgen", version = "=23.0.3" }
 test-programs-artifacts = { path = 'crates/test-programs/artifacts' }
 
-cranelift-wasm = { path = "cranelift/wasm", version = "0.110.2" }
-cranelift-codegen = { path = "cranelift/codegen", version = "0.110.2", default-features = false, features = ["std", "unwind", "trace-log"] }
-cranelift-frontend = { path = "cranelift/frontend", version = "0.110.2" }
-cranelift-entity = { path = "cranelift/entity", version = "0.110.2" }
-cranelift-native = { path = "cranelift/native", version = "0.110.2" }
-cranelift-module = { path = "cranelift/module", version = "0.110.2" }
-cranelift-interpreter = { path = "cranelift/interpreter", version = "0.110.2" }
-cranelift-reader = { path = "cranelift/reader", version = "0.110.2" }
+cranelift-wasm = { path = "cranelift/wasm", version = "0.110.3" }
+cranelift-codegen = { path = "cranelift/codegen", version = "0.110.3", default-features = false, features = ["std", "unwind", "trace-log"] }
+cranelift-frontend = { path = "cranelift/frontend", version = "0.110.3" }
+cranelift-entity = { path = "cranelift/entity", version = "0.110.3" }
+cranelift-native = { path = "cranelift/native", version = "0.110.3" }
+cranelift-module = { path = "cranelift/module", version = "0.110.3" }
+cranelift-interpreter = { path = "cranelift/interpreter", version = "0.110.3" }
+cranelift-reader = { path = "cranelift/reader", version = "0.110.3" }
 cranelift-filetests = { path = "cranelift/filetests" }
-cranelift-object = { path = "cranelift/object", version = "0.110.2" }
-cranelift-jit = { path = "cranelift/jit", version = "0.110.2" }
+cranelift-object = { path = "cranelift/object", version = "0.110.3" }
+cranelift-jit = { path = "cranelift/jit", version = "0.110.3" }
 cranelift-fuzzgen = { path = "cranelift/fuzzgen" }
-cranelift-bforest = { path = "cranelift/bforest", version = "0.110.2" }
-cranelift-bitset = { path = "cranelift/bitset", version = "0.110.2" }
-cranelift-control = { path = "cranelift/control", version = "0.110.2" }
-cranelift = { path = "cranelift/umbrella", version = "0.110.2" }
+cranelift-bforest = { path = "cranelift/bforest", version = "0.110.3" }
+cranelift-bitset = { path = "cranelift/bitset", version = "0.110.3" }
+cranelift-control = { path = "cranelift/control", version = "0.110.3" }
+cranelift = { path = "cranelift/umbrella", version = "0.110.3" }
 
-winch-codegen = { path = "winch/codegen", version = "=0.21.2" }
+winch-codegen = { path = "winch/codegen", version = "=0.21.3" }
 
 wasi-preview1-component-adapter = { path = "crates/wasi-preview1-component-adapter" }
 byte-array-literals = { path = "crates/wasi-preview1-component-adapter/byte-array-literals" }
diff --git a/RELEASES.md b/RELEASES.md
index db3a245a2..23f1316ec 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,19 @@
+## 23.0.3
+
+Released 2024-10-09.
+
+### Fixed
+
+* Fix a runtime crash when combining tail-calls with host imports that capture a
+  stack trace or trap.
+  [GHSA-q8hx-mm92-4wvg](https://github.com/bytecodealliance/wasmtime/security/advisories/GHSA-q8hx-mm92-4wvg)
+
+* Fix a race condition could lead to WebAssembly control-flow integrity and type
+  safety violations.
+  [GHSA-7qmx-3fpx-r45m](https://github.com/bytecodealliance/wasmtime/security/advisories/GHSA-7qmx-3fpx-r45m)
+
+--------------------------------------------------------------------------------
+
 ## 23.0.2
 
 Released 2024-08-12.
diff --git a/cranelift/bforest/Cargo.toml b/cranelift/bforest/Cargo.toml
index 31a4432f9..f6f9054e1 100644
--- a/cranelift/bforest/Cargo.toml
+++ b/cranelift/bforest/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-bforest"
-version = "0.110.2"
+version = "0.110.3"
 description = "A forest of B+-trees"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://docs.rs/cranelift-bforest"
diff --git a/cranelift/bitset/Cargo.toml b/cranelift/bitset/Cargo.toml
index b6ec8b96e..d67f885df 100644
--- a/cranelift/bitset/Cargo.toml
+++ b/cranelift/bitset/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-bitset"
-version = "0.110.2"
+version = "0.110.3"
 description = "Various bitset stuff for use inside Cranelift"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://docs.rs/cranelift-bitset"
diff --git a/cranelift/codegen/Cargo.toml b/cranelift/codegen/Cargo.toml
index ced0f833f..38a20c6bf 100644
--- a/cranelift/codegen/Cargo.toml
+++ b/cranelift/codegen/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-codegen"
-version = "0.110.2"
+version = "0.110.3"
 description = "Low-level code generator library"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://docs.rs/cranelift-codegen"
@@ -19,7 +19,7 @@ workspace = true
 anyhow = { workspace = true, optional = true, features = ['std'] }
 bumpalo = "3"
 capstone = { workspace = true, optional = true }
-cranelift-codegen-shared = { path = "./shared", version = "0.110.2" }
+cranelift-codegen-shared = { path = "./shared", version = "0.110.3" }
 cranelift-entity = { workspace = true }
 cranelift-bforest = { workspace = true }
 cranelift-bitset = { workspace = true }
@@ -47,8 +47,8 @@ similar = "2.1.0"
 env_logger = { workspace = true }
 
 [build-dependencies]
-cranelift-codegen-meta = { path = "meta", version = "0.110.2" }
-cranelift-isle = { path = "../isle/isle", version = "=0.110.2" }
+cranelift-codegen-meta = { path = "meta", version = "0.110.3" }
+cranelift-isle = { path = "../isle/isle", version = "=0.110.3" }
 
 [features]
 default = ["std", "unwind", "host-arch", "timing"]
diff --git a/cranelift/codegen/meta/Cargo.toml b/cranelift/codegen/meta/Cargo.toml
index e2ef59bc1..f61f4fd73 100644
--- a/cranelift/codegen/meta/Cargo.toml
+++ b/cranelift/codegen/meta/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "cranelift-codegen-meta"
 authors = ["The Cranelift Project Developers"]
-version = "0.110.2"
+version = "0.110.3"
 description = "Metaprogram for cranelift-codegen code generator library"
 license = "Apache-2.0 WITH LLVM-exception"
 repository = "https://github.com/bytecodealliance/wasmtime"
@@ -15,4 +15,4 @@ workspace = true
 rustdoc-args = [ "--document-private-items" ]
 
 [dependencies]
-cranelift-codegen-shared = { path = "../shared", version = "0.110.2" }
+cranelift-codegen-shared = { path = "../shared", version = "0.110.3" }
diff --git a/cranelift/codegen/shared/Cargo.toml b/cranelift/codegen/shared/Cargo.toml
index 2b690296a..6fb3aa504 100644
--- a/cranelift/codegen/shared/Cargo.toml
+++ b/cranelift/codegen/shared/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-codegen-shared"
-version = "0.110.2"
+version = "0.110.3"
 description = "For code shared between cranelift-codegen-meta and cranelift-codegen"
 license = "Apache-2.0 WITH LLVM-exception"
 repository = "https://github.com/bytecodealliance/wasmtime"
diff --git a/cranelift/control/Cargo.toml b/cranelift/control/Cargo.toml
index 255289263..fb285a24b 100644
--- a/cranelift/control/Cargo.toml
+++ b/cranelift/control/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-control"
-version = "0.110.2"
+version = "0.110.3"
 description = "White-box fuzz testing framework"
 license = "Apache-2.0 WITH LLVM-exception"
 repository = "https://github.com/bytecodealliance/wasmtime"
diff --git a/cranelift/entity/Cargo.toml b/cranelift/entity/Cargo.toml
index 3d3b5c00f..1eca10545 100644
--- a/cranelift/entity/Cargo.toml
+++ b/cranelift/entity/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-entity"
-version = "0.110.2"
+version = "0.110.3"
 description = "Data structures using entity references as mapping keys"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://docs.rs/cranelift-entity"
diff --git a/cranelift/frontend/Cargo.toml b/cranelift/frontend/Cargo.toml
index 20ae3769f..7e4c1c6af 100644
--- a/cranelift/frontend/Cargo.toml
+++ b/cranelift/frontend/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-frontend"
-version = "0.110.2"
+version = "0.110.3"
 description = "Cranelift IR builder helper"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://docs.rs/cranelift-frontend"
diff --git a/cranelift/interpreter/Cargo.toml b/cranelift/interpreter/Cargo.toml
index a741b9545..fc73fa030 100644
--- a/cranelift/interpreter/Cargo.toml
+++ b/cranelift/interpreter/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cranelift-interpreter"
-version = "0.110.2"
+version = "0.110.3"
 authors = ["The Cranelift Project Developers"]
 description = "Interpret Cranelift IR"
 repository = "https://github.com/bytecodealliance/wasmtime"
diff --git a/cranelift/isle/isle/Cargo.toml b/cranelift/isle/isle/Cargo.toml
index 1a0d606e6..b1eb70679 100644
--- a/cranelift/isle/isle/Cargo.toml
+++ b/cranelift/isle/isle/Cargo.toml
@@ -6,7 +6,7 @@ license = "Apache-2.0 WITH LLVM-exception"
 name = "cranelift-isle"
 readme = "../README.md"
 repository = "https://github.com/bytecodealliance/wasmtime/tree/main/cranelift/isle"
-version = "0.110.2"
+version = "0.110.3"
 
 [lints]
 workspace = true
diff --git a/cranelift/jit/Cargo.toml b/cranelift/jit/Cargo.toml
index 5c0203276..883a72fc3 100644
--- a/cranelift/jit/Cargo.toml
+++ b/cranelift/jit/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cranelift-jit"
-version = "0.110.2"
+version = "0.110.3"
 authors = ["The Cranelift Project Developers"]
 description = "A JIT library backed by Cranelift"
 repository = "https://github.com/bytecodealliance/wasmtime"
diff --git a/cranelift/module/Cargo.toml b/cranelift/module/Cargo.toml
index a442fe5e4..3e0244e3a 100644
--- a/cranelift/module/Cargo.toml
+++ b/cranelift/module/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cranelift-module"
-version = "0.110.2"
+version = "0.110.3"
 authors = ["The Cranelift Project Developers"]
 description = "Support for linking functions and data with Cranelift"
 repository = "https://github.com/bytecodealliance/wasmtime"
diff --git a/cranelift/native/Cargo.toml b/cranelift/native/Cargo.toml
index 3ffd1974c..f2dac606a 100644
--- a/cranelift/native/Cargo.toml
+++ b/cranelift/native/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cranelift-native"
-version = "0.110.2"
+version = "0.110.3"
 authors = ["The Cranelift Project Developers"]
 description = "Support for targeting the host with Cranelift"
 documentation = "https://docs.rs/cranelift-native"
diff --git a/cranelift/object/Cargo.toml b/cranelift/object/Cargo.toml
index 2d8a2eecb..030f7cc89 100644
--- a/cranelift/object/Cargo.toml
+++ b/cranelift/object/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cranelift-object"
-version = "0.110.2"
+version = "0.110.3"
 authors = ["The Cranelift Project Developers"]
 description = "Emit Cranelift output to native object files with `object`"
 repository = "https://github.com/bytecodealliance/wasmtime"
diff --git a/cranelift/reader/Cargo.toml b/cranelift/reader/Cargo.toml
index 7606f4266..7a73b0ab3 100644
--- a/cranelift/reader/Cargo.toml
+++ b/cranelift/reader/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-reader"
-version = "0.110.2"
+version = "0.110.3"
 description = "Cranelift textual IR reader"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://docs.rs/cranelift-reader"
diff --git a/cranelift/serde/Cargo.toml b/cranelift/serde/Cargo.toml
index f532a25e6..02b513e29 100644
--- a/cranelift/serde/Cargo.toml
+++ b/cranelift/serde/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cranelift-serde"
-version = "0.110.2"
+version = "0.110.3"
 authors = ["The Cranelift Project Developers"]
 description = "Serializer/Deserializer for Cranelift IR"
 repository = "https://github.com/bytecodealliance/wasmtime"
diff --git a/cranelift/umbrella/Cargo.toml b/cranelift/umbrella/Cargo.toml
index b8d7c4545..b18ab69ea 100644
--- a/cranelift/umbrella/Cargo.toml
+++ b/cranelift/umbrella/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift"
-version = "0.110.2"
+version = "0.110.3"
 description = "Umbrella for commonly-used cranelift crates"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://docs.rs/cranelift"
diff --git a/cranelift/wasm/Cargo.toml b/cranelift/wasm/Cargo.toml
index 91db391ce..d6cc6c5cb 100644
--- a/cranelift/wasm/Cargo.toml
+++ b/cranelift/wasm/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cranelift-wasm"
-version = "0.110.2"
+version = "0.110.3"
 authors = ["The Cranelift Project Developers"]
 description = "Translator from WebAssembly to Cranelift IR"
 documentation = "https://docs.rs/cranelift-wasm"
diff --git a/crates/c-api/include/wasmtime.h b/crates/c-api/include/wasmtime.h
index 3de9d248c..e3db5c206 100644
--- a/crates/c-api/include/wasmtime.h
+++ b/crates/c-api/include/wasmtime.h
@@ -206,7 +206,7 @@
 /**
  * \brief Wasmtime version string.
  */
-#define WASMTIME_VERSION "23.0.2"
+#define WASMTIME_VERSION "23.0.3"
 /**
  * \brief Wasmtime major version number.
  */
@@ -218,7 +218,7 @@
 /**
  * \brief Wasmtime patch version number.
  */
-#define WASMTIME_VERSION_PATCH 2
+#define WASMTIME_VERSION_PATCH 3
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/crates/environ/src/compile/module_environ.rs b/crates/environ/src/compile/module_environ.rs
index 7c90f1596..0bb9505ea 100644
--- a/crates/environ/src/compile/module_environ.rs
+++ b/crates/environ/src/compile/module_environ.rs
@@ -239,7 +239,9 @@ impl<'a, 'data> ModuleEnvironment<'a, 'data> {
             Payload::TypeSection(types) => {
                 self.validator.type_section(&types)?;
 
-                let count = types.count();
+                let count = self.validator.types(0).unwrap().core_type_count();
+                log::trace!("interning {count} Wasm types");
+
                 let capacity = usize::try_from(count).unwrap();
                 self.result.module.types.reserve(capacity);
                 self.types.reserve_wasm_signatures(capacity);
@@ -254,15 +256,16 @@ impl<'a, 'data> ModuleEnvironment<'a, 'data> {
                 // groups, we need copy the duplicates over (shallowly) as well,
                 // so that our types index space doesn't have holes.
                 let mut type_index = 0;
-                for _ in 0..count {
+                while type_index < count {
                     let validator_types = self.validator.types(0).unwrap();
 
                     // Get the rec group for the current type index, which is
                     // always the first type defined in a rec group.
+                    log::trace!("looking up wasmparser type for index {type_index}");
                     let core_type_id = validator_types.core_type_at(type_index).unwrap_sub();
                     log::trace!(
-                        "about to intern rec group for {core_type_id:?} = {:?}",
-                        validator_types[core_type_id]
+                        "  --> {core_type_id:?} = {:?}",
+                        validator_types[core_type_id],
                     );
                     let rec_group_id = validator_types.rec_group_id_of(core_type_id);
                     debug_assert_eq!(
diff --git a/crates/wasmtime/src/runtime/type_registry.rs b/crates/wasmtime/src/runtime/type_registry.rs
index 47c8dc262..88d0a9838 100644
--- a/crates/wasmtime/src/runtime/type_registry.rs
+++ b/crates/wasmtime/src/runtime/type_registry.rs
@@ -15,15 +15,16 @@ use core::{
     hash::{Hash, Hasher},
     ops::Range,
     sync::atomic::{
-        AtomicUsize,
-        Ordering::{AcqRel, Acquire},
+        AtomicBool, AtomicUsize,
+        Ordering::{AcqRel, Acquire, Release},
     },
 };
 use hashbrown::HashSet;
 use wasmtime_environ::{
-    iter_entity_range, packed_option::PackedOption, EngineOrModuleTypeIndex,
-    ModuleInternedTypeIndex, ModuleTypes, PrimaryMap, SecondaryMap, TypeTrace, VMSharedTypeIndex,
-    WasmRecGroup, WasmSubType,
+    iter_entity_range,
+    packed_option::{PackedOption, ReservedValue},
+    EngineOrModuleTypeIndex, ModuleInternedTypeIndex, ModuleTypes, PrimaryMap, SecondaryMap,
+    TypeTrace, VMSharedTypeIndex, WasmRecGroup, WasmSubType,
 };
 use wasmtime_slab::{Id as SlabId, Slab};
 
@@ -173,12 +174,15 @@ impl Drop for TypeCollection {
 
 #[inline]
 fn shared_type_index_to_slab_id(index: VMSharedTypeIndex) -> SlabId {
+    assert!(!index.is_reserved_value());
     SlabId::from_raw(index.bits())
 }
 
 #[inline]
 fn slab_id_to_shared_type_index(id: SlabId) -> VMSharedTypeIndex {
-    VMSharedTypeIndex::new(id.into_raw())
+    let index = VMSharedTypeIndex::new(id.into_raw());
+    assert!(!index.is_reserved_value());
+    index
 }
 
 /// A Wasm type that has been registered in the engine's `TypeRegistry`.
@@ -387,8 +391,28 @@ impl Debug for RecGroupEntry {
 struct RecGroupEntryInner {
     /// The Wasm rec group, canonicalized for hash consing.
     hash_consing_key: WasmRecGroup,
+
+    /// The shared type indices for each type in this rec group.
     shared_type_indices: Box<[VMSharedTypeIndex]>,
+
+    /// The number of times that this entry has been registered in the
+    /// `TypeRegistryInner`.
+    ///
+    /// This is an atomic counter so that cloning a `RegisteredType`, and
+    /// temporarily keeping a type registered, doesn't require locking the full
+    /// registry.
     registrations: AtomicUsize,
+
+    /// Whether this entry has already been unregistered from the
+    /// `TypeRegistryInner`.
+    ///
+    /// This flag exists to detect and avoid double-unregistration bugs that
+    /// could otherwise occur in rare cases. See the comments in
+    /// `TypeRegistryInner::unregister_type` for details.
+    ///
+    /// To maintain consistency with the rest of this entry's state, this flag
+    /// should only be accessed while holding the type registry lock.
+    unregistered: AtomicBool,
 }
 
 impl PartialEq for RecGroupEntry {
@@ -571,6 +595,7 @@ impl TypeRegistryInner {
 
         // If we've already registered this rec group before, reuse it.
         if let Some(entry) = self.hash_consing_map.get(&hash_consing_key) {
+            assert_eq!(entry.0.unregistered.load(Acquire), false);
             entry.incref(
                 "hash consed to already-registered type in `TypeRegistryInner::register_rec_group`",
             );
@@ -582,8 +607,9 @@ impl TypeRegistryInner {
         // while this rec group is still alive.
         hash_consing_key
             .trace_engine_indices::<_, ()>(&mut |index| {
-                let entry = &self.type_to_rec_group[index].as_ref().unwrap();
-                entry.incref(
+                let other_entry = &self.type_to_rec_group[index].as_ref().unwrap();
+                assert_eq!(other_entry.0.unregistered.load(Acquire), false);
+                other_entry.incref(
                     "new cross-group type reference to existing type in `register_rec_group`",
                 );
                 Ok(())
@@ -605,7 +631,10 @@ impl TypeRegistryInner {
                         map[idx]
                     } else {
                         let rec_group_offset = idx.as_u32() - module_rec_group_start.as_u32();
-                        VMSharedTypeIndex::from_u32(engine_rec_group_start + rec_group_offset)
+                        let index =
+                            VMSharedTypeIndex::from_u32(engine_rec_group_start + rec_group_offset);
+                        assert!(!index.is_reserved_value());
+                        index
                     }
                 });
                 self.insert_one_type_from_rec_group(module_index, ty)
@@ -616,6 +645,7 @@ impl TypeRegistryInner {
             hash_consing_key,
             shared_type_indices,
             registrations: AtomicUsize::new(1),
+            unregistered: AtomicBool::new(false),
         }));
         log::trace!("create new entry {entry:?} (registrations -> 1)");
 
@@ -778,29 +808,133 @@ impl TypeRegistryInner {
     /// zero remaining registrations.
     fn unregister_entry(&mut self, entry: RecGroupEntry) {
         debug_assert!(self.drop_stack.is_empty());
+
+        // There are two races to guard against before we can unregister the
+        // entry, even though it was on the drop stack:
+        //
+        // 1. Although an entry has to reach zero registrations before it is
+        //    enqueued in the drop stack, we need to double check whether the
+        //    entry is *still* at zero registrations. This is because someone
+        //    else can resurrect the entry in between when the
+        //    zero-registrations count was first observed and when we actually
+        //    acquire the lock to unregister it. In this example, we have
+        //    threads A and B, an existing rec group entry E, and a rec group
+        //    entry E' that is a duplicate of E:
+        //
+        //    Thread A                        | Thread B
+        //    --------------------------------+-----------------------------
+        //    acquire(type registry lock)     |
+        //                                    |
+        //                                    | decref(E) --> 0
+        //                                    |
+        //                                    | block_on(type registry lock)
+        //                                    |
+        //    register(E') == incref(E) --> 1 |
+        //                                    |
+        //    release(type registry lock)     |
+        //                                    |
+        //                                    | acquire(type registry lock)
+        //                                    |
+        //                                    | unregister(E)         !!!!!!
+        //
+        //    If we aren't careful, we can unregister a type while it is still
+        //    in use!
+        //
+        //    The fix in this case is that we skip unregistering the entry if
+        //    its reference count is non-zero, since that means it was
+        //    concurrently resurrected and is now in use again.
+        //
+        // 2. In a slightly more convoluted version of (1), where an entry is
+        //    resurrected but then dropped *again*, someone might attempt to
+        //    unregister an entry a second time:
+        //
+        //    Thread A                        | Thread B
+        //    --------------------------------|-----------------------------
+        //    acquire(type registry lock)     |
+        //                                    |
+        //                                    | decref(E) --> 0
+        //                                    |
+        //                                    | block_on(type registry lock)
+        //                                    |
+        //    register(E') == incref(E) --> 1 |
+        //                                    |
+        //    release(type registry lock)     |
+        //                                    |
+        //    decref(E) --> 0                 |
+        //                                    |
+        //    acquire(type registry lock)     |
+        //                                    |
+        //    unregister(E)                   |
+        //                                    |
+        //    release(type registry lock)     |
+        //                                    |
+        //                                    | acquire(type registry lock)
+        //                                    |
+        //                                    | unregister(E)         !!!!!!
+        //
+        //    If we aren't careful, we can unregister a type twice, which leads
+        //    to panics and registry corruption!
+        //
+        //    To detect this scenario and avoid the double-unregistration bug,
+        //    we maintain an `unregistered` flag on entries. We set this flag
+        //    once an entry is unregistered and therefore, even if it is
+        //    enqueued in the drop stack multiple times, we only actually
+        //    unregister the entry the first time.
+        //
+        // A final note: we don't need to worry about any concurrent
+        // modifications during the middle of this function's execution, only
+        // between (a) when we first observed a zero-registrations count and
+        // decided to unregister the type, and (b) when we acquired the type
+        // registry's lock so that we could perform that unregistration. This is
+        // because this method has exclusive access to `&mut self` -- that is,
+        // we have a write lock on the whole type registry -- and therefore no
+        // one else can create new references to this zero-registration entry
+        // and bring it back to life (which would require finding it in
+        // `self.hash_consing_map`, which no one else has access to, because we
+        // now have an exclusive lock on `self`).
+
+        // Handle scenario (1) from above.
+        let registrations = entry.0.registrations.load(Acquire);
+        if registrations != 0 {
+            log::trace!(
+                "{entry:?} was concurrently resurrected and no longer has \
+                 zero registrations (registrations -> {registrations})",
+            );
+            assert_eq!(entry.0.unregistered.load(Acquire), false);
+            return;
+        }
+
+        // Handle scenario (2) from above.
+        if entry.0.unregistered.load(Acquire) {
+            log::trace!(
+                "{entry:?} was concurrently resurrected, dropped again, \
+                 and already unregistered"
+            );
+            return;
+        }
+
+        // Okay, we are really going to unregister this entry. Enqueue it on the
+        // drop stack.
         self.drop_stack.push(entry);
 
+        // Keep unregistering entries until the drop stack is empty. This is
+        // logically a recursive process where if we unregister a type that was
+        // the only thing keeping another type alive, we then recursively
+        // unregister that other type as well. However, we use this explicit
+        // drop stack to avoid recursion and the potential stack overflows that
+        // recursion implies.
         while let Some(entry) = self.drop_stack.pop() {
             log::trace!("Start unregistering {entry:?}");
 
-            // We need to double check whether the entry is still at zero
-            // registrations: Between the time that we observed a zero and
-            // acquired the lock to call this function, another thread could
-            // have registered the type and found the 0-registrations entry in
-            // `self.map` and incremented its count.
-            //
-            // We don't need to worry about any concurrent increments during
-            // this function's invocation after we check for zero because we
-            // have exclusive access to `&mut self` and therefore no one can
-            // create a new reference to this entry and bring it back to life.
-            let registrations = entry.0.registrations.load(Acquire);
-            if registrations != 0 {
-                log::trace!(
-                    "{entry:?} was concurrently resurrected and no longer has \
-                     zero registrations (registrations -> {registrations})",
-                );
-                continue;
-            }
+            // All entries on the drop stack should *really* be ready for
+            // unregistration, since no one can resurrect entries once we've
+            // locked the registry.
+            assert_eq!(entry.0.registrations.load(Acquire), 0);
+            assert_eq!(entry.0.unregistered.load(Acquire), false);
+
+            // We are taking responsibility for unregistering this entry, so
+            // prevent anyone else from attempting to do it again.
+            entry.0.unregistered.store(true, Release);
 
             // Decrement any other types that this type was shallowly
             // (i.e. non-transitively) referencing and keeping alive. If this
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/supply-chain/imports.lock b/supply-chain/imports.lock
index 9fc1befe5..aae802f14 100644
--- a/supply-chain/imports.lock
+++ b/supply-chain/imports.lock
@@ -25,6 +25,10 @@ audited_as = "0.110.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-bforest]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -49,10 +53,18 @@ audited_as = "0.110.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-bforest]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-bitset]]
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-bitset]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-codegen]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -77,6 +89,10 @@ audited_as = "0.109.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-codegen]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-codegen-meta]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -101,6 +117,10 @@ audited_as = "0.110.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-codegen-meta]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-codegen-shared]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -125,6 +145,10 @@ audited_as = "0.110.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-codegen-shared]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-control]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -149,6 +173,10 @@ audited_as = "0.110.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-control]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-entity]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -173,6 +201,10 @@ audited_as = "0.109.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-entity]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-frontend]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -197,6 +229,10 @@ audited_as = "0.110.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-frontend]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-interpreter]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -221,6 +257,10 @@ audited_as = "0.110.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-interpreter]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-isle]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -245,6 +285,10 @@ audited_as = "0.110.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-isle]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-jit]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -269,6 +313,10 @@ audited_as = "0.109.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-jit]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-module]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -293,6 +341,10 @@ audited_as = "0.110.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-module]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-native]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -317,6 +369,10 @@ audited_as = "0.110.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-native]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-object]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -341,6 +397,10 @@ audited_as = "0.110.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-object]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-reader]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -365,6 +425,10 @@ audited_as = "0.110.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-reader]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-serde]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -389,6 +453,10 @@ audited_as = "0.109.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-serde]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.cranelift-wasm]]
 version = "0.107.0"
 audited_as = "0.105.2"
@@ -413,6 +481,10 @@ audited_as = "0.110.0"
 version = "0.110.2"
 audited_as = "0.110.1"
 
+[[unpublished.cranelift-wasm]]
+version = "0.110.3"
+audited_as = "0.110.2"
+
 [[unpublished.wasi-common]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -437,6 +509,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasi-common]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -461,6 +537,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-asm-macros]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -485,6 +565,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-asm-macros]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-cache]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -509,6 +593,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-cache]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-cli]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -533,6 +621,10 @@ audited_as = "22.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-cli]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-cli-flags]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -557,6 +649,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-cli-flags]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-component-macro]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -581,6 +677,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-component-macro]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-component-util]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -605,6 +705,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-component-util]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-cranelift]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -629,6 +733,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-cranelift]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-cranelift-shared]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -657,6 +765,10 @@ audited_as = "22.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-environ]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-explorer]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -681,6 +793,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-explorer]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-fiber]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -705,6 +821,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-fiber]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-jit-debug]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -729,6 +849,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-jit-debug]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-jit-icache-coherence]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -753,6 +877,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-jit-icache-coherence]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-runtime]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -785,6 +913,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-slab]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-types]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -809,6 +941,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-types]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-wasi]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -833,6 +969,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-wasi]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-wasi-http]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -857,6 +997,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-wasi-http]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-wasi-nn]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -881,6 +1025,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-wasi-nn]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-wasi-threads]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -905,6 +1053,10 @@ audited_as = "22.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-wasi-threads]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-wast]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -929,6 +1081,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-wast]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-winch]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -953,6 +1109,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-winch]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-wit-bindgen]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -977,6 +1137,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-wit-bindgen]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wasmtime-wmemcheck]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -1001,6 +1165,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wasmtime-wmemcheck]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wiggle]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -1025,6 +1193,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wiggle]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wiggle-generate]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -1049,6 +1221,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wiggle-generate]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wiggle-macro]]
 version = "20.0.0"
 audited_as = "18.0.2"
@@ -1073,6 +1249,10 @@ audited_as = "23.0.0"
 version = "23.0.2"
 audited_as = "23.0.1"
 
+[[unpublished.wiggle-macro]]
+version = "23.0.3"
+audited_as = "23.0.2"
+
 [[unpublished.wiggle-test]]
 version = "0.0.0"
 audited_as = "0.1.0"
@@ -1101,6 +1281,10 @@ audited_as = "0.21.0"
 version = "0.21.2"
 audited_as = "0.21.1"
 
+[[unpublished.winch-codegen]]
+version = "0.21.3"
+audited_as = "0.21.2"
+
 [[publisher.aho-corasick]]
 version = "1.0.2"
 when = "2023-06-04"
@@ -1330,6 +1514,12 @@ when = "2024-07-22"
 user-id = 73222
 user-login = "wasmtime-publish"
 
+[[publisher.cranelift-bitset]]
+version = "0.110.2"
+when = "2024-08-12"
+user-id = 73222
+user-login = "wasmtime-publish"
+
 [[publisher.cranelift-codegen]]
 version = "0.105.2"
 when = "2024-02-28"
@@ -2881,6 +3071,12 @@ when = "2024-07-22"
 user-id = 73222
 user-login = "wasmtime-publish"
 
+[[publisher.wasmtime-slab]]
+version = "23.0.2"
+when = "2024-08-12"
+user-id = 73222
+user-login = "wasmtime-publish"
+
 [[publisher.wasmtime-types]]
 version = "18.0.2"
 when = "2024-02-28"
diff --git a/winch/codegen/Cargo.toml b/winch/codegen/Cargo.toml
index 970e260d5..49390b0b6 100644
--- a/winch/codegen/Cargo.toml
+++ b/winch/codegen/Cargo.toml
@@ -4,7 +4,7 @@ name = "winch-codegen"
 description = "Winch code generation library"
 license = "Apache-2.0 WITH LLVM-exception"
 repository = "https://github.com/bytecodealliance/wasmtime"
-version = "0.21.2"
+version = "0.21.3"
 edition.workspace = true
 
 [lints]


Test patch:
diff --git a/tests/all/module.rs b/tests/all/module.rs
index 94a56acf5..1b28912ce 100644
--- a/tests/all/module.rs
+++ b/tests/all/module.rs
@@ -1,4 +1,8 @@
+use anyhow::Context;
+use std::sync::atomic::{AtomicBool, Ordering::Relaxed};
+use std::sync::Arc;
 use wasmtime::*;
+use wasmtime_test_macros::wasmtime_test;
 
 #[test]
 fn checks_incompatible_target() -> Result<()> {
@@ -306,3 +310,237 @@ fn cross_engine_module_exports() -> Result<()> {
     assert!(instance.get_module_export(&mut store, &export).is_none());
     Ok(())
 }
+
+/// 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();
+
+    // The number of seconds to run the smoke test.
+    const TEST_DURATION_SECONDS: u64 = 5;
+
+    // The number of worker threads to spawn for this smoke test.
+    const NUM_WORKER_THREADS: usize = 32;
+
+    let engine = Engine::new(config)?;
+
+    /// Tests of various kinds of modifications to the type registry.
+    enum Test {
+        /// Creating a module (from its text format) should register new entries
+        /// in the type registry.
+        Module(&'static str),
+        /// Creating an individual func type registers a singleton entry in the
+        /// registry which is managed slightly differently from modules.
+        Func(fn(&Engine) -> FuncType),
+        /// Create a single struct type like a single function type.
+        Struct(fn(&Engine) -> StructType),
+        /// Create a single array type like a single function type.
+        Array(fn(&Engine) -> ArrayType),
+    }
+    const TESTS: &'static [Test] = &[
+        Test::Func(|engine| FuncType::new(engine, [], [])),
+        Test::Func(|engine| FuncType::new(engine, [], [ValType::I32])),
+        Test::Func(|engine| FuncType::new(engine, [ValType::I32], [])),
+        Test::Struct(|engine| StructType::new(engine, []).unwrap()),
+        Test::Array(|engine| {
+            ArrayType::new(engine, FieldType::new(Mutability::Const, StorageType::I8))
+        }),
+        Test::Array(|engine| {
+            ArrayType::new(engine, FieldType::new(Mutability::Var, StorageType::I8))
+        }),
+        Test::Module(
+            r#"
+                (module
+                    ;; A handful of function types.
+                    (type (func))
+                    (type (func (param i32)))
+                    (type (func (result i32)))
+                    (type (func (param i32) (result i32)))
+
+                    ;; A handful of recursive types.
+                    (rec)
+                    (rec (type $s (struct (field (ref null $s)))))
+                    (rec (type $a (struct (field (ref null $b))))
+                         (type $b (struct (field (ref null $a)))))
+                    (rec (type $c (struct (field (ref null $b))
+                                          (field (ref null $d))))
+                         (type $d (struct (field (ref null $a))
+                                          (field (ref null $c)))))
+
+                    ;; Some GC types
+                    (type (struct))
+                    (type (array i8))
+                    (type (array (mut i8)))
+                )
+            "#,
+        ),
+        Test::Module(
+            r#"
+                (module
+                    ;; Just the function types.
+                    (type (func))
+                    (type (func (param i32)))
+                    (type (func (result i32)))
+                    (type (func (param i32) (result i32)))
+                )
+            "#,
+        ),
+        Test::Module(
+            r#"
+                (module
+                    ;; Just the recursive types.
+                    (rec)
+                    (rec (type $s (struct (field (ref null $s)))))
+                    (rec (type $a (struct (field (ref null $b))))
+                         (type $b (struct (field (ref null $a)))))
+                    (rec (type $c (struct (field (ref null $b))
+                                          (field (ref null $d))))
+                         (type $d (struct (field (ref null $a))
+                                          (field (ref null $c)))))
+                )
+            "#,
+        ),
+        Test::Module(
+            r#"
+                (module
+                    ;; One of each kind of type.
+                    (type (func (param i32) (result i32)))
+                    (rec (type $a (struct (field (ref null $b))))
+                         (type $b (struct (field (ref null $a)))))
+                )
+            "#,
+        ),
+    ];
+
+    // Spawn the worker threads, each of them just registering and unregistering
+    // modules (and their types) constantly for the duration of the smoke test.
+    let handles = (0..NUM_WORKER_THREADS)
+        .map(|_| {
+            let engine = engine.clone();
+            std::thread::spawn(move || -> Result<()> {
+                let mut tests = TESTS.iter().cycle();
+                let start = std::time::Instant::now();
+                while start.elapsed().as_secs() < TEST_DURATION_SECONDS {
+                    match tests.next() {
+                        Some(Test::Module(wat)) => {
+                            let _ = Module::new(&engine, wat)?;
+                        }
+                        Some(Test::Func(ctor)) => {
+                            let _ = ctor(&engine);
+                        }
+                        Some(Test::Struct(ctor)) => {
+                            let _ = ctor(&engine);
+                        }
+                        Some(Test::Array(ctor)) => {
+                            let _ = ctor(&engine);
+                        }
+                        None => unreachable!(),
+                    }
+                }
+
+                Ok(())
+            })
+        })
+        .collect::<Vec<_>>();
+
+    // Join all of the thread handles.
+    for handle in handles {
+        handle
+            .join()
+            .expect("should join thread handle")
+            .context("error during thread execution")?;
+    }
+
+    Ok(())
+}
+
+#[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;
+
+    let _ = env_logger::try_init();
+
+    let engine = Engine::new(&config)?;
+
+    let mut threads = Vec::new();
+    let keep_going = Arc::new(AtomicBool::new(true));
+
+    // Spawn a number of threads that are all working with a module and testing
+    // various properties about type-checks in the module.
+    for _ in 0..THREADS_CHECKING {
+        threads.push(std::thread::spawn({
+            let engine = engine.clone();
+            let keep_going = keep_going.clone();
+            move || -> Result<()> {
+                while keep_going.load(Relaxed) {
+                    let module = Module::new(
+                        &engine,
+                        r#"
+                            (module
+                                (func (export "f") (param funcref)
+                                    i32.const 0
+                                    local.get 0
+                                    table.set
+                                    i32.const 0
+                                    call_indirect (result f64)
+                                    drop
+                                )
+
+                                (table 1 funcref)
+                            )
+                        "#,
+                    )?;
+                    let ty = FuncType::new(&engine, [], [ValType::I32]);
+                    let mut store = Store::new(&engine, ());
+                    let func = Func::new(&mut store, ty, |_, _, results| {
+                        results[0] = Val::I32(0);
+                        Ok(())
+                    });
+
+                    let instance = Instance::new(&mut store, &module, &[])?;
+                    assert!(instance.get_typed_func::<(), i32>(&mut store, "f").is_err());
+                    assert!(instance.get_typed_func::<(), f64>(&mut store, "f").is_err());
+                    let f = instance.get_typed_func::<Func, ()>(&mut store, "f")?;
+                    let err = f.call(&mut store, func).unwrap_err();
+                    assert_eq!(err.downcast::<Trap>()?, Trap::BadSignature);
+                }
+                Ok(())
+            }
+        }));
+    }
+
+    // Spawn threads in the background creating/destroying `FuncType`s related
+    // to the module above.
+    threads.push(std::thread::spawn({
+        let engine = engine.clone();
+        let keep_going = keep_going.clone();
+        move || -> Result<()> {
+            while keep_going.load(Relaxed) {
+                FuncType::new(&engine, [], [ValType::F64]);
+            }
+            Ok(())
+        }
+    }));
+    threads.push(std::thread::spawn({
+        let engine = engine.clone();
+        let keep_going = keep_going.clone();
+        move || -> Result<()> {
+            while keep_going.load(Relaxed) {
+                FuncType::new(&engine, [], [ValType::I32]);
+            }
+            Ok(())
+        }
+    }));
+
+    std::thread::sleep(std::time::Duration::new(2, 0));
+    keep_going.store(false, Relaxed);
+
+    for thread in threads {
+        thread.join().unwrap()?;
+    }
+
+    Ok(())
+}
diff --git a/tests/all/traps.rs b/tests/all/traps.rs
index 7c356adad..8fc77391a 100644
--- a/tests/all/traps.rs
+++ b/tests/all/traps.rs
@@ -6,6 +6,9 @@ use std::process::Command;
 use std::sync::{Arc, Mutex};
 use wasmtime::*;
 
+#[cfg(not(target_arch = "s390x"))]
+use wasmtime_test_macros::wasmtime_test;
+
 #[test]
 fn test_trap_return() -> Result<()> {
     let mut store = Store::<()>::default();
@@ -1679,3 +1682,117 @@ fn async_stack_size_ignored_if_disabled() -> Result<()> {
 
     Ok(())
 }
+
+#[wasmtime_test(wasm_features(tail_call))]
+#[cfg(not(target_arch = "s390x"))]
+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))]
+#[cfg(not(target_arch = "s390x"))]
+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))]
+#[cfg(not(target_arch = "s390x"))]
+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))]
+#[cfg(not(target_arch = "s390x"))]
+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(())
+}
diff --git a/tests/misc_testsuite/gc/more-rec-groups-than-types.wast b/tests/misc_testsuite/gc/more-rec-groups-than-types.wast
new file mode 100644
index 000000000..5f3644de0
--- /dev/null
+++ b/tests/misc_testsuite/gc/more-rec-groups-than-types.wast
@@ -0,0 +1,18 @@
+;; Test that we properly handle empty rec groups and when we have more rec
+;; groups defined in the type section than actual types (and therefore the
+;; length that the type section reports is greater than the length of the types
+;; index space).
+
+(module
+  (rec)
+  (rec)
+  (rec)
+  (rec)
+  (rec)
+  (rec)
+  (rec)
+  (rec)
+  (rec)
+  (rec)
+  (type (func (param i32) (result i32)))
+)