From 5560b9ceaad7f04f125e805101a8926210501100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Tue, 1 Jul 2025 12:35:00 +0300 Subject: [PATCH 001/271] gdb: fix issue "Debug not enabled" when `gdb` feature was enabled (#678) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - This happened due to a message that was sent from the Hypervisor to the `gdb` thread even if the sandbox had no debug enabled. The transmission failed and returned this error. - The fix checks a condition before sending this signal so that to ensure the sandbox has debugging enabled Signed-off-by: Doru Blânzeanu --- .../examples/guest-debugging/main.rs | 31 +++++++++++++++++-- .../src/hypervisor/hyperv_linux.rs | 4 ++- .../src/hypervisor/hyperv_windows.rs | 4 ++- src/hyperlight_host/src/hypervisor/kvm.rs | 4 ++- src/tests/rust_guests/witguest/Cargo.lock | 18 +++++------ 5 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/hyperlight_host/examples/guest-debugging/main.rs b/src/hyperlight_host/examples/guest-debugging/main.rs index 42b97598d..f33ed511f 100644 --- a/src/hyperlight_host/examples/guest-debugging/main.rs +++ b/src/hyperlight_host/examples/guest-debugging/main.rs @@ -41,14 +41,27 @@ fn get_sandbox_cfg() -> Option { fn main() -> hyperlight_host::Result<()> { let cfg = get_sandbox_cfg(); + // Create an uninitialized sandbox with a guest binary and debug enabled + let mut uninitialized_sandbox_dbg = UninitializedSandbox::new( + hyperlight_host::GuestBinary::FilePath( + hyperlight_testing::simple_guest_as_string().unwrap(), + ), + cfg, // sandbox configuration + )?; + // Create an uninitialized sandbox with a guest binary let mut uninitialized_sandbox = UninitializedSandbox::new( hyperlight_host::GuestBinary::FilePath( hyperlight_testing::simple_guest_as_string().unwrap(), ), - cfg, // sandbox configuration + None, // sandbox configuration )?; + // Register a host functions + uninitialized_sandbox_dbg.register("Sleep5Secs", || { + thread::sleep(std::time::Duration::from_secs(5)); + Ok(()) + })?; // Register a host functions uninitialized_sandbox.register("Sleep5Secs", || { thread::sleep(std::time::Duration::from_secs(5)); @@ -56,11 +69,23 @@ fn main() -> hyperlight_host::Result<()> { })?; // Note: This function is unused, it's just here for demonstration purposes - // Initialize sandbox to be able to call host functions + // Initialize sandboxes to be able to call host functions + let mut multi_use_sandbox_dbg: MultiUseSandbox = + uninitialized_sandbox_dbg.evolve(Noop::default())?; let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve(Noop::default())?; // Call guest function - let message = "Hello, World! I am executing inside of a VM :)\n".to_string(); + let message = + "Hello, World! I am executing inside of a VM with debugger attached :)\n".to_string(); + multi_use_sandbox_dbg + .call_guest_function_by_name::( + "PrintOutput", // function must be defined in the guest binary + message.clone(), + ) + .unwrap(); + + let message = + "Hello, World! I am executing inside of a VM without debugger attached :)\n".to_string(); multi_use_sandbox .call_guest_function_by_name::( "PrintOutput", // function must be defined in the guest binary diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index db3f81c9b..db5037106 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -441,7 +441,9 @@ impl HypervLinuxDriver { // Send the interrupt handle to the GDB thread if debugging is enabled // This is used to allow the GDB thread to stop the vCPU #[cfg(gdb)] - hv.send_dbg_msg(DebugResponse::InterruptHandle(interrupt_handle))?; + if hv.debug.is_some() { + hv.send_dbg_msg(DebugResponse::InterruptHandle(interrupt_handle))?; + } Ok(hv) } diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index 0d6d794bc..288b5bf5b 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -356,7 +356,9 @@ impl HypervWindowsDriver { // Send the interrupt handle to the GDB thread if debugging is enabled // This is used to allow the GDB thread to stop the vCPU #[cfg(gdb)] - hv.send_dbg_msg(DebugResponse::InterruptHandle(interrupt_handle))?; + if hv.debug.is_some() { + hv.send_dbg_msg(DebugResponse::InterruptHandle(interrupt_handle))?; + } Ok(hv) } diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index d6b348cc0..d85a6a838 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -395,7 +395,9 @@ impl KVMDriver { // Send the interrupt handle to the GDB thread if debugging is enabled // This is used to allow the GDB thread to stop the vCPU #[cfg(gdb)] - hv.send_dbg_msg(DebugResponse::InterruptHandle(interrupt_handle))?; + if hv.debug.is_some() { + hv.send_dbg_msg(DebugResponse::InterruptHandle(interrupt_handle))?; + } Ok(hv) } diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index 478740f35..a1edc4b10 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -178,7 +178,7 @@ dependencies = [ [[package]] name = "hyperlight-common" -version = "0.6.1" +version = "0.7.0" dependencies = [ "anyhow", "flatbuffers", @@ -188,7 +188,7 @@ dependencies = [ [[package]] name = "hyperlight-component-macro" -version = "0.6.1" +version = "0.7.0" dependencies = [ "env_logger", "hyperlight-component-util", @@ -202,7 +202,7 @@ dependencies = [ [[package]] name = "hyperlight-component-util" -version = "0.6.1" +version = "0.7.0" dependencies = [ "itertools", "log", @@ -215,7 +215,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.6.1" +version = "0.7.0" dependencies = [ "anyhow", "hyperlight-common", @@ -224,7 +224,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.6.1" +version = "0.7.0" dependencies = [ "buddy_system_allocator", "cc", @@ -337,9 +337,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.34" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6837b9e10d61f45f987d50808f83d1ee3d206c66acf650c3e4ae2e1f6ddedf55" +checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" dependencies = [ "proc-macro2", "syn", @@ -477,9 +477,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.103" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", From 3dd58b312c50241dab0b8955b1f637348a7799af Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Tue, 1 Jul 2025 09:16:38 -0700 Subject: [PATCH 002/271] Switch 'deny' lints to 'warn' to simplify local development. Warnings will be caught by clippy regardless in CI (#679) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- src/hyperlight_host/src/lib.rs | 2 +- src/hyperlight_host/src/sandbox/hypervisor.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/hyperlight_host/src/lib.rs b/src/hyperlight_host/src/lib.rs index 998bc9c9e..2c52729a5 100644 --- a/src/hyperlight_host/src/lib.rs +++ b/src/hyperlight_host/src/lib.rs @@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -#![deny(dead_code, missing_docs, unused_mut)] +#![warn(dead_code, missing_docs, unused_mut)] //! This crate contains an SDK that is used to execute specially- // compiled binaries within a very lightweight hypervisor environment. diff --git a/src/hyperlight_host/src/sandbox/hypervisor.rs b/src/hyperlight_host/src/sandbox/hypervisor.rs index 7cd1154ee..114083c78 100644 --- a/src/hyperlight_host/src/sandbox/hypervisor.rs +++ b/src/hyperlight_host/src/sandbox/hypervisor.rs @@ -77,3 +77,9 @@ pub(crate) enum HypervisorType { #[cfg(target_os = "windows")] Whp, } + +// Compiler error if no hypervisor type is available +#[cfg(not(any(kvm, mshv, target_os = "windows")))] +compile_error!( + "No hypervisor type is available for the current platform. Please enable either the `kvm` or `mshv` cargo feature." +); From c725c8bdbdb575fd97e269647e6f3ab05684a213 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 10:02:29 +0100 Subject: [PATCH 003/271] Bump crate-ci/typos from 1.33.1 to 1.34.0 (#681) * Fix typos Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> * Bump crate-ci/typos from 1.33.1 to 1.34.0 Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.33.1 to 1.34.0. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.33.1...v1.34.0) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.34.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --------- Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> Signed-off-by: dependabot[bot] Co-authored-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ValidatePullRequest.yml | 2 +- src/hyperlight_host/benches/benchmarks.rs | 2 +- src/hyperlight_host/src/seccomp/guest.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index 83a3cb2d4..4c8432cd7 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -65,7 +65,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Spell Check Repo - uses: crate-ci/typos@v1.33.1 + uses: crate-ci/typos@v1.34.0 license-headers: name: check license headers diff --git a/src/hyperlight_host/benches/benchmarks.rs b/src/hyperlight_host/benches/benchmarks.rs index a0943a1ea..c9160ff52 100644 --- a/src/hyperlight_host/benches/benchmarks.rs +++ b/src/hyperlight_host/benches/benchmarks.rs @@ -82,7 +82,7 @@ fn guest_call_benchmark(c: &mut Criterion) { fn guest_call_benchmark_large_param(c: &mut Criterion) { let mut group = c.benchmark_group("guest_functions_with_large_parameters"); #[cfg(target_os = "windows")] - group.sample_size(10); // This benchark is very slow on Windows, so we reduce the sample size to avoid long test runs. + group.sample_size(10); // This benchmark is very slow on Windows, so we reduce the sample size to avoid long test runs. // This benchmark includes time to first clone a vector and string, so it is not a "pure' benchmark of the guest call, but it's still useful group.bench_function("guest_call_with_large_parameters", |b| { diff --git a/src/hyperlight_host/src/seccomp/guest.rs b/src/hyperlight_host/src/seccomp/guest.rs index cd4801d89..b08f483f6 100644 --- a/src/hyperlight_host/src/seccomp/guest.rs +++ b/src/hyperlight_host/src/seccomp/guest.rs @@ -120,7 +120,7 @@ pub(crate) fn get_seccomp_filter_for_host_function_worker_thread( )? .try_into()?; - // If `openat` is an exclicitly allowed syscall, we shouldn't return the filter that forces it to return EACCES. + // If `openat` is an explicitly allowed syscall, we shouldn't return the filter that forces it to return EACCES. if let Some(extra_syscalls) = extra_allowed_syscalls { if extra_syscalls.contains(&libc::SYS_openat) { return Ok(vec![allowlist]); From 9108a592e360cd9d78906b0a8106cbb3a26b9444 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Jul 2025 04:12:24 +0000 Subject: [PATCH 004/271] Bump tokio from 1.45.1 to 1.46.0 (#687) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.45.1 to 1.46.0. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.45.1...tokio-1.46.0) --- updated-dependencies: - dependency-name: tokio dependency-version: 1.46.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 17 +++++++++++++++-- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7983d278c..26019e9d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1494,6 +1494,17 @@ dependencies = [ "serde", ] +[[package]] +name = "io-uring" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "libc", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -3138,17 +3149,19 @@ dependencies = [ [[package]] name = "tokio" -version = "1.45.1" +version = "1.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +checksum = "1140bb80481756a8cbe10541f37433b459c5aa1e727b4c020fbfebdc25bf3ec4" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", + "slab", "socket2", "tokio-macros", "windows-sys 0.52.0", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 3dfd9482b..17bab1b56 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -96,7 +96,7 @@ opentelemetry = "0.30.0" opentelemetry-otlp = { version = "0.30.0", features = ["default", "grpc-tonic"] } opentelemetry-semantic-conventions = "0.30" opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio"] } -tokio = { version = "1.45.1", features = ["full"] } +tokio = { version = "1.46.0", features = ["full"] } criterion = "0.6.0" tracing-chrome = "0.7.2" metrics-util = "0.20.0" From 63c492f4f208fb6a7ce0bc6465ebbb92af148099 Mon Sep 17 00:00:00 2001 From: Isaac Foster Date: Thu, 3 Jul 2025 12:14:31 -0400 Subject: [PATCH 005/271] Update paging-development-notes.md (#675) typo Signed-off-by: Isaac Foster --- docs/paging-development-notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/paging-development-notes.md b/docs/paging-development-notes.md index ae63f1a18..e1f4d3c0b 100644 --- a/docs/paging-development-notes.md +++ b/docs/paging-development-notes.md @@ -1,6 +1,6 @@ # Paging in Hyperlight -Hyperlight uses paging, which means the all addresses inside a Hyperlight VM are treated as virtual addresses by the processor. Specifically, Hyperlight uses (ordinary) 4-level paging. 4-level paging is used because we set the following control registers on logical cores inside a VM: `CR0.PG = 1, CR4.PAE = 1, IA32_EFER.LME = 1, and CR4.LA57 = 0`. A Hyperlight VM is limited to 1GB of addressable memory, see below for more details. These control register settings have the following effects: +Hyperlight uses paging, which means that all addresses inside a Hyperlight VM are treated as virtual addresses by the processor. Specifically, Hyperlight uses (ordinary) 4-level paging. 4-level paging is used because we set the following control registers on logical cores inside a VM: `CR0.PG = 1, CR4.PAE = 1, IA32_EFER.LME = 1, and CR4.LA57 = 0`. A Hyperlight VM is limited to 1GB of addressable memory, see below for more details. These control register settings have the following effects: - `CR0.PG = 1`: Enables paging - `CR4.PAE = 1`: Enables Physical Address Extension (PAE) mode (this is required for 4-level paging) From f080c4ec1d79b2fdeadb0e315b93106974742d2d Mon Sep 17 00:00:00 2001 From: Isaac Foster Date: Thu, 3 Jul 2025 12:14:56 -0400 Subject: [PATCH 006/271] Update glossary.md (#673) type/phrasing Signed-off-by: Isaac Foster --- docs/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/glossary.md b/docs/glossary.md index eca0459dd..f5201ffa6 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -54,7 +54,7 @@ The interface that a guest must implement is specific to the associated [host](# A micro virtual machine is an execution environment managed by a hypervisor that isolates a [guest](#guest) from the [host](#host). A hypervisor prevents the guest from directly accessing the host's resources, such as memory, filesystem, devices, memory or CPU. -We use the term Micro Virtual Machine as the VMs are very lightweight compared to traditional VMs, they contains no operating system or other unnecessary components. The goal is to provide a minimal environment for executing workloads with low latency and high density. However the isolation provided by the hypervisor is the same as that of a traditional VM. +We use the term Micro Virtual Machine as the VMs are very lightweight compared to traditional VMs, containing no operating system or other unnecessary components. The goal is to provide a minimal environment for executing workloads with low latency and high density. However the isolation provided by the hypervisor is the same as that of a traditional VM. ## Workload From 93e5e20b9e4d7ad5c775147fb25e230b96f00526 Mon Sep 17 00:00:00 2001 From: Isaac Foster Date: Thu, 3 Jul 2025 12:15:43 -0400 Subject: [PATCH 007/271] Update README.md (#674) phrasing Signed-off-by: Isaac Foster --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index fff51c662..3b36c5db1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -18,7 +18,7 @@ Given a guest, then, Hyperlight takes some simple steps prior to executing it, i ## Basics: Hyperlight architecture -This project is composed internally of several internal components, depicted in the below diagram: +This project is composed internally of several components, depicted in the below diagram: ![Hyperlight architecture](./assets/hyperlight_arch.png) From 907fb8fe9f7cf0afc53fb7752e3b6be9c1bec3a2 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Thu, 3 Jul 2025 10:34:20 -0700 Subject: [PATCH 008/271] Remove some dev-dependecies and cargo features to speed up compilation (#535) * Remove default features from metrics-exporter-prometheus Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Reduce some dependencies from opentelemetry-otlp Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Remove crossbeam dependency by replacing soft-depricated crossbeam::thread::scope with std::thread::scope Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Remove some goblin features we don't need Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --------- Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- Cargo.lock | 547 ++---------------- docs/hyperlight-metrics-logs-and-traces.md | 4 +- src/hyperlight_host/Cargo.toml | 7 +- .../examples/tracing-otlp/main.rs | 9 +- src/hyperlight_host/src/sandbox/host_funcs.rs | 9 +- 5 files changed, 75 insertions(+), 501 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26019e9d4..fe90a7993 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,41 +135,12 @@ dependencies = [ "syn", ] -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "aws-lc-rs" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b756939cb2f8dc900aa6dcd505e6e2428e9cae7ff7b028c49e3946efa70878" -dependencies = [ - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f7720b74ed28ca77f90769a71fd8c637a0137f6fae4ae947e1050229cff57f" -dependencies = [ - "bindgen 0.69.5", - "cc", - "cmake", - "dunce", - "fs_extra", -] - [[package]] name = "backtrace" version = "0.3.74" @@ -182,7 +153,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -191,29 +162,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bindgen" -version = "0.69.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags 2.9.1", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", - "which", -] - [[package]] name = "bindgen" version = "0.70.1" @@ -453,31 +401,12 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" -[[package]] -name = "cmake" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" -dependencies = [ - "cc", -] - [[package]] name = "colorchoice" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" -[[package]] -name = "core-foundation" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -526,19 +455,6 @@ dependencies = [ "itertools 0.10.5", ] -[[package]] -name = "crossbeam" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -651,12 +567,6 @@ dependencies = [ "syn", ] -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - [[package]] name = "either" version = "1.15.0" @@ -759,12 +669,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "futures" version = "0.3.31" @@ -973,25 +877,6 @@ dependencies = [ "scroll", ] -[[package]] -name = "h2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "half" version = "2.6.0" @@ -1024,15 +909,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "http" version = "1.3.1" @@ -1073,12 +949,6 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - [[package]] name = "hyper" version = "1.6.0" @@ -1088,11 +958,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2", "http", "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -1100,50 +968,23 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.27.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" -dependencies = [ - "futures-util", - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-native-certs", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", -] - -[[package]] -name = "hyper-timeout" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" -dependencies = [ - "hyper", - "hyper-util", - "pin-project-lite", - "tokio", - "tower-service", -] - [[package]] name = "hyper-util" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ + "base64", "bytes", "futures-channel", + "futures-core", "futures-util", "http", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", "tokio", @@ -1234,7 +1075,6 @@ dependencies = [ "cfg_aliases", "chrono", "criterion", - "crossbeam", "crossbeam-channel", "crossbeam-queue", "elfcore", @@ -1511,6 +1351,16 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -1526,15 +1376,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -1630,12 +1471,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.174" @@ -1671,7 +1506,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1680,7 +1515,7 @@ version = "0.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78a09b56be5adbcad5aa1197371688dc6bb249a26da3bca2011ee2fb987ebfb" dependencies = [ - "bindgen 0.70.1", + "bindgen", "errno", "libc", ] @@ -1707,12 +1542,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -1801,18 +1630,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b166dea96003ee2531cf14833efedced545751d800f03535801d833313f8c15" dependencies = [ "base64", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", "indexmap", - "ipnet", "metrics", "metrics-util", "quanta", "thiserror 2.0.12", - "tokio", - "tracing", ] [[package]] @@ -1835,12 +1657,6 @@ dependencies = [ "sketches-ddsketch", ] -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2005,12 +1821,6 @@ version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - [[package]] name = "opentelemetry" version = "0.30.0" @@ -2052,9 +1862,6 @@ dependencies = [ "prost", "reqwest", "thiserror 2.0.12", - "tokio", - "tonic", - "tracing", ] [[package]] @@ -2144,7 +1951,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2281,7 +2088,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3db44c5aa60e193a25fcd93bb9ed27423827e8f118897866f946e2cf936c44fb" dependencies = [ "anyhow", - "bindgen 0.70.1", + "bindgen", "libc", "libproc", "mach2", @@ -2325,7 +2132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.10.5", "proc-macro2", "quote", "syn", @@ -2519,9 +2326,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "4c8cea6b35bcceb099f30173754403d2eba0a5dc18cea3630fccd88251909288" dependencies = [ "base64", "bytes", @@ -2533,11 +2340,8 @@ dependencies = [ "http-body-util", "hyper", "hyper-util", - "ipnet", "js-sys", "log", - "mime", - "once_cell", "percent-encoding", "pin-project-lite", "serde", @@ -2546,26 +2350,12 @@ dependencies = [ "sync_wrapper", "tokio", "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows-registry", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.15", - "libc", - "untrusted", - "windows-sys 0.52.0", ] [[package]] @@ -2625,19 +2415,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags 2.9.1", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - [[package]] name = "rustix" version = "1.0.5" @@ -2647,54 +2424,10 @@ dependencies = [ "bitflags 2.9.1", "errno", "libc", - "linux-raw-sys 0.9.4", + "linux-raw-sys", "windows-sys 0.59.0", ] -[[package]] -name = "rustls" -version = "0.23.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" -dependencies = [ - "aws-lc-rs", - "once_cell", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pki-types" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" - -[[package]] -name = "rustls-webpki" -version = "0.103.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" -dependencies = [ - "aws-lc-rs", - "ring", - "rustls-pki-types", - "untrusted", -] - [[package]] name = "rustversion" version = "1.0.20" @@ -2737,15 +2470,6 @@ dependencies = [ "sdd", ] -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "scoped-tls" version = "1.0.1" @@ -2793,29 +2517,6 @@ dependencies = [ "libc", ] -[[package]] -name = "security-framework" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" -dependencies = [ - "bitflags 2.9.1", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" version = "1.0.26" @@ -3018,12 +2719,6 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - [[package]] name = "syn" version = "2.0.104" @@ -3064,7 +2759,7 @@ dependencies = [ "fastrand", "getrandom 0.3.2", "once_cell", - "rustix 1.0.5", + "rustix", "windows-sys 0.59.0", ] @@ -3178,16 +2873,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-rustls" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" -dependencies = [ - "rustls", - "tokio", -] - [[package]] name = "tokio-stream" version = "0.1.17" @@ -3199,19 +2884,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-util" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - [[package]] name = "toml" version = "0.8.20" @@ -3258,15 +2930,10 @@ dependencies = [ "http", "http-body", "http-body-util", - "hyper", - "hyper-timeout", - "hyper-util", "percent-encoding", "pin-project", "prost", - "tokio", "tokio-stream", - "tower", "tower-layer", "tower-service", "tracing", @@ -3280,15 +2947,29 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "indexmap", "pin-project-lite", - "slab", "sync_wrapper", "tokio", - "tokio-util", "tower-layer", "tower-service", - "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.9.1", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", ] [[package]] @@ -3448,7 +3129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69fff37da548239c3bf9e64a12193d261e8b22b660991c6fd2df057c168f435f" dependencies = [ "cc", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3475,12 +3156,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - [[package]] name = "url" version = "2.5.4" @@ -3697,18 +3372,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - [[package]] name = "winapi" version = "0.3.9" @@ -3747,7 +3410,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ "windows-core 0.58.0", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3782,7 +3445,7 @@ dependencies = [ "windows-interface 0.58.0", "windows-result 0.2.0", "windows-strings 0.1.0", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3869,24 +3532,13 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-registry" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" -dependencies = [ - "windows-result 0.3.4", - "windows-strings 0.3.1", - "windows-targets 0.53.0", -] - [[package]] name = "windows-result" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3905,16 +3557,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ "windows-result 0.2.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-strings" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" -dependencies = [ - "windows-link", + "windows-targets", ] [[package]] @@ -3932,7 +3575,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3941,7 +3584,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3950,30 +3593,14 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -4000,96 +3627,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "winnow" version = "0.7.6" @@ -4206,12 +3785,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - [[package]] name = "zerovec" version = "0.10.4" diff --git a/docs/hyperlight-metrics-logs-and-traces.md b/docs/hyperlight-metrics-logs-and-traces.md index 3dc62438d..9158b43e2 100644 --- a/docs/hyperlight-metrics-logs-and-traces.md +++ b/docs/hyperlight-metrics-logs-and-traces.md @@ -81,13 +81,13 @@ The sample will run and generate trace data until any key is pressed. To view the trace data, leave the example running and use the jaegertracing/all-in-one container image with the following command: ```console - docker run -d --name jaeger -e COLLECTOR_OTLP_ENABLED=true -p 4317:4317 -p 16686:16686 jaegertracing/all-in-one:1.60 + docker run -p 16686:16686 -p 4317:4317 -p 4318:4318 -e COLLECTOR_OTLP_ENABLED=true jaegertracing/all-in-one:latest ``` NOTE: when running this on windows that this is a linux container, so you will need to ensure that docker is configured to run linux containers using WSL2. Alternatively, you can download the Jaeger binaries from [here](https://www.jaegertracing.io/download/). Extract the archive and run the `jaeger-all-in-one` executable as follows: ```powershell -.\jaeger-all-in-one.exe --collector.otlp.grpc.host-port=4317 +.\jaeger-all-in-one.exe ``` Once the container or the exe is running, the trace output can be viewed in the jaeger UI at [http://localhost:16686/search](http://localhost:16686/search). diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 17bab1b56..98fbf289a 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -23,7 +23,7 @@ workspace = true [dependencies] gdbstub = { version = "0.7.6", optional = true } gdbstub_arch = { version = "0.3.2", optional = true } -goblin = { version = "0.10" } +goblin = { version = "0.10", default-features = false, features = ["std", "elf32", "elf64", "endian_fd"] } rand = { version = "0.9" } cfg-if = { version = "1.0.1" } libc = { version = "0.2.174" } @@ -37,7 +37,6 @@ tracing-log = "0.2.0" tracing-core = "0.1.34" hyperlight-common = { workspace = true, default-features = true, features = [ "std" ] } vmm-sys-util = "0.14.0" -crossbeam = "0.8.0" crossbeam-channel = "0.5.15" thiserror = "2.0.12" chrono = { version = "0.4", optional = true } @@ -93,14 +92,14 @@ tracing = "0.1.41" tracing-subscriber = {version = "0.3.19", features = ["std", "env-filter"]} tracing-opentelemetry = "0.31.0" opentelemetry = "0.30.0" -opentelemetry-otlp = { version = "0.30.0", features = ["default", "grpc-tonic"] } +opentelemetry-otlp = { version = "0.30.0", default-features = false, features = ["http-proto", "reqwest-blocking-client"] } opentelemetry-semantic-conventions = "0.30" opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio"] } tokio = { version = "1.46.0", features = ["full"] } criterion = "0.6.0" tracing-chrome = "0.7.2" metrics-util = "0.20.0" -metrics-exporter-prometheus = "0.17.2" +metrics-exporter-prometheus = { version = "0.17.2", default-features = false } tracing-tracy = "0.11.4" serde_json = "1.0" hyperlight-component-macro = { workspace = true } diff --git a/src/hyperlight_host/examples/tracing-otlp/main.rs b/src/hyperlight_host/examples/tracing-otlp/main.rs index ab8196972..86b6b4e29 100644 --- a/src/hyperlight_host/examples/tracing-otlp/main.rs +++ b/src/hyperlight_host/examples/tracing-otlp/main.rs @@ -34,14 +34,14 @@ use hyperlight_host::{GuestBinary, MultiUseSandbox, Result as HyperlightResult}; use hyperlight_testing::simple_guest_as_string; use opentelemetry::trace::TracerProvider; use opentelemetry::{KeyValue, global}; -use opentelemetry_otlp::{SpanExporter, WithExportConfig}; +use opentelemetry_otlp::{Protocol, SpanExporter, WithExportConfig}; //use opentelemetry_sdk::runtime::Tokio; use opentelemetry_sdk::Resource; use opentelemetry_semantic_conventions::attribute::SERVICE_VERSION; use tracing_subscriber::EnvFilter; use uuid::Uuid; -const ENDPOINT_ADDR: &str = "http://localhost:4317/"; +const ENDPOINT_ADDR: &str = "http://localhost:4318/v1/traces"; fn fn_writer(_msg: String) -> HyperlightResult { Ok(0) @@ -64,7 +64,8 @@ fn init_tracing_subscriber( addr: &str, ) -> Result> { let exporter = SpanExporter::builder() - .with_tonic() + .with_http() + .with_protocol(Protocol::HttpBinary) .with_endpoint(addr) .build()?; @@ -218,7 +219,7 @@ mod test { use super::*; - const TESTER_ADDR: &str = "127.0.0.1:4317"; + const TESTER_ADDR: &str = "127.0.0.1:4318"; async fn handle(mut stream: TcpStream) -> Result<()> { let mut buf = Vec::with_capacity(128); diff --git a/src/hyperlight_host/src/sandbox/host_funcs.rs b/src/hyperlight_host/src/sandbox/host_funcs.rs index 158ff87d5..96751f391 100644 --- a/src/hyperlight_host/src/sandbox/host_funcs.rs +++ b/src/hyperlight_host/src/sandbox/host_funcs.rs @@ -159,13 +159,15 @@ fn maybe_with_seccomp( syscalls: Option<&[ExtraAllowedSyscall]>, f: impl FnOnce() -> Result + Send, ) -> Result { + use std::thread; + use crate::seccomp::guest::get_seccomp_filter_for_host_function_worker_thread; // Use a scoped thread so that we can pass around references without having to clone them. - crossbeam::thread::scope(|s| { - s.builder() + thread::scope(|s| { + thread::Builder::new() .name(format!("Host Function Worker Thread for: {name:?}")) - .spawn(move |_| { + .spawn_scoped(s, move || { let seccomp_filter = get_seccomp_filter_for_host_function_worker_thread(syscalls)?; seccomp_filter .iter() @@ -194,7 +196,6 @@ fn maybe_with_seccomp( .join() .map_err(|_| new_error!("Error joining thread executing host function"))? }) - .map_err(|_| new_error!("Error joining thread executing host function"))? } #[cfg(not(all(feature = "seccomp", target_os = "linux")))] From f0fb6b47473c43f7cedb1d006833dcf528088c12 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 3 Jul 2025 10:51:29 -0700 Subject: [PATCH 009/271] Fix README.md host function calling examples to match current API (#682) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jsturtevant <648372+jsturtevant@users.noreply.github.com> --- README.md | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 45f04b70b..042ff7bf2 100644 --- a/README.md +++ b/README.md @@ -33,15 +33,16 @@ It is followed by an example of a simple guest application using the Hyperlight ### Host ```rust -use std::{thread, sync::{Arc, Mutex}}; +use std::thread; -use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnType}; -use hyperlight_host::{UninitializedSandbox, MultiUseSandbox, func::HostFunction0, sandbox_state::transition::Noop, sandbox_state::sandbox::EvolvableSandbox}; +use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; +use hyperlight_host::sandbox_state::transition::Noop; +use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; fn main() -> hyperlight_host::Result<()> { // Create an uninitialized sandbox with a guest binary let mut uninitialized_sandbox = UninitializedSandbox::new( - hyperlight_host::GuestBinary::FilePath(hyperlight_testing::simple_guest_as_string().unwrap()), + hyperlight_host::GuestBinary::FilePath("path/to/your/guest/binary".to_string()), None // default configuration )?; @@ -59,12 +60,10 @@ fn main() -> hyperlight_host::Result<()> { let message = "Hello, World! I am executing inside of a VM :)\n".to_string(); // in order to call a function it first must be defined in the guest and exposed so that // the host can call it - let result: i32 = multi_use_sandbox.call_guest_function_by_name( + multi_use_sandbox.call_guest_function_by_name::( "PrintOutput", message, - ); - - assert!(result.is_ok()); + )?; Ok(()) } @@ -84,22 +83,21 @@ use hyperlight_common::flatbuffer_wrappers::function_types::{ ParameterType, ParameterValue, ReturnType, }; use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; -use hyperlight_common::flatbuffer_wrappers::util::get_flatbuffer_result_from_int; +use hyperlight_common::flatbuffer_wrappers::util::get_flatbuffer_result; use hyperlight_guest::error::{HyperlightGuestError, Result}; use hyperlight_guest_bin::guest_function::definition::GuestFunctionDefinition; use hyperlight_guest_bin::guest_function::register::register_function; -use hyperlight_guest_bin::host_comm::{call_host_function, call_host_function_without_returning_result}; +use hyperlight_guest_bin::host_comm::call_host_function; fn print_output(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = function_call.parameters.clone().unwrap()[0].clone() { - call_host_function( + let result = call_host_function::( "HostPrint", Some(Vec::from(&[ParameterValue::String(message.to_string())])), ReturnType::Int, )?; - let result = get_host_value_return_as_int()?; - Ok(get_flatbuffer_result_from_int(result)) + Ok(get_flatbuffer_result(result)) } else { Err(HyperlightGuestError::new( ErrorCode::GuestFunctionParameterTypeMismatch, @@ -114,7 +112,7 @@ pub extern "C" fn hyperlight_main() { "PrintOutput".to_string(), Vec::from(&[ParameterType::String]), ReturnType::Int, - print_output as i64, + print_output as usize, ); register_function(print_output_def); } @@ -129,6 +127,28 @@ pub fn guest_dispatch_function(function_call: FunctionCall) -> Result> { } ``` +**Note**: Guest applications require a specific build configuration. Create a `.cargo/config.toml` file in your guest project with the following content: + +```toml +[build] +target = "x86_64-unknown-none" + +[target.x86_64-unknown-none] +rustflags = [ + "-C", + "code-model=small", + "-C", + "link-args=-e entrypoint", +] +linker = "rust-lld" + +[profile.release] +panic = "abort" + +[profile.dev] +panic = "abort" +``` + For additional examples of using the Hyperlight host Rust library, see the [./src/hyperlight_host/examples](./src/hyperlight_host/examples) directory. From 0db85b170d7e037714fa40c4371f4cb10618ad11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Jul 2025 04:23:24 +0000 Subject: [PATCH 010/271] Bump windows-sys from 0.59.0 to 0.60.2 (#692) Bumps [windows-sys](https://github.com/microsoft/windows-rs) from 0.59.0 to 0.60.2. - [Release notes](https://github.com/microsoft/windows-rs/releases) - [Commits](https://github.com/microsoft/windows-rs/commits) --- updated-dependencies: - dependency-name: windows-sys dependency-version: 0.60.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 123 ++++++++++++++++++++++++++------- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 99 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe90a7993..0a14268c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,7 +153,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -553,7 +553,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -629,7 +629,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1130,7 +1130,7 @@ dependencies = [ "vmm-sys-util", "windows 0.61.3", "windows-result 0.3.4", - "windows-sys 0.59.0", + "windows-sys 0.60.2", "windows-version", ] @@ -1506,7 +1506,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1951,7 +1951,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -2132,7 +2132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.14.0", "proc-macro2", "quote", "syn", @@ -2425,7 +2425,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -2760,7 +2760,7 @@ dependencies = [ "getrandom 0.3.2", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -3129,7 +3129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69fff37da548239c3bf9e64a12193d261e8b22b660991c6fd2df057c168f435f" dependencies = [ "cc", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3394,7 +3394,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -3410,7 +3410,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ "windows-core 0.58.0", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3445,7 +3445,7 @@ dependencies = [ "windows-interface 0.58.0", "windows-result 0.2.0", "windows-strings 0.1.0", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3538,7 +3538,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3557,7 +3557,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ "windows-result 0.2.0", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3575,7 +3575,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3584,7 +3584,16 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", ] [[package]] @@ -3593,14 +3602,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -3627,48 +3652,96 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.7.6" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 98fbf289a..0148342a3 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -60,7 +60,7 @@ windows = { version = "0.61", features = [ "Win32_System_JobObjects", "Win32_System_SystemServices", ] } -windows-sys = { version = "0.59", features = ["Win32"] } +windows-sys = { version = "0.60", features = ["Win32"] } windows-result = "0.3" rust-embed = { version = "8.7.2", features = ["debug-embed", "include-exclude", "interpolate-folder-path"] } sha256 = "1.6.0" From f2728cf1122ec8bd91c584d8f799c1f6119962b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 04:33:53 +0000 Subject: [PATCH 011/271] Bump cc from 1.2.27 to 1.2.29 (#693) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.27 to 1.2.29. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.27...cc-v1.2.29) --- updated-dependencies: - dependency-name: cc dependency-version: 1.2.29 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a14268c7..3314e0d5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -292,9 +292,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.27" +version = "1.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" dependencies = [ "jobserver", "libc", @@ -629,7 +629,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2425,7 +2425,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2760,7 +2760,7 @@ dependencies = [ "getrandom 0.3.2", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3394,7 +3394,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] From fc89be982f409d7373b106aef5ff509bd7814107 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 04:34:07 +0000 Subject: [PATCH 012/271] Bump tokio from 1.46.0 to 1.46.1 (#694) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.46.0 to 1.46.1. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.46.0...tokio-1.46.1) --- updated-dependencies: - dependency-name: tokio dependency-version: 1.46.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3314e0d5a..96c71c3ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2844,9 +2844,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.46.0" +version = "1.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1140bb80481756a8cbe10541f37433b459c5aa1e727b4c020fbfebdc25bf3ec4" +checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" dependencies = [ "backtrace", "bytes", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 0148342a3..bc744c05c 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -95,7 +95,7 @@ opentelemetry = "0.30.0" opentelemetry-otlp = { version = "0.30.0", default-features = false, features = ["http-proto", "reqwest-blocking-client"] } opentelemetry-semantic-conventions = "0.30" opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio"] } -tokio = { version = "1.46.0", features = ["full"] } +tokio = { version = "1.46.1", features = ["full"] } criterion = "0.6.0" tracing-chrome = "0.7.2" metrics-util = "0.20.0" From 21077d671fa2b152d06d76cda7ccc46fb6ef7da5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 18:12:50 +0000 Subject: [PATCH 013/271] Bump libfuzzer-sys from 0.4.9 to 0.4.10 (#691) Bumps [libfuzzer-sys](https://github.com/rust-fuzz/libfuzzer) from 0.4.9 to 0.4.10. - [Changelog](https://github.com/rust-fuzz/libfuzzer/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-fuzz/libfuzzer/compare/0.4.9...0.4.10) --- updated-dependencies: - dependency-name: libfuzzer-sys dependency-version: 0.4.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96c71c3ee..449f9b17e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1479,9 +1479,9 @@ checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libfuzzer-sys" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" dependencies = [ "arbitrary", "cc", From 30b24de2d2fc2c5e7d60f06e42aa94af5fbbe0bd Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Tue, 8 Jul 2025 09:15:32 +0000 Subject: [PATCH 014/271] [hyperlight_host] mshv: dump core on unknown HV message Usually, an unknown HV message is the result of a double fault or similar: something going wrong in the guest. This commit ensures that a core file is generated when this happens and the crashdump feature is enabled. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> [hyperlight_host] Expose MemoryRegion structure It is a convenient tuple of information to use when mapping a new region into the sandbox. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- src/hyperlight_host/src/hypervisor/hyperv_linux.rs | 2 ++ src/hyperlight_host/src/mem/memory_region.rs | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index db5037106..48e589361 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -775,6 +775,8 @@ impl Hypervisor for HypervLinuxDriver { } other => { crate::debug!("mshv Other Exit: Exit: {:#?} \n {:#?}", other, &self); + #[cfg(crashdump)] + let _ = crashdump::generate_crashdump(self); log_then_return!("unknown Hyper-V run message type {:?}", other); } }, diff --git a/src/hyperlight_host/src/mem/memory_region.rs b/src/hyperlight_host/src/mem/memory_region.rs index a7e22255b..c24ac197c 100644 --- a/src/hyperlight_host/src/mem/memory_region.rs +++ b/src/hyperlight_host/src/mem/memory_region.rs @@ -182,13 +182,13 @@ pub enum MemoryRegionType { #[derive(Debug, Clone, PartialEq, Eq)] pub struct MemoryRegion { /// the range of guest memory addresses - pub(crate) guest_region: Range, + pub guest_region: Range, /// the range of host memory addresses - pub(crate) host_region: Range, + pub host_region: Range, /// memory access flags for the given region - pub(crate) flags: MemoryRegionFlags, + pub flags: MemoryRegionFlags, /// the type of memory region - pub(crate) region_type: MemoryRegionType, + pub region_type: MemoryRegionType, } pub(crate) struct MemoryRegionVecBuilder { From 0d65b8707c38e2873bde18f0f0d4a25b235417e3 Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Tue, 8 Jul 2025 01:10:35 +0000 Subject: [PATCH 015/271] [hyperlight_host] Allow mapping a host memory region into a guest Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- src/hyperlight_host/src/func/call_ctx.rs | 25 ++++++ .../src/hypervisor/hyperv_linux.rs | 35 ++++++++ .../src/hypervisor/hyperv_windows.rs | 19 +++- src/hyperlight_host/src/hypervisor/kvm.rs | 15 ++++ src/hyperlight_host/src/hypervisor/mod.rs | 9 ++ src/hyperlight_host/src/mem/mgr.rs | 19 +++- .../src/mem/shared_mem_snapshot.rs | 16 ++-- .../src/sandbox/initialized_multi_use.rs | 87 ++++++++++++++++++- 8 files changed, 211 insertions(+), 14 deletions(-) diff --git a/src/hyperlight_host/src/func/call_ctx.rs b/src/hyperlight_host/src/func/call_ctx.rs index 180731910..168437b97 100644 --- a/src/hyperlight_host/src/func/call_ctx.rs +++ b/src/hyperlight_host/src/func/call_ctx.rs @@ -17,6 +17,7 @@ limitations under the License. use tracing::{Span, instrument}; use super::{ParameterTuple, SupportedReturnType}; +use crate::mem::memory_region::MemoryRegion; use crate::sandbox::Callable; use crate::{MultiUseSandbox, Result}; /// A context for calling guest functions. @@ -70,6 +71,30 @@ impl MultiUseGuestCallContext { pub(crate) fn finish_no_reset(self) -> MultiUseSandbox { self.sbox } + + /// Map a region of host memory into the sandbox. + /// + /// Depending on the host platform, there are likely alignment + /// requirements of at least one page for base and len. + /// + /// `rgn.region_type` is ignored, since guest PTEs are not created + /// for the new memory. + /// + /// # Safety + /// It is the caller's responsibility to ensure that the host side + /// of the region remains intact and is not written to until this + /// mapping is removed, either due to the destruction of the + /// sandbox or due to a state rollback + pub unsafe fn map_region(&mut self, rgn: &MemoryRegion) -> Result<()> { + unsafe { self.sbox.map_region(rgn) } + } + + /// Map the contents of a file into the guest at a particular address + /// + /// Returns the length of the mapping + pub fn map_file_cow(&mut self, fp: &std::path::Path, guest_base: u64) -> Result { + self.sbox.map_file_cow(fp, guest_base) + } } impl Callable for MultiUseGuestCallContext { diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 48e589361..90e91f496 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -297,6 +297,7 @@ pub(crate) fn is_hypervisor_present() -> bool { /// called the Microsoft Hypervisor (MSHV) pub(crate) struct HypervLinuxDriver { _mshv: Mshv, + page_size: usize, vm_fd: VmFd, vcpu_fd: VcpuFd, entrypoint: u64, @@ -424,6 +425,7 @@ impl HypervLinuxDriver { #[allow(unused_mut)] let mut hv = Self { _mshv: mshv, + page_size: 0, vm_fd, vcpu_fd, mem_regions, @@ -525,6 +527,8 @@ impl Hypervisor for HypervLinuxDriver { max_guest_log_level: Option, #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, ) -> Result<()> { + self.page_size = page_size as usize; + let max_guest_log_level: u64 = match max_guest_log_level { Some(level) => level as u64, None => self.get_max_log_level().into(), @@ -556,6 +560,37 @@ impl Hypervisor for HypervLinuxDriver { Ok(()) } + #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] + unsafe fn map_region(&mut self, rgn: &MemoryRegion) -> Result<()> { + if [ + rgn.guest_region.start, + rgn.guest_region.end, + rgn.host_region.start, + rgn.host_region.end, + ] + .iter() + .any(|x| x % self.page_size != 0) + { + log_then_return!("region is not page-aligned"); + } + let mshv_region: mshv_user_mem_region = rgn.to_owned().into(); + self.vm_fd.map_user_memory(mshv_region)?; + self.mem_regions.push(rgn.to_owned()); + Ok(()) + } + + #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] + unsafe fn unmap_regions(&mut self, n: u64) -> Result<()> { + for rgn in self + .mem_regions + .split_off(self.mem_regions.len() - n as usize) + { + let mshv_region: mshv_user_mem_region = rgn.to_owned().into(); + self.vm_fd.unmap_user_memory(mshv_region)?; + } + Ok(()) + } + #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] fn dispatch_call_from_host( &mut self, diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index 288b5bf5b..cd0398854 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -36,8 +36,8 @@ use { DebugCommChannel, DebugMsg, DebugResponse, GuestDebug, HypervDebug, VcpuStopReason, }, super::handlers::DbgMemAccessHandlerWrapper, + crate::HyperlightError, crate::hypervisor::handlers::DbgMemAccessHandlerCaller, - crate::{HyperlightError, log_then_return}, std::sync::Mutex, }; @@ -59,7 +59,7 @@ use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::{GuestPtr, RawPtr}; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; -use crate::{Result, debug, new_error}; +use crate::{Result, debug, log_then_return, new_error}; #[cfg(gdb)] mod debug { @@ -606,6 +606,21 @@ impl Hypervisor for HypervWindowsDriver { Ok(()) } + #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] + unsafe fn map_region(&mut self, _rgn: &MemoryRegion) -> Result<()> { + log_then_return!("Mapping host memory into the guest not yet supported on this platform"); + } + + #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] + unsafe fn unmap_regions(&mut self, n: u64) -> Result<()> { + if n > 0 { + log_then_return!( + "Mapping host memory into the guest not yet supported on this platform" + ); + } + Ok(()) + } + #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] fn dispatch_call_from_host( &mut self, diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index d85a6a838..3da9786cd 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -493,6 +493,21 @@ impl Hypervisor for KVMDriver { Ok(()) } + #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] + unsafe fn map_region(&mut self, _rgn: &MemoryRegion) -> Result<()> { + log_then_return!("Mapping host memory into the guest not yet supported on this platform"); + } + + #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] + unsafe fn unmap_regions(&mut self, n: u64) -> Result<()> { + if n > 0 { + log_then_return!( + "Mapping host memory into the guest not yet supported on this platform" + ); + } + Ok(()) + } + #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] fn dispatch_call_from_host( &mut self, diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index 0a31ee468..ecf6acbc5 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -132,6 +132,15 @@ pub(crate) trait Hypervisor: Debug + Sync + Send { #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, ) -> Result<()>; + /// Map a region of host memory into the sandbox. + /// + /// Depending on the host platform, there are likely alignment + /// requirements of at least one page for base and len. + unsafe fn map_region(&mut self, rgn: &MemoryRegion) -> Result<()>; + + /// Unmap the most recent `n` regions mapped by `map_region` + unsafe fn unmap_regions(&mut self, n: u64) -> Result<()>; + /// Dispatch a call from the host to the guest using the given pointer /// to the dispatch function _in the guest's address space_. /// diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 7910d9dc2..90cb76573 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -73,6 +73,8 @@ pub(crate) struct SandboxMemoryManager { pub(crate) load_addr: RawPtr, /// Offset for the execution entrypoint from `load_addr` pub(crate) entrypoint_offset: Offset, + /// How many memory regions were mapped after sandbox creation + pub(crate) mapped_rgns: u64, /// A vector of memory snapshots that can be used to save and restore the state of the memory /// This is used by the Rust Sandbox implementation (rather than the mem_snapshot field above which only exists to support current C API) snapshots: Arc>>, @@ -95,6 +97,7 @@ where shared_mem, load_addr, entrypoint_offset, + mapped_rgns: 0, snapshots: Arc::new(Mutex::new(Vec::new())), } } @@ -265,7 +268,7 @@ where /// this function will create a memory snapshot and push it onto the stack of snapshots /// It should be used when you want to save the state of the memory, for example, when evolving a sandbox to a new state pub(crate) fn push_state(&mut self) -> Result<()> { - let snapshot = SharedMemorySnapshot::new(&mut self.shared_mem)?; + let snapshot = SharedMemorySnapshot::new(&mut self.shared_mem, self.mapped_rgns)?; self.snapshots .try_lock() .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? @@ -277,7 +280,11 @@ where /// off the stack /// It should be used when you want to restore the state of the memory to a previous state but still want to /// retain that state, for example after calling a function in the guest - pub(crate) fn restore_state_from_last_snapshot(&mut self) -> Result<()> { + /// + /// Returns the number of memory regions mapped into the sandbox + /// that need to be unmapped in order for the restore to be + /// completed. + pub(crate) fn restore_state_from_last_snapshot(&mut self) -> Result { let mut snapshots = self .snapshots .try_lock() @@ -288,13 +295,15 @@ where } #[allow(clippy::unwrap_used)] // We know that last is not None because we checked it above let snapshot = last.unwrap(); - snapshot.restore_from_snapshot(&mut self.shared_mem) + let old_rgns = self.mapped_rgns; + self.mapped_rgns = snapshot.restore_from_snapshot(&mut self.shared_mem)?; + Ok(old_rgns - self.mapped_rgns) } /// this function pops the last snapshot off the stack and restores the memory to the previous state /// It should be used when you want to restore the state of the memory to a previous state and do not need to retain that state /// for example when devolving a sandbox to a previous state. - pub(crate) fn pop_and_restore_state_from_snapshot(&mut self) -> Result<()> { + pub(crate) fn pop_and_restore_state_from_snapshot(&mut self) -> Result { let last = self .snapshots .try_lock() @@ -430,6 +439,7 @@ impl SandboxMemoryManager { layout: self.layout, load_addr: self.load_addr.clone(), entrypoint_offset: self.entrypoint_offset, + mapped_rgns: 0, snapshots: Arc::new(Mutex::new(Vec::new())), }, SandboxMemoryManager { @@ -437,6 +447,7 @@ impl SandboxMemoryManager { layout: self.layout, load_addr: self.load_addr.clone(), entrypoint_offset: self.entrypoint_offset, + mapped_rgns: 0, snapshots: Arc::new(Mutex::new(Vec::new())), }, ) diff --git a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs index d5cf565de..ac2bdc6b5 100644 --- a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs +++ b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs @@ -24,16 +24,21 @@ use crate::Result; #[derive(Clone)] pub(super) struct SharedMemorySnapshot { snapshot: Vec, + /// How many non-main-RAM regions were mapped when this snapshot was taken? + mapped_rgns: u64, } impl SharedMemorySnapshot { /// Take a snapshot of the memory in `shared_mem`, then create a new /// instance of `Self` with the snapshot stored therein. #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - pub(super) fn new(shared_mem: &mut S) -> Result { + pub(super) fn new(shared_mem: &mut S, mapped_rgns: u64) -> Result { // TODO: Track dirty pages instead of copying entire memory let snapshot = shared_mem.with_exclusivity(|e| e.copy_all_to_vec())??; - Ok(Self { snapshot }) + Ok(Self { + snapshot, + mapped_rgns, + }) } /// Take another snapshot of the internally-stored `SharedMemory`, @@ -51,8 +56,9 @@ impl SharedMemorySnapshot { pub(super) fn restore_from_snapshot( &mut self, shared_mem: &mut S, - ) -> Result<()> { - shared_mem.with_exclusivity(|e| e.copy_from_slice(self.snapshot.as_slice(), 0))? + ) -> Result { + shared_mem.with_exclusivity(|e| e.copy_from_slice(self.snapshot.as_slice(), 0))??; + Ok(self.mapped_rgns) } } @@ -69,7 +75,7 @@ mod tests { let data2 = data1.iter().map(|b| b + 1).collect::>(); let mut gm = ExclusiveSharedMemory::new(PAGE_SIZE_USIZE).unwrap(); gm.copy_from_slice(data1.as_slice(), 0).unwrap(); - let mut snap = super::SharedMemorySnapshot::new(&mut gm).unwrap(); + let mut snap = super::SharedMemorySnapshot::new(&mut gm, 0).unwrap(); { // after the first snapshot is taken, make sure gm has the equivalent // of data1 diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 8d1e27918..8df9d08ef 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -14,6 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ +#[cfg(unix)] +use std::os::fd::AsRawFd; +#[cfg(unix)] +use std::os::linux::fs::MetadataExt; +use std::path::Path; use std::sync::{Arc, Mutex}; use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType}; @@ -31,12 +36,15 @@ use crate::func::{ParameterTuple, SupportedReturnType}; use crate::hypervisor::handlers::DbgMemAccessHandlerWrapper; use crate::hypervisor::handlers::{MemAccessHandlerCaller, OutBHandlerCaller}; use crate::hypervisor::{Hypervisor, InterruptHandle}; +#[cfg(unix)] +use crate::mem::memory_region::MemoryRegionType; +use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::RawPtr; use crate::mem::shared_mem::HostSharedMemory; use crate::metrics::maybe_time_and_emit_guest_call; use crate::sandbox_state::sandbox::{DevolvableSandbox, EvolvableSandbox, Sandbox}; use crate::sandbox_state::transition::{MultiUseContextCallback, Noop}; -use crate::{HyperlightError, Result}; +use crate::{HyperlightError, Result, log_then_return}; /// A sandbox that supports being used Multiple times. /// The implication of being used multiple times is two-fold: @@ -173,6 +181,75 @@ impl MultiUseSandbox { }) } + /// Map a region of host memory into the sandbox. + /// + /// Depending on the host platform, there are likely alignment + /// requirements of at least one page for base and len. + /// + /// `rgn.region_type` is ignored, since guest PTEs are not created + /// for the new memory. + /// + /// It is the caller's responsibility to ensure that the host side + /// of the region remains intact and is not written to until this + /// mapping is removed, either due to the destruction of the + /// sandbox or due to a state rollback + #[instrument(err(Debug), skip(self, rgn), parent = Span::current())] + pub unsafe fn map_region(&mut self, rgn: &MemoryRegion) -> Result<()> { + if rgn.flags.contains(MemoryRegionFlags::STACK_GUARD) { + // Stack guard pages are an internal implementation detail + // (which really should be moved into the guest) + log_then_return!("Cannot map host memory as a stack guard page"); + } + if rgn.flags.contains(MemoryRegionFlags::WRITE) { + // TODO: Implement support for writable mappings, which + // need to be registered with the memory manager so that + // writes can be rolled back when necessary. + log_then_return!("TODO: Writable mappings not yet supported"); + } + unsafe { self.vm.map_region(rgn) }?; + self.mem_mgr.unwrap_mgr_mut().mapped_rgns += 1; + Ok(()) + } + + /// Map the contents of a file into the guest at a particular address + /// + /// Returns the length of the mapping + #[instrument(err(Debug), skip(self, _fp, _guest_base), parent = Span::current())] + pub(crate) fn map_file_cow(&mut self, _fp: &Path, _guest_base: u64) -> Result { + #[cfg(windows)] + log_then_return!("mmap'ing a file into the guest is not yet supported on Windows"); + #[cfg(unix)] + unsafe { + let file = std::fs::File::options().read(true).write(true).open(_fp)?; + let file_size = file.metadata()?.st_size(); + let page_size = page_size::get(); + let size = (file_size as usize).div_ceil(page_size) * page_size; + let base = libc::mmap( + std::ptr::null_mut(), + size, + libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC, + libc::MAP_PRIVATE, + file.as_raw_fd(), + 0, + ); + if base == libc::MAP_FAILED { + log_then_return!("mmap error: {:?}", std::io::Error::last_os_error()); + } + + if let Err(err) = self.map_region(&MemoryRegion { + host_region: base as usize..base.wrapping_add(size) as usize, + guest_region: _guest_base as usize.._guest_base as usize + size, + flags: MemoryRegionFlags::READ | MemoryRegionFlags::EXECUTE, + region_type: MemoryRegionType::Heap, + }) { + libc::munmap(base, size); + return Err(err); + }; + + Ok(size as u64) + } + } + /// This function is kept here for fuzz testing the parameter and return types #[cfg(feature = "fuzzing")] #[instrument(err(Debug), skip(self, args), parent = Span::current())] @@ -193,7 +270,9 @@ impl MultiUseSandbox { #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] pub(crate) fn restore_state(&mut self) -> Result<()> { let mem_mgr = self.mem_mgr.unwrap_mgr_mut(); - mem_mgr.restore_state_from_last_snapshot() + let rgns_to_unmap = mem_mgr.restore_state_from_last_snapshot()?; + unsafe { self.vm.unmap_regions(rgns_to_unmap)? }; + Ok(()) } pub(crate) fn call_guest_function_by_name_no_reset( @@ -275,9 +354,11 @@ impl DevolvableSandbox) -> Result { - self.mem_mgr + let rgns_to_unmap = self + .mem_mgr .unwrap_mgr_mut() .pop_and_restore_state_from_snapshot()?; + unsafe { self.vm.unmap_regions(rgns_to_unmap)? }; Ok(self) } } From 63ba9a3672734c053890eeae06da67b7e69df86c Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Tue, 8 Jul 2025 01:12:31 +0000 Subject: [PATCH 016/271] [hyperlight_guest] Add basic page table modification functions Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- .../src/guest_function/call.rs | 11 + src/hyperlight_guest_bin/src/lib.rs | 1 + src/hyperlight_guest_bin/src/paging.rs | 252 ++++++++++++++++++ 3 files changed, 264 insertions(+) create mode 100644 src/hyperlight_guest_bin/src/paging.rs diff --git a/src/hyperlight_guest_bin/src/guest_function/call.rs b/src/hyperlight_guest_bin/src/guest_function/call.rs index bdaed4212..d829e2a85 100644 --- a/src/hyperlight_guest_bin/src/guest_function/call.rs +++ b/src/hyperlight_guest_bin/src/guest_function/call.rs @@ -100,6 +100,17 @@ fn internal_dispatch_function() -> Result<()> { // which if it were included in the internal_dispatch_function cause the epilogue to not be called because the halt() would not return // when running in the hypervisor. pub(crate) extern "C" fn dispatch_function() { + // The hyperlight host likes to use one partition and reset it in + // various ways; if that has happened, there might stale TLB + // entries hanging around from the former user of the + // partition. Flushing the TLB here is not quite the right thing + // to do, since incorrectly cached entries could make even this + // code not exist, but regrettably there is not a simple way for + // the host to trigger flushing when it ought to happen, so for + // now this works in practice, since the text segment is always + // part of the big identity-mapped region at the base of the + // guest. + crate::paging::flush_tlb(); let _ = internal_dispatch_function(); halt(); } diff --git a/src/hyperlight_guest_bin/src/lib.rs b/src/hyperlight_guest_bin/src/lib.rs index 473bfbfc1..c3d44f4f5 100644 --- a/src/hyperlight_guest_bin/src/lib.rs +++ b/src/hyperlight_guest_bin/src/lib.rs @@ -52,6 +52,7 @@ pub mod guest_function { pub mod guest_logger; pub mod host_comm; pub mod memory; +pub mod paging; // === Globals === #[global_allocator] diff --git a/src/hyperlight_guest_bin/src/paging.rs b/src/hyperlight_guest_bin/src/paging.rs new file mode 100644 index 000000000..3d824e680 --- /dev/null +++ b/src/hyperlight_guest_bin/src/paging.rs @@ -0,0 +1,252 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +use alloc::alloc::Layout; +use core::arch::asm; + +use crate::OS_PAGE_SIZE; + +/// Convert a physical address in main memory to a virtual address +/// through the pysmap +/// +/// This is _not guaranteed_ to work with device memory +pub fn ptov(x: u64) -> *mut u8 { + // Currently, all of main memory is identity mapped + x as *mut u8 +} + +// TODO: This is not at all thread-safe atm +// TODO: A lot of code in this file uses inline assembly to load and +// store page table entries. It would be nice to use pointer +// volatile read/writes instead, but unfortunately we have a PTE +// at physical address 0, which is currently identity-mapped at +// virtual address 0, and Rust raw pointer operations can't be +// used to read/write from address 0. + +/// A helper structure indicating a mapping operation that needs to be +/// performed +struct MapRequest { + table_base: u64, + vmin: *mut u8, + len: u64, +} + +/// A helper structure indicating that a particular PTE needs to be +/// modified +struct MapResponse { + entry_ptr: *mut u64, + vmin: *mut u8, + len: u64, +} + +/// Assumption: all are page-aligned +pub unsafe fn map_region(phys_base: u64, virt_base: *mut u8, len: u64) { + let mut pml4_base: u64 = 0; + unsafe { + asm!("mov {}, cr3", out(reg) pml4_base); + } + pml4_base &= !0xfff; + modify_ptes::<47, 39>(MapRequest { + table_base: pml4_base, + vmin: virt_base, + len, + }) + .map(|r| unsafe { alloc_pte_if_needed(r) }) + .flat_map(modify_ptes::<38, 30>) + .map(|r| unsafe { alloc_pte_if_needed(r) }) + .flat_map(modify_ptes::<29, 21>) + .map(|r| unsafe { alloc_pte_if_needed(r) }) + .flat_map(modify_ptes::<20, 12>) + .map(|r| map_normal(phys_base, virt_base, r)) + .collect::<()>(); +} + +#[allow(unused)] +/// This function is not presently used for anything, but is useful +/// for debugging +pub unsafe fn dbg_print_address_pte(address: u64) -> u64 { + let mut pml4_base: u64 = 0; + unsafe { + asm!("mov {}, cr3", out(reg) pml4_base); + } + pml4_base &= !0xfff; + let addrs = modify_ptes::<47, 39>(MapRequest { + table_base: pml4_base, + vmin: address as *mut u8, + len: unsafe { OS_PAGE_SIZE as u64 }, + }) + .map(|r| unsafe { require_pte_exist(r) }) + .flat_map(modify_ptes::<38, 30>) + .map(|r| unsafe { require_pte_exist(r) }) + .flat_map(modify_ptes::<29, 21>) + .map(|r| unsafe { require_pte_exist(r) }) + .flat_map(modify_ptes::<20, 12>) + .map(|r| { + let mut pte: u64 = 0; + unsafe { + asm!("mov {}, qword ptr [{}]", out(reg) pte, in(reg) r.entry_ptr); + } + pte + }) + .collect::>(); + if addrs.len() != 1 { + panic!("impossible: 1 page map request resolved to multiple PTEs"); + } + return addrs[0]; +} + +/// Allocate n contiguous physical pages and return the physical +/// addresses of the pages in question. +pub unsafe fn alloc_phys_pages(n: u64) -> u64 { + // Currently, since all of main memory is idmap'd, we can just + // allocate any appropriately aligned section of memory. + unsafe { + let v = alloc::alloc::alloc_zeroed( + Layout::from_size_align(n as usize * OS_PAGE_SIZE as usize, OS_PAGE_SIZE as usize) + .expect("could not create physical page allocation layout"), + ); + if v.is_null() { + panic!("could not allocate a physical page"); + } + v as u64 + } +} + +pub unsafe fn require_pte_exist(x: MapResponse) -> MapRequest { + let mut pte: u64 = 0; + unsafe { + asm!("mov {}, qword ptr [{}]", out(reg) pte, in(reg) x.entry_ptr); + } + let present = pte & 0x1; + if present == 0 { + panic!("debugging: found not-present pte"); + } + MapRequest { + table_base: pte & !0xfff, + vmin: x.vmin, + len: x.len, + } +} + +/// Page-mapping callback to allocate a next-level page table if necessary +pub unsafe fn alloc_pte_if_needed(x: MapResponse) -> MapRequest { + let mut pte: u64 = 0; + unsafe { + asm!("mov {}, qword ptr [{}]", out(reg) pte, in(reg) x.entry_ptr); + } + let present = pte & 0x1; + if present != 0 { + return MapRequest { + table_base: pte & !0xfff, + vmin: x.vmin, + len: x.len, + }; + } + let page_addr = unsafe { alloc_phys_pages(1) }; + unsafe { ptov(page_addr).write_bytes(0u8, OS_PAGE_SIZE as usize) }; + let pte = page_addr | + 1 << 5 | // A - we don't track accesses at table level + 0 << 4 | // PCD - leave caching enabled + 0 << 3 | // PWT - write-back + 1 << 2 | // U/S - allow user access to everything (for now) + 1 << 1 | // R/W - we don't use block-level permissions + 1 << 0; // P - this entry is present + unsafe { + asm!("mov qword ptr [{}], {}", in(reg) x.entry_ptr, in(reg) pte); + } + MapRequest { + table_base: page_addr, + vmin: x.vmin, + len: x.len, + } +} + +/// Map a normal memory page +/// +/// TODO: support permissions; currently mapping is always RWX +fn map_normal(phys_base: u64, virt_base: *mut u8, r: MapResponse) { + let pte = (phys_base + (r.vmin as u64 - virt_base as u64)) | + 1 << 6 | // D - we don't presently track dirty state for anything + 1 << 5 | // A - we don't presently track access for anything + 0 << 4 | // PCD - leave caching enabled + 0 << 3 | // PWT - write-back + 1 << 2 | // U/S - allow user access to everything (for now) + 1 << 1 | // R/W - for now make everything r/w + 1 << 0; // P - this entry is present + unsafe { + r.entry_ptr.write_volatile(pte); + } +} + +#[inline(always)] +/// Utility function to extract an (inclusive on both ends) bit range +/// from a quadword. +fn bits(x: u64) -> u64 { + (x & ((1 << (high_bit + 1)) - 1)) >> low_bit +} + +struct ModifyPteIterator { + request: MapRequest, + n: u64, +} +impl Iterator for ModifyPteIterator { + type Item = MapResponse; + fn next(&mut self) -> Option { + if (self.n << low_bit) >= self.request.len { + return None; + } + // next stage parameters + let next_vmin = self.request.vmin.wrapping_add((self.n << low_bit) as usize); + let entry_ptr = ptov(self.request.table_base) + .wrapping_add((bits::(next_vmin as u64) << 3) as usize) + as *mut u64; + let len_from_here = self.request.len - (self.n << low_bit); + let next_len = core::cmp::min(len_from_here, 1 << low_bit); + + // update our state + self.n += 1; + + Some(MapResponse { + entry_ptr, + vmin: next_vmin, + len: next_len, + }) + } +} +fn modify_ptes( + r: MapRequest, +) -> ModifyPteIterator { + ModifyPteIterator { request: r, n: 0 } +} + +pub fn flush_tlb() { + // Currently this just always flips CR4.PGE back and forth to + // trigger a tlb flush. We should use a faster approach where + // available + let mut orig_cr4: u64 = 0; + unsafe { + asm!("mov {}, cr4", out(reg) orig_cr4); + } + let tmp_cr4: u64 = orig_cr4 ^ (1 << 7); // CR4.PGE + unsafe { + asm!( + "mov cr4, {}", + "mov cr4, {}", + in(reg) tmp_cr4, + in(reg) orig_cr4 + ); + } +} From 6295bec1cca5f5736f0ff24779a9296ede9a91ba Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Mon, 7 Jul 2025 22:15:48 +0000 Subject: [PATCH 017/271] [hyperlight_guest_bin] Disable red zones when compiling C Because we don't presently switch stacks on interrupt entry, we cannot support a red zone in the ABI. rustc's x86_64-unknown-none target already does not use a redzone, but clang's x86_64-unknown-none-linux target, which we use for compiling C code, does use a red zone by default. This commit modifies the clang options that we use to remove uses of a red zone from generated code. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- src/hyperlight_guest_bin/build.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/hyperlight_guest_bin/build.rs b/src/hyperlight_guest_bin/build.rs index 35a39b469..dd8d76079 100644 --- a/src/hyperlight_guest_bin/build.rs +++ b/src/hyperlight_guest_bin/build.rs @@ -88,6 +88,10 @@ fn cargo_main() { // targets will eventually show up. cfg.flag("--target=x86_64-unknown-linux-none"); + // We don't use a different stack for all interrupts, so there + // can be no red zone + cfg.flag("-mno-red-zone"); + // We don't support stack protectors at the moment, but Arch Linux clang // auto-enables them for -linux platforms, so explicitly disable them. cfg.flag("-fno-stack-protector"); @@ -245,6 +249,7 @@ fn main() -> std::process::ExitCode { "-fno-stack-protector", "-fstack-clash-protection", "-mstack-probe-size=4096", + "-mno-red-zone", ]) .arg("-nostdinc") .arg("-isystem") From b46da1222eaccc1cc359cd4cf55c9537cc59be09 Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Tue, 8 Jul 2025 00:47:06 +0000 Subject: [PATCH 018/271] [hyperlight_guest_bin] Pop error code on context restore Previously, we did remove the error code from the stack before `iret`'ing, which resulted in the return failing. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- src/hyperlight_guest_bin/src/exceptions/interrupt_entry.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hyperlight_guest_bin/src/exceptions/interrupt_entry.rs b/src/hyperlight_guest_bin/src/exceptions/interrupt_entry.rs index 0a0d63775..f29aaa1e8 100644 --- a/src/hyperlight_guest_bin/src/exceptions/interrupt_entry.rs +++ b/src/hyperlight_guest_bin/src/exceptions/interrupt_entry.rs @@ -123,7 +123,8 @@ macro_rules! generate_exceptions { " mov rdi, rsp\n", " call {hl_exception_handler}\n", context_restore!(), - " iretq\n", // iretq is used to return from exception in x86_64 + " add rsp, 8\n", // error code + " iretq\n", // iretq is used to return from exception in x86_64 generate_excp!(0, pusherrcode), generate_excp!(1, pusherrcode), generate_excp!(2, pusherrcode), From f17f3a46742b21c57f1cf15eb9ecebac1bebd5dc Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Tue, 8 Jul 2025 00:49:16 +0000 Subject: [PATCH 019/271] [hyperlight_guest_bin] Save/restore x87 & SSE regs on context switch We unfortunately don't have a good way of making sure that code run in exception contexts doesn't use floating point and SSE instructions. This commit simply always saves and restores the relevant registers as a workaround. We should at some point look into the alternative of ensuring that simd instructions aren't used in code reachable from an exception handler, and see if that actually improves performance. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- .../src/exceptions/interrupt_entry.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/hyperlight_guest_bin/src/exceptions/interrupt_entry.rs b/src/hyperlight_guest_bin/src/exceptions/interrupt_entry.rs index f29aaa1e8..bbfdd96fa 100644 --- a/src/hyperlight_guest_bin/src/exceptions/interrupt_entry.rs +++ b/src/hyperlight_guest_bin/src/exceptions/interrupt_entry.rs @@ -67,9 +67,19 @@ macro_rules! context_save { " push r13\n", " push r14\n", " push r15\n", - // Save segment registers + // Save one of the segment registers to get 16-byte alignment for + // FXSAVE. TODO: consider packing the segment registers " mov rax, ds\n", " push rax\n", + // Save floating-point/SSE registers + // TODO: Don't do this unconditionally: get the exn + // handlers compiled without sse + // TODO: Check if we ever generate code with ymm/zmm in + // the handlers and save/restore those as well + " sub rsp, 512\n", + " mov rax, rsp\n", + " fxsave [rax]\n", + // Save the rest of the segment registers " mov rax, es\n", " push rax\n", " mov rax, fs\n", @@ -83,13 +93,18 @@ macro_rules! context_save { macro_rules! context_restore { () => { concat!( - // Restore segment registers + // Restore most segment registers " pop rax\n", " mov gs, rax\n", " pop rax\n", " mov fs, rax\n", " pop rax\n", " mov es, rax\n", + // Restore floating-point/SSE registers + " mov rax, rsp\n", + " fxrstor [rax]\n", + " add rsp, 512\n", + // Restore the last segment register " pop rax\n", " mov ds, rax\n", // Restore general-purpose registers From ea6fa8f16dae2325d94af39eb6ac3b441b24dcac Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Tue, 8 Jul 2025 17:23:20 +0100 Subject: [PATCH 020/271] [hyperlight_host] exceptions: allow guests to register handlers This commit adds a simple mechanism for guests to register exception handlers. It does not support any kind of chaining, so there can only be one exception handler per exception per guest, which should probably be improved in the future. This will be used in hyperlight-wasm shortly. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- .../src/exceptions/handler.rs | 75 ++++++++++++++++++- src/hyperlight_guest_bin/src/lib.rs | 4 +- 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/hyperlight_guest_bin/src/exceptions/handler.rs b/src/hyperlight_guest_bin/src/exceptions/handler.rs index 5bc1a7e09..e2072bf1f 100644 --- a/src/hyperlight_guest_bin/src/exceptions/handler.rs +++ b/src/hyperlight_guest_bin/src/exceptions/handler.rs @@ -21,6 +21,45 @@ use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_common::outb::Exception; use hyperlight_guest::exit::abort_with_code_and_message; +use crate::paging; + +/// See AMD64 Architecture Programmer's Manual, Volume 2 +/// §8.9.3 Interrupt Stack Frame, pp. 283--284 +/// Figure 8-14: Long-Mode Stack After Interrupt---Same Privilege, +/// Figure 8-15: Long-Mode Stack After Interrupt---Higher Privilege +/// Subject to the proviso that we push a dummy error code of 0 for exceptions +/// for which the processor does not provide one +#[repr(C)] +pub struct ExceptionInfo { + pub error_code: u64, + pub rip: u64, + pub cs: u64, + pub rflags: u64, + pub rsp: u64, + pub ss: u64, +} +const _: () = assert!(core::mem::offset_of!(ExceptionInfo, rip) == 8); +const _: () = assert!(core::mem::offset_of!(ExceptionInfo, rsp) == 32); + +#[repr(C)] +/// Saved context, pushed onto the stack by exception entry code +pub struct Context { + /// in order: gs, fs, es + pub segments: [u64; 3], + pub fxsave: [u8; 512], + pub ds: u64, + /// no `rsp`, since the processor saved it + /// `rax` is at the top, `r15` the bottom + pub gprs: [u64; 15], +} +const _: () = assert!(size_of::() == 152 + 512); + +// TODO: This will eventually need to end up in a per-thread context, +// when there are threads. +pub static handlers: [core::sync::atomic::AtomicU64; 31] = + [const { core::sync::atomic::AtomicU64::new(0) }; 31]; +type handler_t = fn(n: u64, info: *mut ExceptionInfo, ctx: *mut Context, pf_addr: u64) -> bool; + /// Exception handler #[unsafe(no_mangle)] pub extern "C" fn hl_exception_handler( @@ -28,13 +67,43 @@ pub extern "C" fn hl_exception_handler( exception_number: u64, page_fault_address: u64, ) { + let ctx = stack_pointer as *mut Context; + let exn_info = (stack_pointer + size_of::() as u64) as *mut ExceptionInfo; + let exception = Exception::try_from(exception_number as u8).expect("Invalid exception number"); + + let saved_rip = unsafe { (&raw const (*exn_info).rip).read_volatile() }; + let error_code = unsafe { (&raw const (*exn_info).error_code).read_volatile() }; + let msg = format!( - "Page Fault Address: {:#x}\n\ - Stack Pointer: {:#x}", - page_fault_address, stack_pointer + "Exception vector: {:#}\n\ + Faulting Instruction: {:#x}\n\ + Page Fault Address: {:#x}\n\ + Error code: {:#x}\n\ + Stack Pointer: {:#x}", + exception_number, saved_rip, page_fault_address, error_code, stack_pointer ); + // We don't presently have any need for user-defined interrupts, + // so we only support handlers for the architecture-defined + // vectors (0-31) + if exception_number < 31 { + let handler = + handlers[exception_number as usize].load(core::sync::atomic::Ordering::Acquire); + if handler != 0 + && unsafe { + core::mem::transmute::<_, handler_t>(handler)( + exception_number, + exn_info, + ctx, + page_fault_address, + ) + } + { + return; + } + } + unsafe { abort_with_code_and_message( &[ErrorCode::GuestError as u8, exception as u8], diff --git a/src/hyperlight_guest_bin/src/lib.rs b/src/hyperlight_guest_bin/src/lib.rs index c3d44f4f5..f48a196d6 100644 --- a/src/hyperlight_guest_bin/src/lib.rs +++ b/src/hyperlight_guest_bin/src/lib.rs @@ -35,9 +35,9 @@ use spin::Once; // === Modules === #[cfg(target_arch = "x86_64")] -mod exceptions { +pub mod exceptions { pub(super) mod gdt; - mod handler; + pub mod handler; mod idt; pub(super) mod idtr; mod interrupt_entry; From 39df600cbaf5a9a74215879f67207d1d07dc3d54 Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Thu, 10 Jul 2025 15:09:47 +0100 Subject: [PATCH 021/271] add memory mapping support with kvm (#709) Signed-off-by: Jorge Prendes --- src/hyperlight_host/src/hypervisor/kvm.rs | 62 ++++++++++++------- src/hyperlight_host/src/mem/memory_region.rs | 23 +++++++ .../src/sandbox/initialized_multi_use.rs | 61 ++++++++++++++++++ src/tests/rust_guests/simpleguest/src/main.rs | 32 ++++++++++ 4 files changed, 155 insertions(+), 23 deletions(-) diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index 3da9786cd..0802ecb6b 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -21,7 +21,7 @@ use std::sync::Arc; use std::sync::Mutex; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; -use kvm_bindings::{KVM_MEM_READONLY, kvm_fpu, kvm_regs, kvm_userspace_memory_region}; +use kvm_bindings::{kvm_fpu, kvm_regs, kvm_userspace_memory_region}; use kvm_ioctls::Cap::UserMemory; use kvm_ioctls::{Kvm, VcpuExit, VcpuFd, VmFd}; use log::LevelFilter; @@ -284,7 +284,8 @@ mod debug { /// A Hypervisor driver for KVM on Linux pub(crate) struct KVMDriver { _kvm: Kvm, - _vm_fd: VmFd, + vm_fd: VmFd, + page_size: usize, vcpu_fd: VcpuFd, entrypoint: u64, orig_rsp: GuestPtr, @@ -317,21 +318,9 @@ impl KVMDriver { let vm_fd = kvm.create_vm_with_type(0)?; - let perm_flags = - MemoryRegionFlags::READ | MemoryRegionFlags::WRITE | MemoryRegionFlags::EXECUTE; - mem_regions.iter().enumerate().try_for_each(|(i, region)| { - let perm_flags = perm_flags.intersection(region.flags); - let kvm_region = kvm_userspace_memory_region { - slot: i as u32, - guest_phys_addr: region.guest_region.start as u64, - memory_size: (region.guest_region.end - region.guest_region.start) as u64, - userspace_addr: region.host_region.start as u64, - flags: match perm_flags { - MemoryRegionFlags::READ => KVM_MEM_READONLY, - _ => 0, // normal, RWX - }, - }; + let mut kvm_region: kvm_userspace_memory_region = region.clone().into(); + kvm_region.slot = i as u32; unsafe { vm_fd.set_user_memory_region(kvm_region) } })?; @@ -378,7 +367,8 @@ impl KVMDriver { #[allow(unused_mut)] let mut hv = Self { _kvm: kvm, - _vm_fd: vm_fd, + vm_fd, + page_size: 0, vcpu_fd, entrypoint, orig_rsp: rsp_gp, @@ -463,6 +453,8 @@ impl Hypervisor for KVMDriver { max_guest_log_level: Option, #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, ) -> Result<()> { + self.page_size = page_size as usize; + let max_guest_log_level: u64 = match max_guest_log_level { Some(level) => level as u64, None => self.get_max_log_level().into(), @@ -494,16 +486,40 @@ impl Hypervisor for KVMDriver { } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - unsafe fn map_region(&mut self, _rgn: &MemoryRegion) -> Result<()> { - log_then_return!("Mapping host memory into the guest not yet supported on this platform"); + unsafe fn map_region(&mut self, region: &MemoryRegion) -> Result<()> { + if [ + region.guest_region.start, + region.guest_region.end, + region.host_region.start, + region.host_region.end, + ] + .iter() + .any(|x| x % self.page_size != 0) + { + log_then_return!( + "region is not page-aligned {:x}, {region:?}", + self.page_size + ); + } + + let mut kvm_region: kvm_userspace_memory_region = region.clone().into(); + kvm_region.slot = self.mem_regions.len() as u32; + unsafe { self.vm_fd.set_user_memory_region(kvm_region) }?; + self.mem_regions.push(region.to_owned()); + Ok(()) } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] unsafe fn unmap_regions(&mut self, n: u64) -> Result<()> { - if n > 0 { - log_then_return!( - "Mapping host memory into the guest not yet supported on this platform" - ); + let n_keep = self.mem_regions.len() - n as usize; + for (k, region) in self.mem_regions.split_off(n_keep).iter().enumerate() { + let mut kvm_region: kvm_userspace_memory_region = region.clone().into(); + kvm_region.slot = (n_keep + k) as u32; + // Setting memory_size to 0 unmaps the slot's region + // From https://docs.kernel.org/virt/kvm/api.html + // > Deleting a slot is done by passing zero for memory_size. + kvm_region.memory_size = 0; + unsafe { self.vm_fd.set_user_memory_region(kvm_region) }?; } Ok(()) } diff --git a/src/hyperlight_host/src/mem/memory_region.rs b/src/hyperlight_host/src/mem/memory_region.rs index c24ac197c..b46426c3b 100644 --- a/src/hyperlight_host/src/mem/memory_region.rs +++ b/src/hyperlight_host/src/mem/memory_region.rs @@ -30,6 +30,8 @@ use bitflags::bitflags; #[cfg(mshv)] use hyperlight_common::mem::PAGE_SHIFT; use hyperlight_common::mem::PAGE_SIZE_USIZE; +#[cfg(kvm)] +use kvm_bindings::{KVM_MEM_READONLY, kvm_userspace_memory_region}; #[cfg(mshv2)] use mshv_bindings::{ HV_MAP_GPA_EXECUTABLE, HV_MAP_GPA_PERMISSIONS_NONE, HV_MAP_GPA_READABLE, HV_MAP_GPA_WRITABLE, @@ -308,3 +310,24 @@ impl From for mshv_user_mem_region { } } } + +#[cfg(kvm)] +impl From for kvm_bindings::kvm_userspace_memory_region { + fn from(region: MemoryRegion) -> Self { + let perm_flags = + MemoryRegionFlags::READ | MemoryRegionFlags::WRITE | MemoryRegionFlags::EXECUTE; + + let perm_flags = perm_flags.intersection(region.flags); + + kvm_userspace_memory_region { + slot: 0, + guest_phys_addr: region.guest_region.start as u64, + memory_size: (region.guest_region.end - region.guest_region.start) as u64, + userspace_addr: region.host_region.start as u64, + flags: match perm_flags { + MemoryRegionFlags::READ => KVM_MEM_READONLY, + _ => 0, // normal, RWX + }, + } + } +} diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 8df9d08ef..c2959262b 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -402,6 +402,10 @@ mod tests { use hyperlight_testing::simple_guest_as_string; use crate::func::call_ctx::MultiUseGuestCallContext; + #[cfg(target_os = "linux")] + use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags, MemoryRegionType}; + #[cfg(target_os = "linux")] + use crate::mem::shared_mem::{ExclusiveSharedMemory, GuestSharedMemory, SharedMemory as _}; use crate::sandbox::{Callable, SandboxConfiguration}; use crate::sandbox_state::sandbox::{DevolvableSandbox, EvolvableSandbox}; use crate::sandbox_state::transition::{MultiUseContextCallback, Noop}; @@ -693,4 +697,61 @@ mod tests { handle.join().unwrap(); } } + + #[cfg(target_os = "linux")] + #[test] + fn test_mmap() { + let mut sbox = UninitializedSandbox::new( + GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")), + None, + ) + .unwrap() + .evolve(Noop::default()) + .unwrap(); + + let expected = b"hello world"; + let map_mem = page_aligned_memory(expected); + let guest_base = 0x1_0000_0000; // Arbitrary guest base address + + unsafe { + sbox.map_region(®ion_for_memory(&map_mem, guest_base)) + .unwrap(); + } + + let _guard = map_mem.lock.try_read().unwrap(); + let actual: Vec = sbox + .call_guest_function_by_name( + "ReadMappedBuffer", + (guest_base as u64, expected.len() as u64), + ) + .unwrap(); + + assert_eq!(actual, expected); + } + + #[cfg(target_os = "linux")] + fn page_aligned_memory(src: &[u8]) -> GuestSharedMemory { + use hyperlight_common::mem::PAGE_SIZE_USIZE; + + let len = src.len().div_ceil(PAGE_SIZE_USIZE) * PAGE_SIZE_USIZE; + + let mut mem = ExclusiveSharedMemory::new(len).unwrap(); + mem.copy_from_slice(src, 0).unwrap(); + + let (_, guest_mem) = mem.build(); + + guest_mem + } + + #[cfg(target_os = "linux")] + fn region_for_memory(mem: &GuestSharedMemory, guest_base: usize) -> MemoryRegion { + let ptr = mem.base_addr(); + let len = mem.mem_size(); + MemoryRegion { + host_region: ptr..(ptr + len), + guest_region: guest_base..(guest_base + len), + flags: MemoryRegionFlags::READ, + region_type: MemoryRegionType::Heap, + } + } } diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index 1cd276dd6..3bf093665 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -775,6 +775,29 @@ fn read_from_user_memory(function_call: &FunctionCall) -> Result> { } } +fn read_mapped_buffer(function_call: &FunctionCall) -> Result> { + if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( + function_call.parameters.clone().unwrap()[0].clone(), + function_call.parameters.clone().unwrap()[1].clone(), + ) { + let base = base as usize as *const u8; + let len = len as usize; + + unsafe { + hyperlight_guest_bin::paging::map_region(base as _, base as _, len as u64 + 4096) + }; + + let data = unsafe { core::slice::from_raw_parts(base, len) }; + + Ok(get_flatbuffer_result(data)) + } else { + Err(HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + "Invalid parameters passed to read_mapped_buffer".to_string(), + )) + } +} + #[no_mangle] pub extern "C" fn hyperlight_main() { let read_from_user_memory_def = GuestFunctionDefinition::new( @@ -786,6 +809,15 @@ pub extern "C" fn hyperlight_main() { register_function(read_from_user_memory_def); + let read_mapped_buffer_def = GuestFunctionDefinition::new( + "ReadMappedBuffer".to_string(), + Vec::from(&[ParameterType::ULong, ParameterType::ULong]), + ReturnType::VecBytes, + read_mapped_buffer as usize, + ); + + register_function(read_mapped_buffer_def); + let set_static_def = GuestFunctionDefinition::new( "SetStatic".to_string(), Vec::new(), From 8c55d6ee83b8f2362f54c899e0f75ad4b49a19d3 Mon Sep 17 00:00:00 2001 From: Mark Rossetti Date: Thu, 10 Jul 2025 17:03:50 -0700 Subject: [PATCH 022/271] Clippy updates (#672) * Run a more exhasutive clippy check Signed-off-by: Mark Rossett * Updating dep_rust.yaml to run clippy and other code checks as a seperate job Signed-off-by: Mark Rossett * Fix clippy warnings for hyperlight-guest Signed-off-by: Mark Rossett * More clippy fixes for hyperlight_guest_bin Signed-off-by: Mark Rossett --------- Signed-off-by: Mark Rossett --- .github/workflows/dep_rust.yml | 59 ++++++++++----- Justfile | 13 ++++ hack/clippy-package-features.sh | 71 ++++++++++++++++++ .../src/guest_handle/handle.rs | 2 +- .../src/guest_handle/host_comm.rs | 6 +- .../src/exceptions/handler.rs | 17 ++--- .../src/exceptions/idtr.rs | 1 + .../src/guest_function/call.rs | 3 +- src/hyperlight_guest_bin/src/host_comm.rs | 6 +- src/hyperlight_guest_bin/src/lib.rs | 2 +- src/hyperlight_guest_bin/src/paging.rs | 72 +++++++++++++------ 11 files changed, 196 insertions(+), 56 deletions(-) create mode 100755 hack/clippy-package-features.sh diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index 389f24faa..07c9f3615 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -31,6 +31,49 @@ defaults: shell: bash jobs: + code-checks: + if: ${{ inputs.docs_only == 'false' }} + timeout-minutes: 60 + strategy: + fail-fast: true + matrix: + hypervisor: ['hyperv-ws2025', kvm] + config: [debug, release] + runs-on: ${{ fromJson( + format('["self-hosted", "{0}", "X64", "1ES.Pool=hld-{1}-amd"]', + (matrix.hypervisor == 'hyperv-ws2025') && 'Windows' || 'Linux', + matrix.hypervisor == 'hyperv-ws2025' && 'win2025' || 'kvm')) }} + steps: + - uses: actions/checkout@v4 + + - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 + with: + rust-toolchain: "1.85" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Does not check for updated Cargo.lock files for test rust guests as this causes an issue with this checkwhen deoendabot updates dependencies in common crates + - name: Ensure up-to-date Cargo.lock + run: | + cargo fetch --locked + + - name: fmt + run: just fmt-check + + - name: clippy + if: ${{ (runner.os == 'Windows' )}} + run: | + just clippy ${{ matrix.config }} + just clippy-guests ${{ matrix.config }} + + - name: clippy exhaustive check + if: ${{ (runner.os == 'Linux' )}} + run: | + just clippy-exhaustive ${{ matrix.config }} + + - name: Verify MSRV + run: ./dev/verify-msrv.sh hyperlight-host hyperlight-guest hyperlight-guest-bin hyperlight-common + build: if: ${{ inputs.docs_only == 'false' }} timeout-minutes: 60 @@ -61,19 +104,6 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: fmt - run: just fmt-check - - - name: clippy - run: | - just clippy ${{ matrix.config }} - just clippy-guests ${{ matrix.config }} - - # Does not check for updated Cargo.lock files for test rust guests as this causes an issue with this checkwhen deoendabot updates dependencies in common crates - - name: Ensure up-to-date Cargo.lock - run: | - cargo fetch --locked - - name: Get gh action service name if: ${{ (runner.os == 'Windows' )}} run: (Get-Service actions.runner.*) | Foreach { $_.Name, $_.UserName, $_.ServiceType } @@ -93,9 +123,6 @@ jobs: - name: Build run: just build ${{ matrix.config }} - - name: Verify MSRV - run: ./dev/verify-msrv.sh hyperlight-host hyperlight-guest hyperlight-guest-bin hyperlight-common - - name: Run Rust tests env: CARGO_TERM_COLOR: always diff --git a/Justfile b/Justfile index 66b06a587..cf32292e5 100644 --- a/Justfile +++ b/Justfile @@ -176,6 +176,19 @@ clippy-apply-fix-unix: clippy-apply-fix-windows: cargo clippy --target x86_64-pc-windows-msvc --fix --all +# Run clippy with feature combinations for all packages +clippy-exhaustive target=default-target: (witguest-wit) + ./hack/clippy-package-features.sh hyperlight-host {{ target }} + ./hack/clippy-package-features.sh hyperlight-guest {{ target }} + ./hack/clippy-package-features.sh hyperlight-guest-bin {{ target }} + ./hack/clippy-package-features.sh hyperlight-common {{ target }} + ./hack/clippy-package-features.sh hyperlight-testing {{ target }} + just clippy-guests {{ target }} + +# Test a specific package with all feature combinations +clippy-package package target=default-target: (witguest-wit) + ./hack/clippy-package-features.sh {{ package }} {{ target }} + # Verify Minimum Supported Rust Version verify-msrv: ./dev/verify-msrv.sh hyperlight-host hyperlight-guest hyperlight-guest-lib hyperlight-common diff --git a/hack/clippy-package-features.sh b/hack/clippy-package-features.sh new file mode 100755 index 000000000..dddf582d8 --- /dev/null +++ b/hack/clippy-package-features.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Check for required arguments +if [[ $# -lt 2 ]]; then + echo "Usage: $0 " >&2 + echo "Example: $0 hyperlight-host debug" >&2 + exit 1 +fi + +PACKAGE="$1" +TARGET="$2" + +# Convert target for cargo profile +PROFILE=$([ "$TARGET" = "debug" ] && echo "dev" || echo "$TARGET") + +# Required features needed so the rust packages can compile +if [[ "$PACKAGE" == "hyperlight-host" ]]; then + REQUIRED_FEATURES=("kvm" "mshv3") +elif [[ "$PACKAGE" == "hyperlight-guest-bin" ]]; then + REQUIRED_FEATURES=("printf") +else + REQUIRED_FEATURES=() +fi + +# Get all features for the package (excluding default and required features) +# Always exclude "default", and exclude any required features using jq +features=$(cargo metadata --format-version 1 --no-deps | jq -r --arg pkg "$PACKAGE" '.packages[] | select(.name == $pkg) | .features | keys[] | select(. != "default" and (IN($ARGS.positional[])|not))' --args "${REQUIRED_FEATURES[@]}" || true) + +# Convert required features array to comma-separated string for cargo +if [[ ${#REQUIRED_FEATURES[@]} -gt 0 ]]; then + required_features_str=$(IFS=,; echo "${REQUIRED_FEATURES[*]}") +else + required_features_str="" +fi + +# Test with minimal features +if [[ ${#REQUIRED_FEATURES[@]} -gt 0 ]]; then + echo "Testing $PACKAGE with required features only ($required_features_str)..." + (set -x; cargo clippy -p "$PACKAGE" --all-targets --no-default-features --features "$required_features_str" --profile="$PROFILE" -- -D warnings) +else + echo "Testing $PACKAGE with no features..." + (set -x; cargo clippy -p "$PACKAGE" --all-targets --no-default-features --profile="$PROFILE" -- -D warnings) +fi + +echo "Testing $PACKAGE with default features..." +(set -x; cargo clippy -p "$PACKAGE" --all-targets --profile="$PROFILE" -- -D warnings) + +# Test each additional feature individually +for feature in $features; do + if [[ ${#REQUIRED_FEATURES[@]} -gt 0 ]]; then + echo "Testing $PACKAGE with feature: $required_features_str,$feature" + (set -x; cargo clippy -p "$PACKAGE" --all-targets --no-default-features --features "$required_features_str,$feature" --profile="$PROFILE" -- -D warnings) + else + echo "Testing $PACKAGE with feature: $feature" + (set -x; cargo clippy -p "$PACKAGE" --all-targets --no-default-features --features "$feature" --profile="$PROFILE" -- -D warnings) + fi +done + +# Test all features together +if [[ -n "$features" ]]; then + all_features=$(echo $features | tr '\n' ',' | sed 's/,$//') + if [[ ${#REQUIRED_FEATURES[@]} -gt 0 ]]; then + echo "Testing $PACKAGE with all features: $required_features_str,$all_features" + (set -x; cargo clippy -p "$PACKAGE" --all-targets --no-default-features --features "$required_features_str,$all_features" --profile="$PROFILE" -- -D warnings) + else + echo "Testing $PACKAGE with all features: $all_features" + (set -x; cargo clippy -p "$PACKAGE" --all-targets --no-default-features --features "$all_features" --profile="$PROFILE" -- -D warnings) + fi +fi \ No newline at end of file diff --git a/src/hyperlight_guest/src/guest_handle/handle.rs b/src/hyperlight_guest/src/guest_handle/handle.rs index c18ba3540..3a22ee26c 100644 --- a/src/hyperlight_guest/src/guest_handle/handle.rs +++ b/src/hyperlight_guest/src/guest_handle/handle.rs @@ -25,7 +25,7 @@ use hyperlight_common::mem::HyperlightPEB; /// /// Guests are expected to initialize this and store it. For example, you /// could store it in a global variable. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Default)] pub struct GuestHandle { peb: Option<*mut HyperlightPEB>, } diff --git a/src/hyperlight_guest/src/guest_handle/host_comm.rs b/src/hyperlight_guest/src/guest_handle/host_comm.rs index 97e90f3a6..972685ae1 100644 --- a/src/hyperlight_guest/src/guest_handle/host_comm.rs +++ b/src/hyperlight_guest/src/guest_handle/host_comm.rs @@ -41,13 +41,13 @@ impl GuestHandle { let user_memory_region_size = unsafe { (*peb_ptr).init_data.size }; if num > user_memory_region_size { - return Err(HyperlightGuestError::new( + Err(HyperlightGuestError::new( ErrorCode::GuestError, format!( "Requested {} bytes from user memory, but only {} bytes are available", num, user_memory_region_size ), - )); + )) } else { let user_memory_region_slice = unsafe { core::slice::from_raw_parts(user_memory_region_ptr, num as usize) }; @@ -142,7 +142,7 @@ impl GuestHandle { /// Write an error to the shared output data buffer. pub fn write_error(&self, error_code: ErrorCode, message: Option<&str>) { let guest_error: GuestError = GuestError::new( - error_code.clone(), + error_code, message.map_or("".to_string(), |m| m.to_string()), ); let guest_error_buffer: Vec = (&guest_error) diff --git a/src/hyperlight_guest_bin/src/exceptions/handler.rs b/src/hyperlight_guest_bin/src/exceptions/handler.rs index e2072bf1f..ab0da4cfe 100644 --- a/src/hyperlight_guest_bin/src/exceptions/handler.rs +++ b/src/hyperlight_guest_bin/src/exceptions/handler.rs @@ -21,8 +21,6 @@ use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_common::outb::Exception; use hyperlight_guest::exit::abort_with_code_and_message; -use crate::paging; - /// See AMD64 Architecture Programmer's Manual, Volume 2 /// §8.9.3 Interrupt Stack Frame, pp. 283--284 /// Figure 8-14: Long-Mode Stack After Interrupt---Same Privilege, @@ -56,9 +54,9 @@ const _: () = assert!(size_of::() == 152 + 512); // TODO: This will eventually need to end up in a per-thread context, // when there are threads. -pub static handlers: [core::sync::atomic::AtomicU64; 31] = +pub static HANDLERS: [core::sync::atomic::AtomicU64; 31] = [const { core::sync::atomic::AtomicU64::new(0) }; 31]; -type handler_t = fn(n: u64, info: *mut ExceptionInfo, ctx: *mut Context, pf_addr: u64) -> bool; +pub type HandlerT = fn(n: u64, info: *mut ExceptionInfo, ctx: *mut Context, pf_addr: u64) -> bool; /// Exception handler #[unsafe(no_mangle)] @@ -89,15 +87,12 @@ pub extern "C" fn hl_exception_handler( // vectors (0-31) if exception_number < 31 { let handler = - handlers[exception_number as usize].load(core::sync::atomic::Ordering::Acquire); + HANDLERS[exception_number as usize].load(core::sync::atomic::Ordering::Acquire); if handler != 0 && unsafe { - core::mem::transmute::<_, handler_t>(handler)( - exception_number, - exn_info, - ctx, - page_fault_address, - ) + core::mem::transmute:: bool>( + handler, + )(exception_number, exn_info, ctx, page_fault_address) } { return; diff --git a/src/hyperlight_guest_bin/src/exceptions/idtr.rs b/src/hyperlight_guest_bin/src/exceptions/idtr.rs index dc547a199..d1d54830b 100644 --- a/src/hyperlight_guest_bin/src/exceptions/idtr.rs +++ b/src/hyperlight_guest_bin/src/exceptions/idtr.rs @@ -49,6 +49,7 @@ pub(crate) unsafe fn load_idt() { // Use &raw mut to get a mutable raw pointer, then dereference it // this is to avoid the clippy warning "shared reference to mutable static" + #[allow(clippy::deref_addrof)] let idtr = &mut *(&raw mut IDTR); idtr.init(expected_base, idt_size as u16); idtr.load(); diff --git a/src/hyperlight_guest_bin/src/guest_function/call.rs b/src/hyperlight_guest_bin/src/guest_function/call.rs index d829e2a85..0c7c99a0e 100644 --- a/src/hyperlight_guest_bin/src/guest_function/call.rs +++ b/src/hyperlight_guest_bin/src/guest_function/call.rs @@ -42,6 +42,7 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result // Find the function definition for the function call. // Use &raw const to get an immutable reference to the static HashMap // this is to avoid the clippy warning "shared reference to mutable static" + #[allow(clippy::deref_addrof)] if let Some(registered_function_definition) = unsafe { (*(&raw const REGISTERED_GUEST_FUNCTIONS)).get(&function_call.function_name) } { @@ -90,7 +91,7 @@ fn internal_dispatch_function() -> Result<()> { .expect("Function call deserialization failed"); let result_vec = call_guest_function(function_call).inspect_err(|e| { - handle.write_error(e.kind.clone(), Some(e.message.as_str())); + handle.write_error(e.kind, Some(e.message.as_str())); })?; handle.push_shared_output_data(result_vec) diff --git a/src/hyperlight_guest_bin/src/host_comm.rs b/src/hyperlight_guest_bin/src/host_comm.rs index e21097661..ab0b3d46a 100644 --- a/src/hyperlight_guest_bin/src/host_comm.rs +++ b/src/hyperlight_guest_bin/src/host_comm.rs @@ -101,7 +101,7 @@ pub fn print_output_with_host_print(function_call: &FunctionCall) -> Result> 4) >> 32) as u32; + let srand_seed = (((peb_address << 8) ^ (seed >> 4)) >> 32) as u32; // Set the seed for the random number generator for C code using rand; srand(srand_seed); diff --git a/src/hyperlight_guest_bin/src/paging.rs b/src/hyperlight_guest_bin/src/paging.rs index 3d824e680..749900349 100644 --- a/src/hyperlight_guest_bin/src/paging.rs +++ b/src/hyperlight_guest_bin/src/paging.rs @@ -53,8 +53,16 @@ struct MapResponse { } /// Assumption: all are page-aligned +/// # Safety +/// This function modifies pages backing a virtual memory range which is inherently unsafe w.r.t. +/// the Rust memory model. +/// When using this function note: +/// - No locking is performed before touching page table data structures, +/// as such do not use concurrently with any other page table operations +/// - TLB invalidation is not performed, +/// if previously-unmapped ranges are not being mapped, TLB invalidation may need to be performed afterwards. pub unsafe fn map_region(phys_base: u64, virt_base: *mut u8, len: u64) { - let mut pml4_base: u64 = 0; + let mut pml4_base: u64; unsafe { asm!("mov {}, cr3", out(reg) pml4_base); } @@ -71,12 +79,18 @@ pub unsafe fn map_region(phys_base: u64, virt_base: *mut u8, len: u64) { .map(|r| unsafe { alloc_pte_if_needed(r) }) .flat_map(modify_ptes::<20, 12>) .map(|r| map_normal(phys_base, virt_base, r)) - .collect::<()>(); + .for_each(drop); } #[allow(unused)] /// This function is not presently used for anything, but is useful /// for debugging +/// # Safety +/// This function traverses page table data structures, and should not be called concurrently +/// with any other operations that modify the page table. +/// # Panics +/// This function will panic if: +/// - A page map request resolves to multiple page table entries pub unsafe fn dbg_print_address_pte(address: u64) -> u64 { let mut pml4_base: u64 = 0; unsafe { @@ -105,11 +119,18 @@ pub unsafe fn dbg_print_address_pte(address: u64) -> u64 { if addrs.len() != 1 { panic!("impossible: 1 page map request resolved to multiple PTEs"); } - return addrs[0]; + addrs[0] } /// Allocate n contiguous physical pages and return the physical /// addresses of the pages in question. +/// # Safety +/// This function is not inherently unsafe but will likely become so in the future +/// when a real physical page allocator is implemented. +/// # Panics +/// This function will panic if: +/// - The Layout creation fails +/// - Memory allocation fails pub unsafe fn alloc_phys_pages(n: u64) -> u64 { // Currently, since all of main memory is idmap'd, we can just // allocate any appropriately aligned section of memory. @@ -125,8 +146,11 @@ pub unsafe fn alloc_phys_pages(n: u64) -> u64 { } } -pub unsafe fn require_pte_exist(x: MapResponse) -> MapRequest { - let mut pte: u64 = 0; +/// # Safety +/// This function traverses page table data structures, and should not be called concurrently +/// with any other operations that modify the page table. +unsafe fn require_pte_exist(x: MapResponse) -> MapRequest { + let mut pte: u64; unsafe { asm!("mov {}, qword ptr [{}]", out(reg) pte, in(reg) x.entry_ptr); } @@ -141,9 +165,12 @@ pub unsafe fn require_pte_exist(x: MapResponse) -> MapRequest { } } -/// Page-mapping callback to allocate a next-level page table if necessary -pub unsafe fn alloc_pte_if_needed(x: MapResponse) -> MapRequest { - let mut pte: u64 = 0; +/// Page-mapping callback to allocate a next-level page table if necessary. +/// # Safety +/// This function modifies page table data structures, and should not be called concurrently +/// with any other operations that modify the page table. +unsafe fn alloc_pte_if_needed(x: MapResponse) -> MapRequest { + let mut pte: u64; unsafe { asm!("mov {}, qword ptr [{}]", out(reg) pte, in(reg) x.entry_ptr); } @@ -157,6 +184,9 @@ pub unsafe fn alloc_pte_if_needed(x: MapResponse) -> MapRequest { } let page_addr = unsafe { alloc_phys_pages(1) }; unsafe { ptov(page_addr).write_bytes(0u8, OS_PAGE_SIZE as usize) }; + + #[allow(clippy::identity_op)] + #[allow(clippy::precedence)] let pte = page_addr | 1 << 5 | // A - we don't track accesses at table level 0 << 4 | // PCD - leave caching enabled @@ -178,6 +208,8 @@ pub unsafe fn alloc_pte_if_needed(x: MapResponse) -> MapRequest { /// /// TODO: support permissions; currently mapping is always RWX fn map_normal(phys_base: u64, virt_base: *mut u8, r: MapResponse) { + #[allow(clippy::identity_op)] + #[allow(clippy::precedence)] let pte = (phys_base + (r.vmin as u64 - virt_base as u64)) | 1 << 6 | // D - we don't presently track dirty state for anything 1 << 5 | // A - we don't presently track access for anything @@ -194,27 +226,27 @@ fn map_normal(phys_base: u64, virt_base: *mut u8, r: MapResponse) { #[inline(always)] /// Utility function to extract an (inclusive on both ends) bit range /// from a quadword. -fn bits(x: u64) -> u64 { - (x & ((1 << (high_bit + 1)) - 1)) >> low_bit +fn bits(x: u64) -> u64 { + (x & ((1 << (HIGH_BIT + 1)) - 1)) >> LOW_BIT } -struct ModifyPteIterator { +struct ModifyPteIterator { request: MapRequest, n: u64, } -impl Iterator for ModifyPteIterator { +impl Iterator for ModifyPteIterator { type Item = MapResponse; fn next(&mut self) -> Option { - if (self.n << low_bit) >= self.request.len { + if (self.n << LOW_BIT) >= self.request.len { return None; } // next stage parameters - let next_vmin = self.request.vmin.wrapping_add((self.n << low_bit) as usize); + let next_vmin = self.request.vmin.wrapping_add((self.n << LOW_BIT) as usize); let entry_ptr = ptov(self.request.table_base) - .wrapping_add((bits::(next_vmin as u64) << 3) as usize) + .wrapping_add((bits::(next_vmin as u64) << 3) as usize) as *mut u64; - let len_from_here = self.request.len - (self.n << low_bit); - let next_len = core::cmp::min(len_from_here, 1 << low_bit); + let len_from_here = self.request.len - (self.n << LOW_BIT); + let next_len = core::cmp::min(len_from_here, 1 << LOW_BIT); // update our state self.n += 1; @@ -226,9 +258,9 @@ impl Iterator for ModifyPteIterator( +fn modify_ptes( r: MapRequest, -) -> ModifyPteIterator { +) -> ModifyPteIterator { ModifyPteIterator { request: r, n: 0 } } @@ -236,7 +268,7 @@ pub fn flush_tlb() { // Currently this just always flips CR4.PGE back and forth to // trigger a tlb flush. We should use a faster approach where // available - let mut orig_cr4: u64 = 0; + let mut orig_cr4: u64; unsafe { asm!("mov {}, cr4", out(reg) orig_cr4); } From 98e31f26499dec1787444c3d5507c2f1c5931cb2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 04:24:21 +0000 Subject: [PATCH 023/271] Bump wasmparser from 0.224.1 to 0.235.0 Bumps [wasmparser](https://github.com/bytecodealliance/wasm-tools) from 0.224.1 to 0.235.0. - [Release notes](https://github.com/bytecodealliance/wasm-tools/releases) - [Commits](https://github.com/bytecodealliance/wasm-tools/commits) --- updated-dependencies: - dependency-name: wasmparser dependency-version: 0.235.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 449f9b17e..41c263955 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3341,9 +3341,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.224.1" +version = "0.235.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f17a5917c2ddd3819e84c661fae0d6ba29d7b9c1f0e96c708c65a9c4188e11" +checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917" dependencies = [ "bitflags 2.9.1", "hashbrown", diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index b23c0fef9..8c90c88b3 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -16,7 +16,7 @@ name = "hyperlight_component_macro" proc-macro = true [dependencies] -wasmparser = { version = "0.224.0" } +wasmparser = { version = "0.235.0" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.95" } syn = { version = "2.0.104" } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index ece9bdb79..57451dbcd 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -15,7 +15,7 @@ Shared implementation for the procedural macros that generate Hyperlight host an name = "hyperlight_component_util" [dependencies] -wasmparser = { version = "0.224.0" } +wasmparser = { version = "0.235.0" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.95" } syn = { version = "2.0.104" } From 879e8417d389bcb44bd5fb0eee556600ad5840fa Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Fri, 27 Jun 2025 16:38:45 -0700 Subject: [PATCH 024/271] Updates for wasmparser apis This was a bit more involved due to a big change in the way function return types are handled. The orginal change was done in https://github.com/WebAssembly/component-model/pull/368 and put initially put behind a feature flag in https://github.com/bytecodealliance/wasm-tools/pull/1670. In 0.226.0 version of wasmparser this feature flag was removed simplify the return results. This in turn simplifies the handling of the results here as well. Signed-off-by: James Sturtevant --- .../src/elaborate.rs | 35 ++++++++----------- src/hyperlight_component_util/src/etypes.rs | 6 +--- src/hyperlight_component_util/src/hl.rs | 12 +++---- src/hyperlight_component_util/src/rtypes.rs | 11 +++--- .../src/substitute.rs | 4 +-- src/hyperlight_component_util/src/wf.rs | 6 ++-- src/tests/rust_guests/witguest/Cargo.lock | 4 +-- 7 files changed, 32 insertions(+), 46 deletions(-) diff --git a/src/hyperlight_component_util/src/elaborate.rs b/src/hyperlight_component_util/src/elaborate.rs index c38051725..bff05737a 100644 --- a/src/hyperlight_component_util/src/elaborate.rs +++ b/src/hyperlight_component_util/src/elaborate.rs @@ -24,14 +24,14 @@ limitations under the License. //! substitute.rs for more details of the approach here). use wasmparser::{ - ComponentAlias, ComponentDefinedType, ComponentFuncResult, ComponentFuncType, - ComponentOuterAliasKind, ComponentType, ComponentTypeDeclaration, ComponentTypeRef, - ComponentValType, CompositeInnerType, CoreType, InstanceTypeDeclaration, ModuleTypeDeclaration, - OuterAliasKind, PrimitiveValType, TypeBounds, TypeRef, + ComponentAlias, ComponentDefinedType, ComponentFuncType, ComponentOuterAliasKind, + ComponentType, ComponentTypeDeclaration, ComponentTypeRef, ComponentValType, + CompositeInnerType, CoreType, InstanceTypeDeclaration, ModuleTypeDeclaration, OuterAliasKind, + PrimitiveValType, TypeBounds, TypeRef, }; use crate::etypes::{ - self, BoundedTyvar, Component, CoreDefined, CoreExportDecl, CoreExternDesc, CoreModule, + BoundedTyvar, Component, CoreDefined, CoreExportDecl, CoreExternDesc, CoreModule, CoreOrComponentExternDesc, Ctx, Defined, ExternDecl, ExternDesc, FloatWidth, Func, Handleable, Instance, IntWidth, Name, Param, QualifiedInstance, RecordField, Resource, ResourceId, TypeBound, Tyvar, Value, VariantCase, @@ -366,6 +366,7 @@ impl<'p, 'a> Ctx<'p, 'a> { PrimitiveValType::F64 => Value::F(FloatWidth::F64), PrimitiveValType::Char => Value::Char, PrimitiveValType::String => Value::String, + PrimitiveValType::ErrorContext => panic!("async not yet supported"), }), } } @@ -428,9 +429,12 @@ impl<'p, 'a> Ctx<'p, 'a> { Defined::Handleable(h) => Ok(Value::Borrow(h.clone())), _ => Err(Error::HandleToNonResource), }, - ComponentDefinedType::Future(_) - | ComponentDefinedType::Stream(_) - | ComponentDefinedType::ErrorContext => panic!("async not yet supported"), + ComponentDefinedType::Future(_) | ComponentDefinedType::Stream(_) => { + panic!("async not yet supported") + } + ComponentDefinedType::FixedSizeList(vt, _) => { + Ok(Value::List(Box::new(self.elab_value(vt)?))) + } } } @@ -446,18 +450,9 @@ impl<'p, 'a> Ctx<'p, 'a> { }) }) .collect::, Error<'a>>>()?, - result: match &ft.results { - ComponentFuncResult::Unnamed(vt) => etypes::Result::Unnamed(self.elab_value(vt)?), - ComponentFuncResult::Named(rs) => etypes::Result::Named( - rs.iter() - .map(|(n, vt)| { - Ok(Param { - name: Name { name: n }, - ty: self.elab_value(vt)?, - }) - }) - .collect::, Error<'a>>>()?, - ), + result: match &ft.result { + Some(vt) => Some(self.elab_value(vt)?), + None => None, }, }) } diff --git a/src/hyperlight_component_util/src/etypes.rs b/src/hyperlight_component_util/src/etypes.rs index 0cec42887..78ce056ab 100644 --- a/src/hyperlight_component_util/src/etypes.rs +++ b/src/hyperlight_component_util/src/etypes.rs @@ -136,11 +136,7 @@ pub struct Param<'a> { pub ty: Value<'a>, } -#[derive(Debug, Clone)] -pub enum Result<'a> { - Unnamed(Value<'a>), - Named(Vec>), -} +pub type Result<'a> = Option>; /// functype_e in the specification #[derive(Debug, Clone)] diff --git a/src/hyperlight_component_util/src/hl.rs b/src/hyperlight_component_util/src/hl.rs index 5a8e984f3..21fc71ad5 100644 --- a/src/hyperlight_component_util/src/hl.rs +++ b/src/hyperlight_component_util/src/hl.rs @@ -653,14 +653,13 @@ pub fn emit_hl_unmarshal_param(s: &mut State, id: Ident, pt: &Value) -> TokenStr /// /// Precondition: the result type must only be a named result if there /// are no names in it (i.e. a unit type) -pub fn emit_hl_unmarshal_result(s: &mut State, id: Ident, rt: &etypes::Result) -> TokenStream { +pub fn emit_hl_unmarshal_result(s: &mut State, id: Ident, rt: &etypes::Result<'_>) -> TokenStream { match rt { - etypes::Result::Named(rs) if rs.is_empty() => quote! { () }, - etypes::Result::Unnamed(vt) => { + Some(vt) => { let toks = emit_hl_unmarshal_value(s, id, vt); quote! { { #toks }.0 } } - _ => panic!("named results not supported"), + None => quote! { () }, } } @@ -680,11 +679,10 @@ pub fn emit_hl_marshal_param(s: &mut State, id: Ident, pt: &Value) -> TokenStrea /// are no names in it (a unit type) pub fn emit_hl_marshal_result(s: &mut State, id: Ident, rt: &etypes::Result) -> TokenStream { match rt { - etypes::Result::Named(rs) if rs.is_empty() => quote! { ::alloc::vec::Vec::new() }, - etypes::Result::Unnamed(vt) => { + None => quote! { ::alloc::vec::Vec::new() }, + Some(vt) => { let toks = emit_hl_marshal_value(s, id, vt); quote! { { #toks } } } - _ => panic!("named results not supported"), } } diff --git a/src/hyperlight_component_util/src/rtypes.rs b/src/hyperlight_component_util/src/rtypes.rs index a6b2266a3..907f88b12 100644 --- a/src/hyperlight_component_util/src/rtypes.rs +++ b/src/hyperlight_component_util/src/rtypes.rs @@ -29,8 +29,8 @@ use crate::emit::{ split_wit_name, }; use crate::etypes::{ - Component, Defined, ExternDecl, ExternDesc, Func, Handleable, ImportExport, Instance, Param, - Result, TypeBound, Tyvar, Value, + self, Component, Defined, ExternDecl, ExternDesc, Func, Handleable, ImportExport, Instance, + Param, TypeBound, Tyvar, Value, }; /// When referring to an instance or resource trait, emit a token @@ -521,11 +521,10 @@ pub fn emit_func_param(s: &mut State, p: &Param) -> TokenStream { /// /// Precondition: the result type must only be a named result if there /// are no names in it (i.e. a unit type) -pub fn emit_func_result(s: &mut State, r: &Result) -> TokenStream { +pub fn emit_func_result(s: &mut State, r: &etypes::Result<'_>) -> TokenStream { match r { - Result::Unnamed(vt) => emit_value(s, vt), - Result::Named(rs) if rs.is_empty() => quote! { () }, - _ => panic!("multiple named function results are not currently supported"), + Some(vt) => emit_value(s, vt), + None => quote! { () }, } } diff --git a/src/hyperlight_component_util/src/substitute.rs b/src/hyperlight_component_util/src/substitute.rs index 94f95cf7b..f885dcb55 100644 --- a/src/hyperlight_component_util/src/substitute.rs +++ b/src/hyperlight_component_util/src/substitute.rs @@ -139,8 +139,8 @@ where rt: &crate::etypes::Result<'a>, ) -> Result, Self::Error> { Ok(match rt { - crate::etypes::Result::Unnamed(vt) => crate::etypes::Result::Unnamed(self.value(vt)?), - crate::etypes::Result::Named(pts) => crate::etypes::Result::Named(self.params(pts)?), + Some(vt) => Some(self.value(vt)?), + None => None, }) } diff --git a/src/hyperlight_component_util/src/wf.rs b/src/hyperlight_component_util/src/wf.rs index db15a7613..b93d1cdfc 100644 --- a/src/hyperlight_component_util/src/wf.rs +++ b/src/hyperlight_component_util/src/wf.rs @@ -268,10 +268,8 @@ impl<'p, 'a> Ctx<'p, 'a> { .iter() .try_for_each(|fp: &'r Param<'a>| self.wf_value(param_pos, &fp.ty))?; match &ft.result { - crate::etypes::Result::Unnamed(vt) => self.wf_value(result_pos, vt), - crate::etypes::Result::Named(ps) => ps - .iter() - .try_for_each(|fp: &'r Param<'a>| self.wf_value(result_pos, &fp.ty)), + Some(vt) => self.wf_value(result_pos, vt), + None => Ok(()), } } fn wf_type_bound<'r>( diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index a1edc4b10..bcb5b4813 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -500,9 +500,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "wasmparser" -version = "0.224.1" +version = "0.235.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f17a5917c2ddd3819e84c661fae0d6ba29d7b9c1f0e96c708c65a9c4188e11" +checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917" dependencies = [ "bitflags", "hashbrown", From 6b7b92afef6a1912fed963871dd6879a3fe44908 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Tue, 1 Jul 2025 17:14:22 +0000 Subject: [PATCH 025/271] Add test to make sure fixed length works Signed-off-by: James Sturtevant --- src/hyperlight_host/tests/wit_test.rs | 4 ++++ src/tests/rust_guests/witguest/guest.wit | 1 + src/tests/rust_guests/witguest/src/main.rs | 3 +++ 3 files changed, 8 insertions(+) diff --git a/src/hyperlight_host/tests/wit_test.rs b/src/hyperlight_host/tests/wit_test.rs index e42441dd8..58572cad4 100644 --- a/src/hyperlight_host/tests/wit_test.rs +++ b/src/hyperlight_host/tests/wit_test.rs @@ -155,6 +155,9 @@ impl test::wit::Roundtrip for Host { ) -> test::wit::roundtrip::Testenum { x } + fn roundtrip_fix_list(&mut self, x: Vec) -> Vec { + x + } fn roundtrip_no_result(&mut self, _x: u32) {} } @@ -331,6 +334,7 @@ mod wit_test { make_test! { roundtrip_flags_large, in arb_largeflags() } make_test! { roundtrip_variant, in arb_testvariant() } make_test! { roundtrip_enum, in arb_testenum() } + make_test! { roundtrip_fix_list, : Vec } #[test] fn test_simple_func() { diff --git a/src/tests/rust_guests/witguest/guest.wit b/src/tests/rust_guests/witguest/guest.wit index 30b4969c5..b99e35ef9 100644 --- a/src/tests/rust_guests/witguest/guest.wit +++ b/src/tests/rust_guests/witguest/guest.wit @@ -26,6 +26,7 @@ interface roundtrip { roundtrip-option: func(x: option) -> option; roundtrip-result: func(x: result) -> result; roundtrip-no-result: func(x: u32); + roundtrip-fix-list: func(x: list) -> list; record testrecord { contents: string, diff --git a/src/tests/rust_guests/witguest/src/main.rs b/src/tests/rust_guests/witguest/src/main.rs index 1edf44ec1..cb71aa0e4 100644 --- a/src/tests/rust_guests/witguest/src/main.rs +++ b/src/tests/rust_guests/witguest/src/main.rs @@ -113,6 +113,9 @@ impl test::wit::Roundtrip for Guest { ) -> test::wit::roundtrip::Testenum { (Host {}).roundtrip_enum(x) } + fn roundtrip_fix_list(&mut self, x: Vec) -> Vec { + (Host {}).roundtrip_fix_list(x) + } fn roundtrip_no_result(&mut self, x: u32) { (Host {}).roundtrip_no_result(x) } From b61265e4aa9e2ecf8d648b994022caeea0205352 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Tue, 1 Jul 2025 19:36:14 +0000 Subject: [PATCH 026/271] Handle fixed list with different API Signed-off-by: James Sturtevant --- .../src/elaborate.rs | 15 ++--- src/hyperlight_component_util/src/etypes.rs | 1 + src/hyperlight_component_util/src/hl.rs | 26 +++++++++ src/hyperlight_component_util/src/rtypes.rs | 5 ++ .../src/substitute.rs | 1 + src/hyperlight_component_util/src/wf.rs | 1 + src/hyperlight_host/tests/wit_test.rs | 58 ++++++++++++++++++- src/tests/rust_guests/witguest/guest.wit | 13 +++++ src/tests/rust_guests/witguest/src/main.rs | 43 +++++++++++++- 9 files changed, 152 insertions(+), 11 deletions(-) diff --git a/src/hyperlight_component_util/src/elaborate.rs b/src/hyperlight_component_util/src/elaborate.rs index bff05737a..120092922 100644 --- a/src/hyperlight_component_util/src/elaborate.rs +++ b/src/hyperlight_component_util/src/elaborate.rs @@ -429,12 +429,12 @@ impl<'p, 'a> Ctx<'p, 'a> { Defined::Handleable(h) => Ok(Value::Borrow(h.clone())), _ => Err(Error::HandleToNonResource), }, + ComponentDefinedType::FixedSizeList(vt, size) => { + Ok(Value::FixList(Box::new(self.elab_value(vt)?), *size)) + } ComponentDefinedType::Future(_) | ComponentDefinedType::Stream(_) => { panic!("async not yet supported") } - ComponentDefinedType::FixedSizeList(vt, _) => { - Ok(Value::List(Box::new(self.elab_value(vt)?))) - } } } @@ -450,10 +450,11 @@ impl<'p, 'a> Ctx<'p, 'a> { }) }) .collect::, Error<'a>>>()?, - result: match &ft.result { - Some(vt) => Some(self.elab_value(vt)?), - None => None, - }, + result: ft + .result + .as_ref() + .map(|vt| self.elab_value(vt)) + .transpose()?, }) } diff --git a/src/hyperlight_component_util/src/etypes.rs b/src/hyperlight_component_util/src/etypes.rs index 78ce056ab..5723eaf9a 100644 --- a/src/hyperlight_component_util/src/etypes.rs +++ b/src/hyperlight_component_util/src/etypes.rs @@ -83,6 +83,7 @@ pub enum Value<'a> { Char, String, List(Box>), + FixList(Box>, u32), Record(Vec>), Tuple(Vec>), Flags(Vec>), diff --git a/src/hyperlight_component_util/src/hl.rs b/src/hyperlight_component_util/src/hl.rs index 21fc71ad5..719262f6e 100644 --- a/src/hyperlight_component_util/src/hl.rs +++ b/src/hyperlight_component_util/src/hl.rs @@ -223,6 +223,20 @@ pub fn emit_hl_unmarshal_value(s: &mut State, id: Ident, vt: &Value) -> TokenStr (#retid, cursor) } } + Value::FixList(vt, _) => { + let inid = format_ident!("{}_elem", id); + let vtun = emit_hl_unmarshal_value(s, inid.clone(), vt); + quote! { + let mut cursor = 0; + let arr = ::core::array::from_fn(|_i| { + let #inid = &#id[cursor..]; + let (x, b) = { #vtun }; + cursor += b; + x + }); + (arr, cursor) + } + } Value::Record(_) => panic!("record not at top level of valtype"), Value::Tuple(vts) => { let inid = format_ident!("{}_elem", id); @@ -515,6 +529,18 @@ pub fn emit_hl_marshal_value(s: &mut State, id: Ident, vt: &Value) -> TokenStrea #retid } } + Value::FixList(vt, _size) => { + let retid = format_ident!("{}_fixlist", id); + let inid = format_ident!("{}_elem", id); + let vtun = emit_hl_marshal_value(s, inid.clone(), vt); + quote! { + let mut #retid = alloc::vec::Vec::new(); + for #inid in #id { + #retid.extend({ #vtun }) + } + #retid + } + } Value::Record(_) => panic!("record not at top level of valtype"), Value::Tuple(vts) => { let retid = format_ident!("{}_tuple", id); diff --git a/src/hyperlight_component_util/src/rtypes.rs b/src/hyperlight_component_util/src/rtypes.rs index 907f88b12..e9b8ded61 100644 --- a/src/hyperlight_component_util/src/rtypes.rs +++ b/src/hyperlight_component_util/src/rtypes.rs @@ -281,6 +281,11 @@ pub fn emit_value(s: &mut State, vt: &Value) -> TokenStream { let vt = emit_value(s, vt); quote! { alloc::vec::Vec<#vt> } } + Value::FixList(vt, size) => { + let vt = emit_value(s, vt); + let size = *size as usize; + quote! { [#vt; #size] } + } Value::Record(_) => panic!("record not at top level of valtype"), Value::Tuple(vts) => { let vts = vts.iter().map(|vt| emit_value(s, vt)).collect::>(); diff --git a/src/hyperlight_component_util/src/substitute.rs b/src/hyperlight_component_util/src/substitute.rs index f885dcb55..5ea07d609 100644 --- a/src/hyperlight_component_util/src/substitute.rs +++ b/src/hyperlight_component_util/src/substitute.rs @@ -96,6 +96,7 @@ where Value::Char => Value::Char, Value::String => Value::String, Value::List(vt) => Value::List(Box::new(self.value(vt)?)), + Value::FixList(vt, size) => Value::FixList(Box::new(self.value(vt)?), *size), Value::Record(rfs) => Value::Record(self.record_fields(rfs)?), Value::Variant(vcs) => Value::Variant(self.variant_cases(vcs)?), Value::Flags(ns) => Value::Flags(ns.clone()), diff --git a/src/hyperlight_component_util/src/wf.rs b/src/hyperlight_component_util/src/wf.rs index b93d1cdfc..20321d6d7 100644 --- a/src/hyperlight_component_util/src/wf.rs +++ b/src/hyperlight_component_util/src/wf.rs @@ -213,6 +213,7 @@ impl<'p, 'a> Ctx<'p, 'a> { Value::Char => Ok(()), Value::String => Ok(()), Value::List(vt) => self.wf_value(p_, vt), + Value::FixList(vt, _) => self.wf_value(p_, vt), Value::Record(rfs) => anon_err.and(self.wf_record_fields(p_, rfs)), Value::Variant(vcs) => anon_err.and(self.wf_variant_cases(p_, vcs)), Value::Flags(ns) => anon_err.and(error_if_duplicates_by( diff --git a/src/hyperlight_host/tests/wit_test.rs b/src/hyperlight_host/tests/wit_test.rs index 58572cad4..6262b8480 100644 --- a/src/hyperlight_host/tests/wit_test.rs +++ b/src/hyperlight_host/tests/wit_test.rs @@ -155,7 +155,46 @@ impl test::wit::Roundtrip for Host { ) -> test::wit::roundtrip::Testenum { x } - fn roundtrip_fix_list(&mut self, x: Vec) -> Vec { + fn roundtrip_fix_list(&mut self, x: [u8; 4]) -> [u8; 4] { + x + } + fn roundtrip_fix_list_u32(&mut self, x: [u32; 4]) -> [u32; 4] { + x + } + fn roundtrip_fix_list_u64(&mut self, x: [u64; 4]) -> [u64; 4] { + x + } + fn roundtrip_fix_list_i8(&mut self, x: [i8; 4]) -> [i8; 4] { + x + } + fn roundtrip_fix_list_i16(&mut self, x: [i16; 4]) -> [i16; 4] { + x + } + fn roundtrip_fix_list_i32(&mut self, x: [i32; 4]) -> [i32; 4] { + x + } + fn roundtrip_fix_list_i64(&mut self, x: [i64; 4]) -> [i64; 4] { + x + } + fn roundtrip_fix_list_f32(&mut self, x: [f32; 4]) -> [f32; 4] { + x + } + fn roundtrip_fix_list_f64(&mut self, x: [f64; 4]) -> [f64; 4] { + x + } + fn roundtrip_fix_list_u8_size8(&mut self, x: [u8; 8]) -> [u8; 8] { + x + } + fn roundtrip_fix_list_u64_size2(&mut self, x: [u64; 2]) -> [u64; 2] { + x + } + fn roundtrip_fix_list_string(&mut self, x: [String; 4]) -> [String; 4] { + x + } + fn roundtrip_fix_array_of_lists(&mut self, x: [Vec; 3]) -> [Vec; 3] { + x + } + fn roundtrip_fix_array_of_string_lists(&mut self, x: [Vec; 2]) -> [Vec; 2] { x } @@ -334,10 +373,23 @@ mod wit_test { make_test! { roundtrip_flags_large, in arb_largeflags() } make_test! { roundtrip_variant, in arb_testvariant() } make_test! { roundtrip_enum, in arb_testenum() } - make_test! { roundtrip_fix_list, : Vec } + make_test! { roundtrip_fix_list, : [u8; 4] } + make_test! { roundtrip_fix_list_u32, : [u32; 4] } + make_test! { roundtrip_fix_list_u64, : [u64; 4] } + make_test! { roundtrip_fix_list_i8, : [i8; 4] } + make_test! { roundtrip_fix_list_i16, : [i16; 4] } + make_test! { roundtrip_fix_list_i32, : [i32; 4] } + make_test! { roundtrip_fix_list_i64, : [i64; 4] } + make_test! { roundtrip_fix_list_f32, : [f32; 4] } + make_test! { roundtrip_fix_list_f64, : [f64; 4] } + make_test! { roundtrip_fix_list_u8_size8, : [u8; 8] } + make_test! { roundtrip_fix_list_u64_size2, : [u64; 2] } + make_test! { roundtrip_fix_list_string, : [String; 4] } + make_test! { roundtrip_fix_array_of_lists, : [Vec; 3] } + make_test! { roundtrip_fix_array_of_string_lists, : [Vec; 2] } #[test] - fn test_simple_func() { + fn test_roundtrip_no_result() { sb().roundtrip().roundtrip_no_result(42); } diff --git a/src/tests/rust_guests/witguest/guest.wit b/src/tests/rust_guests/witguest/guest.wit index b99e35ef9..d8f4c4a5f 100644 --- a/src/tests/rust_guests/witguest/guest.wit +++ b/src/tests/rust_guests/witguest/guest.wit @@ -27,6 +27,19 @@ interface roundtrip { roundtrip-result: func(x: result) -> result; roundtrip-no-result: func(x: u32); roundtrip-fix-list: func(x: list) -> list; + roundtrip-fix-list-u32: func(x: list) -> list; + roundtrip-fix-list-u64: func(x: list) -> list; + roundtrip-fix-list-i8: func(x: list) -> list; + roundtrip-fix-list-i16: func(x: list) -> list; + roundtrip-fix-list-i32: func(x: list) -> list; + roundtrip-fix-list-i64: func(x: list) -> list; + roundtrip-fix-list-f32: func(x: list) -> list; + roundtrip-fix-list-f64: func(x: list) -> list; + roundtrip-fix-list-u8-size8: func(x: list) -> list; + roundtrip-fix-list-u64-size2: func(x: list) -> list; + roundtrip-fix-list-string: func(x: list) -> list; + roundtrip-fix-array-of-lists: func(x: list, 3>) -> list, 3>; + roundtrip-fix-array-of-string-lists: func(x: list, 2>) -> list, 2>; record testrecord { contents: string, diff --git a/src/tests/rust_guests/witguest/src/main.rs b/src/tests/rust_guests/witguest/src/main.rs index cb71aa0e4..cef36b65d 100644 --- a/src/tests/rust_guests/witguest/src/main.rs +++ b/src/tests/rust_guests/witguest/src/main.rs @@ -21,6 +21,8 @@ extern crate alloc; extern crate hyperlight_guest; mod bindings; +use alloc::string::String; + use bindings::*; struct Guest {} @@ -113,9 +115,48 @@ impl test::wit::Roundtrip for Guest { ) -> test::wit::roundtrip::Testenum { (Host {}).roundtrip_enum(x) } - fn roundtrip_fix_list(&mut self, x: Vec) -> Vec { + fn roundtrip_fix_list(&mut self, x: [u8; 4]) -> [u8; 4] { (Host {}).roundtrip_fix_list(x) } + fn roundtrip_fix_list_u32(&mut self, x: [u32; 4]) -> [u32; 4] { + (Host {}).roundtrip_fix_list_u32(x) + } + fn roundtrip_fix_list_u64(&mut self, x: [u64; 4]) -> [u64; 4] { + (Host {}).roundtrip_fix_list_u64(x) + } + fn roundtrip_fix_list_i8(&mut self, x: [i8; 4]) -> [i8; 4] { + (Host {}).roundtrip_fix_list_i8(x) + } + fn roundtrip_fix_list_i16(&mut self, x: [i16; 4]) -> [i16; 4] { + (Host {}).roundtrip_fix_list_i16(x) + } + fn roundtrip_fix_list_i32(&mut self, x: [i32; 4]) -> [i32; 4] { + (Host {}).roundtrip_fix_list_i32(x) + } + fn roundtrip_fix_list_i64(&mut self, x: [i64; 4]) -> [i64; 4] { + (Host {}).roundtrip_fix_list_i64(x) + } + fn roundtrip_fix_list_f32(&mut self, x: [f32; 4]) -> [f32; 4] { + (Host {}).roundtrip_fix_list_f32(x) + } + fn roundtrip_fix_list_f64(&mut self, x: [f64; 4]) -> [f64; 4] { + (Host {}).roundtrip_fix_list_f64(x) + } + fn roundtrip_fix_list_u8_size8(&mut self, x: [u8; 8]) -> [u8; 8] { + (Host {}).roundtrip_fix_list_u8_size8(x) + } + fn roundtrip_fix_list_u64_size2(&mut self, x: [u64; 2]) -> [u64; 2] { + (Host {}).roundtrip_fix_list_u64_size2(x) + } + fn roundtrip_fix_list_string(&mut self, x: [String; 4]) -> [String; 4] { + (Host {}).roundtrip_fix_list_string(x) + } + fn roundtrip_fix_array_of_lists(&mut self, x: [Vec; 3]) -> [Vec; 3] { + x + } + fn roundtrip_fix_array_of_string_lists(&mut self, x: [Vec; 2]) -> [Vec; 2] { + x + } fn roundtrip_no_result(&mut self, x: u32) { (Host {}).roundtrip_no_result(x) } From 346ede3e90c800806268f048a013482cd38ecb59 Mon Sep 17 00:00:00 2001 From: danbugs Date: Wed, 9 Jul 2025 11:03:21 -0700 Subject: [PATCH 027/271] [host/driver/whp] fixed WHP support without init-paging feature Signed-off-by: danbugs --- .../src/hypervisor/hyperv_windows.rs | 31 ++++++++++++------- .../src/sandbox/uninitialized_evolve.rs | 2 +- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index cd0398854..a057c41cc 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -25,8 +25,11 @@ use tracing::{Span, instrument}; use windows::Win32::System::Hypervisor::{ WHV_MEMORY_ACCESS_TYPE, WHV_PARTITION_HANDLE, WHV_REGISTER_VALUE, WHV_RUN_VP_EXIT_CONTEXT, WHV_RUN_VP_EXIT_REASON, WHV_X64_SEGMENT_REGISTER, WHV_X64_SEGMENT_REGISTER_0, - WHvCancelRunVirtualProcessor, WHvX64RegisterCr0, WHvX64RegisterCr3, WHvX64RegisterCr4, - WHvX64RegisterCs, WHvX64RegisterEfer, + WHvCancelRunVirtualProcessor, WHvX64RegisterCs, +}; +#[cfg(feature = "init-paging")] +use windows::Win32::System::Hypervisor::{ + WHvX64RegisterCr0, WHvX64RegisterCr3, WHvX64RegisterCr4, WHvX64RegisterEfer, }; #[cfg(crashdump)] use {super::crashdump, std::path::Path}; @@ -399,16 +402,22 @@ impl HypervWindowsDriver { ])?; #[cfg(not(feature = "init-paging"))] - proc.set_registers(&[( - WHvX64RegisterCs, - WHV_REGISTER_VALUE { - Segment: WHV_X64_SEGMENT_REGISTER { - Base: 0, - Selector: 0, - ..Default::default() + { + proc.set_registers(&[( + WHvX64RegisterCs, + WHV_REGISTER_VALUE { + Segment: WHV_X64_SEGMENT_REGISTER { + Base: 0, + Selector: 0, + Limit: 0xFFFF, + Anonymous: WHV_X64_SEGMENT_REGISTER_0 { + Attributes: 0b1011 | (1 << 4) | (1 << 7), // Type (11: Execute/Read, accessed) | S (code segment) | P (present) + }, + ..Default::default() + }, }, - }, - )])?; + )])?; + } Ok(()) } diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index a37f747e2..6e97c4a9a 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -33,7 +33,7 @@ use crate::mem::mgr::SandboxMemoryManager; use crate::mem::ptr::{GuestPtr, RawPtr}; use crate::mem::ptr_offset::Offset; use crate::mem::shared_mem::GuestSharedMemory; -#[cfg(feature = "init-paging")] +#[cfg(any(feature = "init-paging", target_os = "windows"))] use crate::mem::shared_mem::SharedMemory; #[cfg(gdb)] use crate::sandbox::config::DebugInfo; From a79232ba701a7ba818a6c25d9c226d02678bfb00 Mon Sep 17 00:00:00 2001 From: danbugs Date: Fri, 11 Jul 2025 17:31:51 +0000 Subject: [PATCH 028/271] [ci] update ci to ensure it builds on windows w/o any features + on Linux w/o init-paging but some driver Signed-off-by: danbugs --- .github/workflows/dep_rust.yml | 4 ++-- Justfile | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index 07c9f3615..fe7d0f203 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -138,8 +138,8 @@ jobs: cargo check -p hyperlight-host --features print_debug cargo check -p hyperlight-host --features gdb - # without any driver (shouldn't compile) - just test-compilation-fail ${{ matrix.config }} + # without any features + just test-compilation-no-default-features ${{ matrix.config }} # One of the examples is flaky on Windows GH runners, so this allows us to disable it for now - name: Run Rust examples - windows diff --git a/Justfile b/Justfile index cf32292e5..ffd7f7c39 100644 --- a/Justfile +++ b/Justfile @@ -84,7 +84,7 @@ test-like-ci config=default-target hypervisor="kvm": cargo check -p hyperlight-host --features gdb @# without any driver (should fail to compile) - just test-compilation-fail {{config}} + just test-compilation-no-default-features {{config}} @# test the crashdump feature just test-rust-crashdump {{config}} @@ -121,10 +121,16 @@ test-seccomp target=default-target features="": cargo test --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host test_violate_seccomp_filters --lib {{ if features =="" {''} else { "--features " + features } }} -- --ignored cargo test --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host test_violate_seccomp_filters --no-default-features {{ if features =~"mshv3" {"--features init-paging,mshv3"} else {"--features mshv2,init-paging,kvm" } }} --lib -- --ignored -# runs tests that ensure compilation fails when it should -test-compilation-fail target=default-target: - @# the following should fail on linux because one of kvm, mshv, or mshv3 feature must be specified, which is why the exit code is inverted with an !. - {{ if os() == "linux" { "! cargo check -p hyperlight-host --no-default-features 2> /dev/null"} else { "" } }} +# tests compilation with no default features on different platforms +test-compilation-no-default-features target=default-target: + @# Linux should fail without a hypervisor feature (kvm, mshv, or mshv3) + {{ if os() == "linux" { "! cargo check -p hyperlight-host --no-default-features 2> /dev/null" } else { "" } }} + @# Windows should succeed even without default features + {{ if os() == "windows" { "cargo check -p hyperlight-host --no-default-features" } else { "" } }} + @# Linux should succeed with a hypervisor driver but without init-paging + {{ if os() == "linux" { "cargo check -p hyperlight-host --no-default-features --features kvm" } else { "" } }} + {{ if os() == "linux" { "cargo check -p hyperlight-host --no-default-features --features mshv2" } else { "" } }} + {{ if os() == "linux" { "cargo check -p hyperlight-host --no-default-features --features mshv3" } else { "" } }} # runs tests that exercise gdb debugging test-rust-gdb-debugging target=default-target features="": From 27c01eab990495fa14e7cdfd7da908657b7cead3 Mon Sep 17 00:00:00 2001 From: danbugs Date: Fri, 11 Jul 2025 19:54:31 +0000 Subject: [PATCH 029/271] [host/driver/hyperv_linux] fixed mshv support without init-paging feature Signed-off-by: danbugs --- .../src/hypervisor/hyperv_linux.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 90e91f496..d9160b6f2 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -479,6 +479,28 @@ impl HypervLinuxDriver { cs: SegmentRegister { base: 0, selector: 0, + limit: 0xFFFF, + type_: 11, + present: 1, + s: 1, + ..Default::default() + }, + ds: SegmentRegister { + base: 0, + selector: 0, + limit: 0xFFFF, + type_: 3, + present: 1, + s: 1, + ..Default::default() + }, + tr: SegmentRegister { + base: 0, + selector: 0, + limit: 0xFFFF, + type_: 11, + present: 1, + s: 0, ..Default::default() }, ..Default::default() From e4a661a09e26cab2b195117020bf7c0af90cfc8e Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Thu, 17 Jul 2025 00:05:02 +0100 Subject: [PATCH 030/271] Remove sandbox evolving and devolving and replace it with snapshotting API. (#697) * expose snapshots to the public API Signed-off-by: Jorge Prendes * remove usage of devolve Signed-off-by: Jorge Prendes * remove DevolvableSandbox trait Signed-off-by: Jorge Prendes * Remove dead code Signed-off-by: Jorge Prendes * replace evolving a MultiUseSandbox with persist_call_guest_function_by_name Signed-off-by: Jorge Prendes * make all guest function calls persistent Signed-off-by: Jorge Prendes * remove dead code Signed-off-by: Jorge Prendes * fix examples Signed-off-by: Jorge Prendes * Remove MultiUseGuestCallContext Signed-off-by: Jorge Prendes * remove EvolvableSandbox trait Signed-off-by: Jorge Prendes * remove TransitionMetadata Signed-off-by: Jorge Prendes * remove Noop transition Signed-off-by: Jorge Prendes * remove automatic snapshot stack Signed-off-by: Jorge Prendes * Remove Sandbox trait Signed-off-by: Jorge Prendes * fix formatting Signed-off-by: Jorge Prendes * fix license header Signed-off-by: Jorge Prendes * fix benchmark to new API Signed-off-by: Jorge Prendes * fix formatting again Signed-off-by: Jorge Prendes * address review comments Signed-off-by: Jorge Prendes --------- Signed-off-by: Jorge Prendes --- README.md | 4 +- fuzz/fuzz_targets/guest_call.rs | 4 +- fuzz/fuzz_targets/host_call.rs | 4 +- fuzz/fuzz_targets/host_print.rs | 4 +- src/hyperlight_component_util/src/host.rs | 9 +- src/hyperlight_host/benches/benchmarks.rs | 45 +-- src/hyperlight_host/examples/func_ctx/main.rs | 46 +-- .../examples/guest-debugging/main.rs | 7 +- .../examples/hello-world/main.rs | 4 +- src/hyperlight_host/examples/logging/main.rs | 21 +- src/hyperlight_host/examples/metrics/main.rs | 21 +- .../examples/tracing-chrome/main.rs | 8 +- .../examples/tracing-otlp/main.rs | 16 +- .../examples/tracing-tracy/main.rs | 8 +- src/hyperlight_host/examples/tracing/main.rs | 21 +- src/hyperlight_host/src/func/call_ctx.rs | 279 ---------------- src/hyperlight_host/src/func/mod.rs | 4 - src/hyperlight_host/src/lib.rs | 6 - src/hyperlight_host/src/mem/mgr.rs | 77 ++--- .../src/mem/shared_mem_snapshot.rs | 13 +- src/hyperlight_host/src/metrics/mod.rs | 4 +- .../src/sandbox/initialized_multi_use.rs | 305 ++++++------------ src/hyperlight_host/src/sandbox/mod.rs | 13 +- .../mod.rs => sandbox/snapshot.rs} | 15 +- .../src/sandbox/uninitialized.rs | 58 +--- .../src/sandbox/uninitialized_evolve.rs | 35 +- .../src/sandbox_state/sandbox.rs | 80 ----- .../src/sandbox_state/transition.rs | 178 ---------- src/hyperlight_host/tests/common/mod.rs | 4 +- src/hyperlight_host/tests/integration_test.rs | 80 ++--- .../tests/sandbox_host_tests.rs | 16 +- src/hyperlight_host/tests/wit_test.rs | 4 +- 32 files changed, 291 insertions(+), 1102 deletions(-) delete mode 100644 src/hyperlight_host/src/func/call_ctx.rs rename src/hyperlight_host/src/{sandbox_state/mod.rs => sandbox/snapshot.rs} (63%) delete mode 100644 src/hyperlight_host/src/sandbox_state/sandbox.rs delete mode 100644 src/hyperlight_host/src/sandbox_state/transition.rs diff --git a/README.md b/README.md index 042ff7bf2..6ca4ec826 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,6 @@ It is followed by an example of a simple guest application using the Hyperlight ```rust use std::thread; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; fn main() -> hyperlight_host::Result<()> { @@ -54,7 +52,7 @@ fn main() -> hyperlight_host::Result<()> { // Note: This function is unused by the guest code below, it's just here for demonstration purposes // Initialize sandbox to be able to call host functions - let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve(Noop::default())?; + let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve()?; // Call a function in the guest let message = "Hello, World! I am executing inside of a VM :)\n".to_string(); diff --git a/fuzz/fuzz_targets/guest_call.rs b/fuzz/fuzz_targets/guest_call.rs index 2e0fcee00..bc0ff163f 100644 --- a/fuzz/fuzz_targets/guest_call.rs +++ b/fuzz/fuzz_targets/guest_call.rs @@ -20,8 +20,6 @@ use std::sync::{Mutex, OnceLock}; use hyperlight_host::func::{ParameterValue, ReturnType}; use hyperlight_host::sandbox::uninitialized::GuestBinary; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::simple_guest_for_fuzzing_as_string; use libfuzzer_sys::fuzz_target; @@ -38,7 +36,7 @@ fuzz_target!( ) .unwrap(); - let mu_sbox: MultiUseSandbox = u_sbox.evolve(Noop::default()).unwrap(); + let mu_sbox: MultiUseSandbox = u_sbox.evolve().unwrap(); SANDBOX.set(Mutex::new(mu_sbox)).unwrap(); }, diff --git a/fuzz/fuzz_targets/host_call.rs b/fuzz/fuzz_targets/host_call.rs index bdd8ad760..5c72a98e5 100644 --- a/fuzz/fuzz_targets/host_call.rs +++ b/fuzz/fuzz_targets/host_call.rs @@ -20,8 +20,6 @@ use std::sync::{Mutex, OnceLock}; use hyperlight_host::func::{ParameterValue, ReturnType}; use hyperlight_host::sandbox::uninitialized::GuestBinary; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{HyperlightError, MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::simple_guest_for_fuzzing_as_string; use libfuzzer_sys::fuzz_target; @@ -37,7 +35,7 @@ fuzz_target!( ) .unwrap(); - let mu_sbox: MultiUseSandbox = u_sbox.evolve(Noop::default()).unwrap(); + let mu_sbox: MultiUseSandbox = u_sbox.evolve().unwrap(); SANDBOX.set(Mutex::new(mu_sbox)).unwrap(); }, diff --git a/fuzz/fuzz_targets/host_print.rs b/fuzz/fuzz_targets/host_print.rs index 0a7e90d40..c9c889e9e 100644 --- a/fuzz/fuzz_targets/host_print.rs +++ b/fuzz/fuzz_targets/host_print.rs @@ -3,8 +3,6 @@ use std::sync::{Mutex, OnceLock}; use hyperlight_host::sandbox::uninitialized::GuestBinary; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::simple_guest_for_fuzzing_as_string; use libfuzzer_sys::{Corpus, fuzz_target}; @@ -23,7 +21,7 @@ fuzz_target!( ) .unwrap(); - let mu_sbox: MultiUseSandbox = u_sbox.evolve(Noop::default()).unwrap(); + let mu_sbox: MultiUseSandbox = u_sbox.evolve().unwrap(); SANDBOX.set(Mutex::new(mu_sbox)).unwrap(); }, diff --git a/src/hyperlight_component_util/src/host.rs b/src/hyperlight_component_util/src/host.rs index 4b822b10c..b8a194dd2 100644 --- a/src/hyperlight_component_util/src/host.rs +++ b/src/hyperlight_component_util/src/host.rs @@ -347,7 +347,6 @@ fn emit_component<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, ct: &'c Com pub(crate) rt: ::std::sync::Arc<::std::sync::Mutex<#rtsid>>, } pub(crate) fn register_host_functions(sb: &mut S, i: I) -> ::std::sync::Arc<::std::sync::Mutex<#rtsid>> { - use ::hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; let rts = ::std::sync::Arc::new(::std::sync::Mutex::new(#rtsid::new())); let #import_id = ::std::sync::Arc::new(::std::sync::Mutex::new(i)); #(#imports)* @@ -357,14 +356,12 @@ fn emit_component<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, ct: &'c Com #(#exports)* } impl #ns::#r#trait for ::hyperlight_host::sandbox::UninitializedSandbox { - type Exports = #wrapper_name; + type Exports = #wrapper_name; fn instantiate(mut self, i: I) -> Self::Exports { let rts = register_host_functions(&mut self, i); - let noop = ::core::default::Default::default(); - let sb = ::hyperlight_host::sandbox_state::sandbox::EvolvableSandbox::evolve(self, noop).unwrap(); - let cc = ::hyperlight_host::func::call_ctx::MultiUseGuestCallContext::start(sb); + let sb = self.evolve().unwrap(); #wrapper_name { - sb: cc, + sb, rt: rts, } } diff --git a/src/hyperlight_host/benches/benchmarks.rs b/src/hyperlight_host/benches/benchmarks.rs index c9160ff52..96cc7ecf0 100644 --- a/src/hyperlight_host/benches/benchmarks.rs +++ b/src/hyperlight_host/benches/benchmarks.rs @@ -19,8 +19,6 @@ use hyperlight_host::GuestBinary; use hyperlight_host::sandbox::{ Callable, MultiUseSandbox, SandboxConfiguration, UninitializedSandbox, }; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_testing::simple_guest_as_string; fn create_uninit_sandbox() -> UninitializedSandbox { @@ -29,7 +27,7 @@ fn create_uninit_sandbox() -> UninitializedSandbox { } fn create_multiuse_sandbox() -> MultiUseSandbox { - create_uninit_sandbox().evolve(Noop::default()).unwrap() + create_uninit_sandbox().evolve().unwrap() } fn guest_call_benchmark(c: &mut Criterion) { @@ -38,24 +36,20 @@ fn guest_call_benchmark(c: &mut Criterion) { // Benchmarks a single guest function call. // The benchmark does **not** include the time to reset the sandbox memory after the call. group.bench_function("guest_call", |b| { - let mut call_ctx = create_multiuse_sandbox().new_call_context(); + let mut sbox = create_multiuse_sandbox(); - b.iter(|| { - call_ctx - .call::("Echo", "hello\n".to_string()) - .unwrap() - }); + b.iter(|| sbox.call::("Echo", "hello\n".to_string()).unwrap()); }); // Benchmarks a single guest function call. // The benchmark does include the time to reset the sandbox memory after the call. - group.bench_function("guest_call_with_reset", |b| { - let mut sandbox = create_multiuse_sandbox(); + group.bench_function("guest_call_with_restore", |b| { + let mut sbox = create_multiuse_sandbox(); + let snapshot = sbox.snapshot().unwrap(); b.iter(|| { - sandbox - .call_guest_function_by_name::("Echo", "hello\n".to_string()) - .unwrap() + sbox.call::("Echo", "hello\n".to_string()).unwrap(); + sbox.restore(&snapshot).unwrap(); }); }); @@ -69,11 +63,13 @@ fn guest_call_benchmark(c: &mut Criterion) { .register("HostAdd", |a: i32, b: i32| Ok(a + b)) .unwrap(); - let multiuse_sandbox: MultiUseSandbox = - uninitialized_sandbox.evolve(Noop::default()).unwrap(); - let mut call_ctx = multiuse_sandbox.new_call_context(); + let mut multiuse_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve().unwrap(); - b.iter(|| call_ctx.call::("Add", (1_i32, 41_i32)).unwrap()); + b.iter(|| { + multiuse_sandbox + .call::("Add", (1_i32, 41_i32)) + .unwrap() + }); }); group.finish(); @@ -99,7 +95,7 @@ fn guest_call_benchmark_large_param(c: &mut Criterion) { Some(config), ) .unwrap(); - let mut sandbox = sandbox.evolve(Noop::default()).unwrap(); + let mut sandbox = sandbox.evolve().unwrap(); b.iter(|| { sandbox @@ -139,17 +135,6 @@ fn sandbox_benchmark(c: &mut Criterion) { b.iter(create_multiuse_sandbox); }); - // Benchmarks the time to create a new sandbox and create a new call context. - // Does **not** include the time to drop the sandbox or the call context. - group.bench_function("create_sandbox_and_call_context", |b| { - b.iter_with_large_drop(|| create_multiuse_sandbox().new_call_context()); - }); - - // Benchmarks the time to create a new sandbox, create a new call context, and drop the call context. - group.bench_function("create_sandbox_and_call_context_and_drop", |b| { - b.iter(|| create_multiuse_sandbox().new_call_context()); - }); - group.finish(); } diff --git a/src/hyperlight_host/examples/func_ctx/main.rs b/src/hyperlight_host/examples/func_ctx/main.rs index ce427a651..2692f9487 100644 --- a/src/hyperlight_host/examples/func_ctx/main.rs +++ b/src/hyperlight_host/examples/func_ctx/main.rs @@ -14,42 +14,28 @@ See the License for the specific language governing permissions and limitations under the License. */ -use hyperlight_host::func::call_ctx::MultiUseGuestCallContext; -use hyperlight_host::sandbox::{Callable, MultiUseSandbox, UninitializedSandbox}; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; -use hyperlight_host::{GuestBinary, Result}; +use hyperlight_host::GuestBinary; +use hyperlight_host::sandbox::UninitializedSandbox; use hyperlight_testing::simple_guest_as_string; fn main() { // create a new `MultiUseSandbox` configured to run the `simpleguest.exe` // test guest binary - let sbox1: MultiUseSandbox = { - let path = simple_guest_as_string().unwrap(); - let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap(); - u_sbox.evolve(Noop::default()) - } - .unwrap(); - - // create a new call context from the sandbox, then do some calls with it. - let ctx1 = sbox1.new_call_context(); - let sbox2 = do_calls(ctx1).unwrap(); - // create a new call context from the returned sandbox, then do some calls - // with that one - let ctx2 = sbox2.new_call_context(); - do_calls(ctx2).unwrap(); -} - -/// Given a `MultiUseGuestCallContext` derived from an existing -/// `MultiUseSandbox` configured to run the `simpleguest.exe` test guest -/// binary, do several calls against that binary, print their results, then -/// call `ctx.finish()` and return the resulting `MultiUseSandbox`. Return an `Err` -/// if anything failed. -fn do_calls(mut ctx: MultiUseGuestCallContext) -> Result { - let res: String = ctx.call("Echo", "hello".to_string())?; + let path = simple_guest_as_string().unwrap(); + let mut sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None) + .unwrap() + .evolve() + .unwrap(); + + // Do several calls against a sandbox running the `simpleguest.exe` binary, + // and print their results + let res: String = sbox + .call_guest_function_by_name("Echo", "hello".to_string()) + .unwrap(); println!("got Echo res: {res}"); - let res: i32 = ctx.call("CallMalloc", 200_i32)?; + let res: i32 = sbox + .call_guest_function_by_name("CallMalloc", 200_i32) + .unwrap(); println!("got CallMalloc res: {res}"); - ctx.finish() } diff --git a/src/hyperlight_host/examples/guest-debugging/main.rs b/src/hyperlight_host/examples/guest-debugging/main.rs index f33ed511f..6b1f46677 100644 --- a/src/hyperlight_host/examples/guest-debugging/main.rs +++ b/src/hyperlight_host/examples/guest-debugging/main.rs @@ -19,8 +19,6 @@ use std::thread; use hyperlight_host::sandbox::SandboxConfiguration; #[cfg(gdb)] use hyperlight_host::sandbox::config::DebugInfo; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; /// Build a sandbox configuration that enables GDB debugging when the `gdb` feature is enabled. @@ -70,9 +68,8 @@ fn main() -> hyperlight_host::Result<()> { // Note: This function is unused, it's just here for demonstration purposes // Initialize sandboxes to be able to call host functions - let mut multi_use_sandbox_dbg: MultiUseSandbox = - uninitialized_sandbox_dbg.evolve(Noop::default())?; - let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve(Noop::default())?; + let mut multi_use_sandbox_dbg: MultiUseSandbox = uninitialized_sandbox_dbg.evolve()?; + let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve()?; // Call guest function let message = diff --git a/src/hyperlight_host/examples/hello-world/main.rs b/src/hyperlight_host/examples/hello-world/main.rs index 57c0b4398..e8461954a 100644 --- a/src/hyperlight_host/examples/hello-world/main.rs +++ b/src/hyperlight_host/examples/hello-world/main.rs @@ -16,8 +16,6 @@ limitations under the License. #![allow(clippy::disallowed_macros)] use std::thread; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; fn main() -> hyperlight_host::Result<()> { @@ -37,7 +35,7 @@ fn main() -> hyperlight_host::Result<()> { // Note: This function is unused, it's just here for demonstration purposes // Initialize sandbox to be able to call host functions - let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve(Noop::default())?; + let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve()?; // Call guest function let message = "Hello, World! I am executing inside of a VM :)\n".to_string(); diff --git a/src/hyperlight_host/examples/logging/main.rs b/src/hyperlight_host/examples/logging/main.rs index ea6e18b31..470441e72 100644 --- a/src/hyperlight_host/examples/logging/main.rs +++ b/src/hyperlight_host/examples/logging/main.rs @@ -18,11 +18,8 @@ extern crate hyperlight_host; use std::sync::{Arc, Barrier}; -use hyperlight_host::sandbox::Callable; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; -use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; +use hyperlight_host::{GuestBinary, Result}; use hyperlight_testing::simple_guest_as_string; fn fn_writer(_msg: String) -> Result { @@ -48,10 +45,7 @@ fn main() -> Result<()> { usandbox.register_print(fn_writer)?; // Initialize the sandbox. - - let no_op = Noop::::default(); - - let mut multiuse_sandbox = usandbox.evolve(no_op)?; + let mut multiuse_sandbox = usandbox.evolve()?; // Call a guest function 5 times to generate some log entries. for _ in 0..5 { @@ -81,10 +75,7 @@ fn main() -> Result<()> { UninitializedSandbox::new(GuestBinary::FilePath(hyperlight_guest_path.clone()), None)?; // Initialize the sandbox. - - let no_op = Noop::::default(); - - let mut multiuse_sandbox = usandbox.evolve(no_op)?; + let mut multiuse_sandbox = usandbox.evolve()?; let interrupt_handle = multiuse_sandbox.interrupt_handle(); let barrier = Arc::new(Barrier::new(2)); let barrier2 = barrier.clone(); @@ -102,10 +93,10 @@ fn main() -> Result<()> { // Call a function that gets cancelled by the host function 5 times to generate some log entries. for _ in 0..NUM_CALLS { - let mut ctx = multiuse_sandbox.new_call_context(); barrier.wait(); - ctx.call::<()>("Spin", ()).unwrap_err(); - multiuse_sandbox = ctx.finish().unwrap(); + multiuse_sandbox + .call_guest_function_by_name::<()>("Spin", ()) + .unwrap_err(); } thread.join().unwrap(); diff --git a/src/hyperlight_host/examples/metrics/main.rs b/src/hyperlight_host/examples/metrics/main.rs index 5b7cc103f..4328a3bfa 100644 --- a/src/hyperlight_host/examples/metrics/main.rs +++ b/src/hyperlight_host/examples/metrics/main.rs @@ -18,11 +18,8 @@ extern crate hyperlight_host; use std::sync::{Arc, Barrier}; use std::thread::{JoinHandle, spawn}; -use hyperlight_host::sandbox::Callable; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; -use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; +use hyperlight_host::{GuestBinary, Result}; use hyperlight_testing::simple_guest_as_string; // Run this rust example with the flag --features "function_call_metrics" to enable more metrics to be emitted @@ -59,10 +56,7 @@ fn do_hyperlight_stuff() { usandbox.register_print(fn_writer)?; // Initialize the sandbox. - - let no_op = Noop::::default(); - - let mut multiuse_sandbox = usandbox.evolve(no_op).expect("Failed to evolve sandbox"); + let mut multiuse_sandbox = usandbox.evolve().expect("Failed to evolve sandbox"); // Call a guest function 5 times to generate some metrics. for _ in 0..5 { @@ -93,10 +87,7 @@ fn do_hyperlight_stuff() { .expect("Failed to create UninitializedSandbox"); // Initialize the sandbox. - - let no_op = Noop::::default(); - - let mut multiuse_sandbox = usandbox.evolve(no_op).expect("Failed to evolve sandbox"); + let mut multiuse_sandbox = usandbox.evolve().expect("Failed to evolve sandbox"); let interrupt_handle = multiuse_sandbox.interrupt_handle(); const NUM_CALLS: i32 = 5; @@ -116,10 +107,10 @@ fn do_hyperlight_stuff() { // Call a function that gets cancelled by the host function 5 times to generate some metrics. for _ in 0..NUM_CALLS { - let mut ctx = multiuse_sandbox.new_call_context(); barrier.wait(); - ctx.call::<()>("Spin", ()).unwrap_err(); - multiuse_sandbox = ctx.finish().unwrap(); + multiuse_sandbox + .call_guest_function_by_name::<()>("Spin", ()) + .unwrap_err(); } for join_handle in join_handles { diff --git a/src/hyperlight_host/examples/tracing-chrome/main.rs b/src/hyperlight_host/examples/tracing-chrome/main.rs index a93e03fab..259a37057 100644 --- a/src/hyperlight_host/examples/tracing-chrome/main.rs +++ b/src/hyperlight_host/examples/tracing-chrome/main.rs @@ -15,9 +15,7 @@ limitations under the License. */ #![allow(clippy::disallowed_macros)] use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; -use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; +use hyperlight_host::{GuestBinary, Result}; use hyperlight_testing::simple_guest_as_string; use tracing_chrome::ChromeLayerBuilder; use tracing_subscriber::prelude::*; @@ -34,9 +32,7 @@ fn main() -> Result<()> { // Create a new sandbox. let usandbox = UninitializedSandbox::new(GuestBinary::FilePath(simple_guest_path), None)?; - let mut sbox = usandbox - .evolve(Noop::::default()) - .unwrap(); + let mut sbox = usandbox.evolve().unwrap(); // do the function call let current_time = std::time::Instant::now(); diff --git a/src/hyperlight_host/examples/tracing-otlp/main.rs b/src/hyperlight_host/examples/tracing-otlp/main.rs index 86b6b4e29..69d318c1f 100644 --- a/src/hyperlight_host/examples/tracing-otlp/main.rs +++ b/src/hyperlight_host/examples/tracing-otlp/main.rs @@ -26,11 +26,8 @@ use std::io::stdin; use std::sync::{Arc, Barrier, Mutex}; use std::thread::{JoinHandle, spawn}; -use hyperlight_host::sandbox::Callable; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; -use hyperlight_host::{GuestBinary, MultiUseSandbox, Result as HyperlightResult}; +use hyperlight_host::{GuestBinary, Result as HyperlightResult}; use hyperlight_testing::simple_guest_as_string; use opentelemetry::trace::TracerProvider; use opentelemetry::{KeyValue, global}; @@ -134,10 +131,7 @@ fn run_example(wait_input: bool) -> HyperlightResult<()> { usandbox.register_print(fn_writer)?; // Initialize the sandbox. - - let no_op = Noop::::default(); - - let mut multiuse_sandbox = usandbox.evolve(no_op)?; + let mut multiuse_sandbox = usandbox.evolve()?; // Call a guest function 5 times to generate some log entries. for _ in 0..5 { @@ -184,10 +178,10 @@ fn run_example(wait_input: bool) -> HyperlightResult<()> { uuid = %id, ); let _entered = span.enter(); - let mut ctx = multiuse_sandbox.new_call_context(); barrier.wait(); - ctx.call::<()>("Spin", ()).unwrap_err(); - multiuse_sandbox = ctx.finish().unwrap(); + multiuse_sandbox + .call_guest_function_by_name::<()>("Spin", ()) + .unwrap_err(); } thread.join().expect("Thread panicked"); } diff --git a/src/hyperlight_host/examples/tracing-tracy/main.rs b/src/hyperlight_host/examples/tracing-tracy/main.rs index 615b59c38..03867f0d5 100644 --- a/src/hyperlight_host/examples/tracing-tracy/main.rs +++ b/src/hyperlight_host/examples/tracing-tracy/main.rs @@ -15,9 +15,7 @@ limitations under the License. */ #![allow(clippy::disallowed_macros)] use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; -use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; +use hyperlight_host::{GuestBinary, Result}; use hyperlight_testing::simple_guest_as_string; use tracing_subscriber::EnvFilter; use tracing_subscriber::layer::SubscriberExt; @@ -40,9 +38,7 @@ fn main() -> Result<()> { // Create a new sandbox. let usandbox = UninitializedSandbox::new(GuestBinary::FilePath(simple_guest_path), None)?; - let mut sbox = usandbox - .evolve(Noop::::default()) - .unwrap(); + let mut sbox = usandbox.evolve().unwrap(); // do the function call let current_time = std::time::Instant::now(); diff --git a/src/hyperlight_host/examples/tracing/main.rs b/src/hyperlight_host/examples/tracing/main.rs index dfc680576..66020dcfa 100644 --- a/src/hyperlight_host/examples/tracing/main.rs +++ b/src/hyperlight_host/examples/tracing/main.rs @@ -19,11 +19,8 @@ extern crate hyperlight_host; use std::sync::{Arc, Barrier}; use std::thread::{JoinHandle, spawn}; -use hyperlight_host::sandbox::Callable; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; -use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; +use hyperlight_host::{GuestBinary, Result}; use hyperlight_testing::simple_guest_as_string; use tracing_forest::ForestLayer; use tracing_subscriber::layer::SubscriberExt; @@ -76,10 +73,7 @@ fn run_example() -> Result<()> { usandbox.register_print(fn_writer)?; // Initialize the sandbox. - - let no_op = Noop::::default(); - - let mut multiuse_sandbox = usandbox.evolve(no_op)?; + let mut multiuse_sandbox = usandbox.evolve()?; // Call a guest function 5 times to generate some log entries. for _ in 0..5 { @@ -108,10 +102,7 @@ fn run_example() -> Result<()> { UninitializedSandbox::new(GuestBinary::FilePath(hyperlight_guest_path.clone()), None)?; // Initialize the sandbox. - - let no_op = Noop::::default(); - - let mut multiuse_sandbox = usandbox.evolve(no_op)?; + let mut multiuse_sandbox = usandbox.evolve()?; let interrupt_handle = multiuse_sandbox.interrupt_handle(); // Call a function that gets cancelled by the host function 5 times to generate some log entries. @@ -139,10 +130,10 @@ fn run_example() -> Result<()> { uuid = %id, ); let _entered = span.enter(); - let mut ctx = multiuse_sandbox.new_call_context(); barrier.wait(); - ctx.call::<()>("Spin", ()).unwrap_err(); - multiuse_sandbox = ctx.finish().unwrap(); + multiuse_sandbox + .call_guest_function_by_name::<()>("Spin", ()) + .unwrap_err(); } for join_handle in join_handles { diff --git a/src/hyperlight_host/src/func/call_ctx.rs b/src/hyperlight_host/src/func/call_ctx.rs deleted file mode 100644 index 168437b97..000000000 --- a/src/hyperlight_host/src/func/call_ctx.rs +++ /dev/null @@ -1,279 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -use tracing::{Span, instrument}; - -use super::{ParameterTuple, SupportedReturnType}; -use crate::mem::memory_region::MemoryRegion; -use crate::sandbox::Callable; -use crate::{MultiUseSandbox, Result}; -/// A context for calling guest functions. -/// -/// Takes ownership of an existing `MultiUseSandbox`. -/// Once created, guest function calls may be made through this and only this context -/// until it is converted back to the `MultiUseSandbox` from which it originated. -/// -/// Upon this conversion,the memory associated with the `MultiUseSandbox` it owns will be reset to the state it was in before -/// this context was created. -/// -/// Calls made through this context will cause state to be retained across calls, until such time as the context -/// is converted back to a `MultiUseSandbox` -/// -/// If dropped, the `MultiUseSandbox` from which it came will be also be dropped as it is owned by the -/// `MultiUseGuestCallContext` until it is converted back to a `MultiUseSandbox` -/// -#[derive(Debug)] -pub struct MultiUseGuestCallContext { - sbox: MultiUseSandbox, -} - -impl MultiUseGuestCallContext { - /// Take ownership of a `MultiUseSandbox` and - /// return a new `MultiUseGuestCallContext` instance. - /// - #[instrument(skip_all, parent = Span::current())] - pub fn start(sbox: MultiUseSandbox) -> Self { - Self { sbox } - } - - /// Close out the context and get back the internally-stored - /// `MultiUseSandbox`. Future contexts opened by the returned sandbox - /// will have guest state restored. - #[instrument(err(Debug), skip(self), parent = Span::current())] - pub fn finish(mut self) -> Result { - self.sbox.restore_state()?; - Ok(self.sbox) - } - /// Close out the context and get back the internally-stored - /// `MultiUseSandbox`. - /// - /// Note that this method is pub(crate) and does not reset the state of the - /// sandbox. - /// - /// It is intended to be used when evolving a MultiUseSandbox to a new state - /// and is not intended to be called publicly. It allows the state of the guest to be altered - /// during the evolution of one sandbox state to another, enabling the new state created - /// to be captured and stored in the Sandboxes state stack. - /// - pub(crate) fn finish_no_reset(self) -> MultiUseSandbox { - self.sbox - } - - /// Map a region of host memory into the sandbox. - /// - /// Depending on the host platform, there are likely alignment - /// requirements of at least one page for base and len. - /// - /// `rgn.region_type` is ignored, since guest PTEs are not created - /// for the new memory. - /// - /// # Safety - /// It is the caller's responsibility to ensure that the host side - /// of the region remains intact and is not written to until this - /// mapping is removed, either due to the destruction of the - /// sandbox or due to a state rollback - pub unsafe fn map_region(&mut self, rgn: &MemoryRegion) -> Result<()> { - unsafe { self.sbox.map_region(rgn) } - } - - /// Map the contents of a file into the guest at a particular address - /// - /// Returns the length of the mapping - pub fn map_file_cow(&mut self, fp: &std::path::Path, guest_base: u64) -> Result { - self.sbox.map_file_cow(fp, guest_base) - } -} - -impl Callable for MultiUseGuestCallContext { - /// Call the guest function called `func_name` with the given arguments - /// `args`, and expect the return value have the same type as - /// `func_ret_type`. - /// - /// Every call to a guest function through this method will be made with the same "context" - /// meaning that the guest state resulting from any previous call will be present/osbservable - /// by the guest function called. - /// - /// If you want to reset state, call `finish()` on this `MultiUseGuestCallContext` - /// and get a new one from the resulting `MultiUseSandbox` - #[instrument(err(Debug),skip(self, args),parent = Span::current())] - fn call( - &mut self, - func_name: &str, - args: impl ParameterTuple, - ) -> Result { - // we are guaranteed to be holding a lock now, since `self` can't - // exist without doing so. Since GuestCallContext is effectively - // !Send (and !Sync), we also don't need to worry about - // synchronization - - let ret = self.sbox.call_guest_function_by_name_no_reset( - func_name, - Output::TYPE, - args.into_value(), - ); - Output::from_value(ret?) - } -} - -#[cfg(test)] -mod tests { - use std::sync::mpsc::sync_channel; - use std::thread::{self, JoinHandle}; - - use hyperlight_testing::simple_guest_as_string; - - use super::MultiUseGuestCallContext; - use crate::sandbox::Callable; - use crate::sandbox_state::sandbox::EvolvableSandbox; - use crate::sandbox_state::transition::Noop; - use crate::{GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox}; - - fn new_uninit() -> Result { - let path = simple_guest_as_string().map_err(|e| { - HyperlightError::Error(format!("failed to get simple guest path ({e:?})")) - })?; - UninitializedSandbox::new(GuestBinary::FilePath(path), None) - } - - /// Test to create a `MultiUseSandbox`, then call several guest functions - /// on it across different threads. - /// - /// This test works by passing messages between threads using Rust's - /// [mpsc crate](https://doc.rust-lang.org/std/sync/mpsc). Details of this - /// interaction are as follows. - /// - /// One thread acts as the receiver (AKA: consumer) and owns the - /// `MultiUseSandbox`. This receiver fields requests from N senders - /// (AKA: producers) to make batches of calls. - /// - /// Upon receipt of a message to execute a batch, a new - /// `MultiUseGuestCallContext` is created in the receiver thread from the - /// existing `MultiUseSandbox`, and the batch is executed. - /// - /// After the batch is complete, the `MultiUseGuestCallContext` is done - /// and it is converted back to the underlying `MultiUseSandbox` - #[test] - fn test_multi_call_multi_thread() { - let (snd, recv) = sync_channel::>(0); - - // create new receiver thread and on it, begin listening for - // requests to execute batches of calls - let recv_hdl = thread::spawn(move || { - let mut sbox: MultiUseSandbox = new_uninit().unwrap().evolve(Noop::default()).unwrap(); - while let Ok(calls) = recv.recv() { - let mut ctx = sbox.new_call_context(); - for call in calls { - call.call(&mut ctx); - } - sbox = ctx.finish().unwrap(); - } - }); - - // create new sender threads - let send_handles: Vec> = (0..10) - .map(|i| { - let sender = snd.clone(); - thread::spawn(move || { - let calls = vec![ - TestFuncCall::new(move |ctx| { - let msg = format!("Hello {}", i); - let ret: String = ctx.call("Echo", msg.clone()).unwrap(); - assert_eq!(ret, msg) - }), - TestFuncCall::new(move |ctx| { - let ret: i32 = ctx.call("CallMalloc", i + 2).unwrap(); - assert_eq!(ret, i + 2) - }), - ]; - sender.send(calls).unwrap(); - }) - }) - .collect(); - - for hdl in send_handles { - hdl.join().unwrap(); - } - // after all sender threads are done, drop the sender itself - // so the receiver thread can exit. then, ensure the receiver - // thread has exited. - drop(snd); - recv_hdl.join().unwrap(); - } - - pub struct TestSandbox { - sandbox: MultiUseSandbox, - } - - impl TestSandbox { - pub fn new() -> Self { - let sbox: MultiUseSandbox = new_uninit().unwrap().evolve(Noop::default()).unwrap(); - Self { sandbox: sbox } - } - pub fn call_add_to_static_multiple_times(mut self, i: i32) -> Result { - let mut ctx = self.sandbox.new_call_context(); - let mut sum: i32 = 0; - for n in 0..i { - let result = ctx.call::("AddToStatic", n); - sum += n; - println!("{:?}", result); - let result = result.unwrap(); - assert_eq!(result, sum); - } - let result = ctx.finish(); - assert!(result.is_ok()); - self.sandbox = result.unwrap(); - Ok(self) - } - - pub fn call_add_to_static(mut self, i: i32) -> Result<()> { - for n in 0..i { - let result = self - .sandbox - .call_guest_function_by_name::("AddToStatic", n); - println!("{:?}", result); - let result = result.unwrap(); - assert_eq!(result, n); - } - Ok(()) - } - } - - #[test] - fn ensure_multiusesandbox_multi_calls_dont_reset_state() { - let sandbox = TestSandbox::new(); - let result = sandbox.call_add_to_static_multiple_times(5); - assert!(result.is_ok()); - } - - #[test] - fn ensure_multiusesandbox_single_calls_do_reset_state() { - let sandbox = TestSandbox::new(); - let result = sandbox.call_add_to_static(5); - assert!(result.is_ok()); - } - - struct TestFuncCall(Box); - - impl TestFuncCall { - fn new(f: impl FnOnce(&mut MultiUseGuestCallContext) + Send + 'static) -> Self { - TestFuncCall(Box::new(f)) - } - - fn call(self, ctx: &mut MultiUseGuestCallContext) { - (self.0)(ctx); - } - } -} diff --git a/src/hyperlight_host/src/func/mod.rs b/src/hyperlight_host/src/func/mod.rs index a0efe113e..57b69dbc4 100644 --- a/src/hyperlight_host/src/func/mod.rs +++ b/src/hyperlight_host/src/func/mod.rs @@ -14,10 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/// Context structures used to allow the user to call one or more guest -/// functions on the same Hyperlight sandbox instance, all from within the -/// same state and mutual exclusion context. -pub mod call_ctx; /// Functionality to check for errors after a guest call pub(crate) mod guest_err; /// Definitions and functionality to enable guest-to-host function calling, diff --git a/src/hyperlight_host/src/lib.rs b/src/hyperlight_host/src/lib.rs index 2c52729a5..6e5e67816 100644 --- a/src/hyperlight_host/src/lib.rs +++ b/src/hyperlight_host/src/lib.rs @@ -58,9 +58,6 @@ pub mod metrics; /// outside this file. Types from this module needed for public consumption are /// re-exported below. pub mod sandbox; -/// `trait`s and other functionality for dealing with defining sandbox -/// states and moving between them -pub mod sandbox_state; #[cfg(all(feature = "seccomp", target_os = "linux"))] pub(crate) mod seccomp; /// Signal handling for Linux @@ -85,9 +82,6 @@ pub use sandbox::is_hypervisor_present; /// The re-export for the `GuestBinary` type pub use sandbox::uninitialized::GuestBinary; -/// The re-export for the `MultiUseGuestCallContext` type` -pub use crate::func::call_ctx::MultiUseGuestCallContext; - /// The universal `Result` type used throughout the Hyperlight codebase. pub type Result = core::result::Result; diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 90cb76573..f6ce32c26 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -15,7 +15,6 @@ limitations under the License. */ use std::cmp::Ordering; -use std::sync::{Arc, Mutex}; use hyperlight_common::flatbuffer_wrappers::function_call::{ FunctionCall, validate_guest_function_call_buffer, @@ -34,7 +33,6 @@ use super::ptr::{GuestPtr, RawPtr}; use super::ptr_offset::Offset; use super::shared_mem::{ExclusiveSharedMemory, GuestSharedMemory, HostSharedMemory, SharedMemory}; use super::shared_mem_snapshot::SharedMemorySnapshot; -use crate::HyperlightError::NoMemorySnapshot; use crate::sandbox::SandboxConfiguration; use crate::sandbox::uninitialized::GuestBlob; use crate::{Result, log_then_return, new_error}; @@ -75,9 +73,6 @@ pub(crate) struct SandboxMemoryManager { pub(crate) entrypoint_offset: Offset, /// How many memory regions were mapped after sandbox creation pub(crate) mapped_rgns: u64, - /// A vector of memory snapshots that can be used to save and restore the state of the memory - /// This is used by the Rust Sandbox implementation (rather than the mem_snapshot field above which only exists to support current C API) - snapshots: Arc>>, } impl SandboxMemoryManager @@ -98,7 +93,6 @@ where load_addr, entrypoint_offset, mapped_rgns: 0, - snapshots: Arc::new(Mutex::new(Vec::new())), } } @@ -265,56 +259,28 @@ where } } - /// this function will create a memory snapshot and push it onto the stack of snapshots - /// It should be used when you want to save the state of the memory, for example, when evolving a sandbox to a new state - pub(crate) fn push_state(&mut self) -> Result<()> { - let snapshot = SharedMemorySnapshot::new(&mut self.shared_mem, self.mapped_rgns)?; - self.snapshots - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .push(snapshot); - Ok(()) + pub(crate) fn snapshot(&mut self) -> Result { + SharedMemorySnapshot::new(&mut self.shared_mem, self.mapped_rgns) } - /// this function restores a memory snapshot from the last snapshot in the list but does not pop the snapshot - /// off the stack - /// It should be used when you want to restore the state of the memory to a previous state but still want to - /// retain that state, for example after calling a function in the guest + /// This function restores a memory snapshot from a given snapshot. /// /// Returns the number of memory regions mapped into the sandbox /// that need to be unmapped in order for the restore to be /// completed. - pub(crate) fn restore_state_from_last_snapshot(&mut self) -> Result { - let mut snapshots = self - .snapshots - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?; - let last = snapshots.last_mut(); - if last.is_none() { - log_then_return!(NoMemorySnapshot); + pub(crate) fn restore_snapshot(&mut self, snapshot: &SharedMemorySnapshot) -> Result { + if self.shared_mem.mem_size() != snapshot.mem_size() { + return Err(new_error!( + "Snapshot size does not match current memory size: {} != {}", + self.shared_mem.raw_mem_size(), + snapshot.mem_size() + )); } - #[allow(clippy::unwrap_used)] // We know that last is not None because we checked it above - let snapshot = last.unwrap(); let old_rgns = self.mapped_rgns; self.mapped_rgns = snapshot.restore_from_snapshot(&mut self.shared_mem)?; Ok(old_rgns - self.mapped_rgns) } - /// this function pops the last snapshot off the stack and restores the memory to the previous state - /// It should be used when you want to restore the state of the memory to a previous state and do not need to retain that state - /// for example when devolving a sandbox to a previous state. - pub(crate) fn pop_and_restore_state_from_snapshot(&mut self) -> Result { - let last = self - .snapshots - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .pop(); - if last.is_none() { - log_then_return!(NoMemorySnapshot); - } - self.restore_state_from_last_snapshot() - } - /// Sets `addr` to the correct offset in the memory referenced by /// `shared_mem` to indicate the address of the outb pointer and context /// for calling outb function @@ -440,7 +406,6 @@ impl SandboxMemoryManager { load_addr: self.load_addr.clone(), entrypoint_offset: self.entrypoint_offset, mapped_rgns: 0, - snapshots: Arc::new(Mutex::new(Vec::new())), }, SandboxMemoryManager { shared_mem: gshm, @@ -448,7 +413,6 @@ impl SandboxMemoryManager { load_addr: self.load_addr.clone(), entrypoint_offset: self.entrypoint_offset, mapped_rgns: 0, - snapshots: Arc::new(Mutex::new(Vec::new())), }, ) } @@ -555,4 +519,25 @@ impl SandboxMemoryManager { self.layout.sandbox_memory_config.get_output_data_size(), ) } + + pub(crate) fn clear_io_buffers(&mut self) { + // Clear the output data buffer + loop { + let Ok(_) = self.shared_mem.try_pop_buffer_into::>( + self.layout.output_data_buffer_offset, + self.layout.sandbox_memory_config.get_output_data_size(), + ) else { + break; + }; + } + // Clear the input data buffer + loop { + let Ok(_) = self.shared_mem.try_pop_buffer_into::>( + self.layout.input_data_buffer_offset, + self.layout.sandbox_memory_config.get_input_data_size(), + ) else { + break; + }; + } + } } diff --git a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs index ac2bdc6b5..b7f461716 100644 --- a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs +++ b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs @@ -22,7 +22,7 @@ use crate::Result; /// A wrapper around a `SharedMemory` reference and a snapshot /// of the memory therein #[derive(Clone)] -pub(super) struct SharedMemorySnapshot { +pub(crate) struct SharedMemorySnapshot { snapshot: Vec, /// How many non-main-RAM regions were mapped when this snapshot was taken? mapped_rgns: u64, @@ -53,13 +53,16 @@ impl SharedMemorySnapshot { /// Copy the memory from the internally-stored memory snapshot /// into the internally-stored `SharedMemory` #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - pub(super) fn restore_from_snapshot( - &mut self, - shared_mem: &mut S, - ) -> Result { + pub(super) fn restore_from_snapshot(&self, shared_mem: &mut S) -> Result { shared_mem.with_exclusivity(|e| e.copy_from_slice(self.snapshot.as_slice(), 0))??; Ok(self.mapped_rgns) } + + /// Return the size of the snapshot in bytes. + #[instrument(skip_all, parent = Span::current(), level= "Trace")] + pub(super) fn mem_size(&self) -> usize { + self.snapshot.len() + } } #[cfg(test)] diff --git a/src/hyperlight_host/src/metrics/mod.rs b/src/hyperlight_host/src/metrics/mod.rs index 3181d3b89..a2f4026e5 100644 --- a/src/hyperlight_host/src/metrics/mod.rs +++ b/src/hyperlight_host/src/metrics/mod.rs @@ -93,8 +93,6 @@ mod tests { use metrics_util::CompositeKey; use super::*; - use crate::sandbox_state::sandbox::EvolvableSandbox; - use crate::sandbox_state::transition::Noop; use crate::{GuestBinary, UninitializedSandbox}; #[test] @@ -108,7 +106,7 @@ mod tests { ) .unwrap(); - let mut multi = uninit.evolve(Noop::default()).unwrap(); + let mut multi = uninit.evolve().unwrap(); let interrupt_handle = multi.interrupt_handle(); // interrupt the guest function call to "Spin" after 1 second diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index c2959262b..6208d8f85 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -28,8 +28,8 @@ use hyperlight_common::flatbuffer_wrappers::function_types::{ use tracing::{Span, instrument}; use super::host_funcs::FunctionRegistry; -use super::{MemMgrWrapper, WrapperGetter}; -use crate::func::call_ctx::MultiUseGuestCallContext; +use super::snapshot::Snapshot; +use super::{Callable, MemMgrWrapper, WrapperGetter}; use crate::func::guest_err::check_for_guest_error; use crate::func::{ParameterTuple, SupportedReturnType}; #[cfg(gdb)] @@ -42,8 +42,6 @@ use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::RawPtr; use crate::mem::shared_mem::HostSharedMemory; use crate::metrics::maybe_time_and_emit_guest_call; -use crate::sandbox_state::sandbox::{DevolvableSandbox, EvolvableSandbox, Sandbox}; -use crate::sandbox_state::transition::{MultiUseContextCallback, Noop}; use crate::{HyperlightError, Result, log_then_return}; /// A sandbox that supports being used Multiple times. @@ -94,76 +92,26 @@ impl MultiUseSandbox { } } - /// Create a new `MultiUseCallContext` suitable for making 0 or more - /// calls to guest functions within the same context. - /// - /// Since this function consumes `self`, the returned - /// `MultiUseGuestCallContext` is guaranteed mutual exclusion for calling - /// functions within the sandbox. This guarantee is enforced at compile - /// time, and no locks, atomics, or any other mutual exclusion mechanisms - /// are used at runtime. - /// - /// If you have called this function, have a `MultiUseGuestCallContext`, - /// and wish to "return" it to a `MultiUseSandbox`, call the `finish` - /// method on the context. - /// - /// Example usage (compiled as a "no_run" doctest since the test binary - /// will not be found): - /// - /// ```no_run - /// use hyperlight_host::sandbox::{UninitializedSandbox, MultiUseSandbox}; - /// use hyperlight_common::flatbuffer_wrappers::function_types::{ReturnType, ParameterValue, ReturnValue}; - /// use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; - /// use hyperlight_host::sandbox_state::transition::Noop; - /// use hyperlight_host::GuestBinary; - /// - /// // First, create a new uninitialized sandbox, then evolve it to become - /// // an initialized, single-use one. - /// let u_sbox = UninitializedSandbox::new( - /// GuestBinary::FilePath("some_guest_binary".to_string()), - /// None, - /// ).unwrap(); - /// let sbox: MultiUseSandbox = u_sbox.evolve(Noop::default()).unwrap(); - /// // Next, create a new call context from the single-use sandbox. - /// // After this line, your code will not compile if you try to use the - /// // original `sbox` variable. - /// let mut ctx = sbox.new_call_context(); - /// - /// // Do a guest call with the context. Assumes that the loaded binary - /// // ("some_guest_binary") has a function therein called "SomeGuestFunc" - /// // that takes a single integer argument and returns an integer. - /// match ctx.call( - /// "SomeGuestFunc", - /// ReturnType::Int, - /// Some(vec![ParameterValue::Int(1)]) - /// ) { - /// Ok(ReturnValue::Int(i)) => println!( - /// "got successful return value {}", - /// i, - /// ), - /// other => panic!( - /// "failed to get return value as expected ({:?})", - /// other, - /// ), - /// }; - /// // You can make further calls with the same context if you want. - /// // Otherwise, `ctx` will be dropped and all resources, including the - /// // underlying `MultiUseSandbox`, will be released and no further - /// // contexts can be created from that sandbox. - /// // - /// // If you want to avoid - /// // that behavior, call `finish` to convert the context back to - /// // the original `MultiUseSandbox`, as follows: - /// let _orig_sbox = ctx.finish(); - /// // Now, you can operate on the original sandbox again (i.e. add more - /// // host functions etc...), create new contexts, and so on. - /// ``` - #[instrument(skip_all, parent = Span::current())] - pub fn new_call_context(self) -> MultiUseGuestCallContext { - MultiUseGuestCallContext::start(self) + /// Create a snapshot of the current state of the sandbox's memory. + #[instrument(err(Debug), skip_all, parent = Span::current())] + pub fn snapshot(&mut self) -> Result { + let snapshot = self.mem_mgr.unwrap_mgr_mut().snapshot()?; + Ok(Snapshot { inner: snapshot }) + } + + /// Restore the sandbox's memory to the state captured in the given snapshot. + #[instrument(err(Debug), skip_all, parent = Span::current())] + pub fn restore(&mut self, snapshot: &Snapshot) -> Result<()> { + let rgns_to_unmap = self + .mem_mgr + .unwrap_mgr_mut() + .restore_snapshot(&snapshot.inner)?; + unsafe { self.vm.unmap_regions(rgns_to_unmap)? }; + Ok(()) } /// Call a guest function by name, with the given return type and arguments. + /// The changes made to the sandbox are persisted #[instrument(err(Debug), skip(self, args), parent = Span::current())] pub fn call_guest_function_by_name( &mut self, @@ -176,7 +124,6 @@ impl MultiUseSandbox { Output::TYPE, args.into_value(), ); - self.restore_state()?; Output::from_value(ret?) }) } @@ -260,56 +207,52 @@ impl MultiUseSandbox { args: Vec, ) -> Result { maybe_time_and_emit_guest_call(func_name, || { - let ret = self.call_guest_function_by_name_no_reset(func_name, ret_type, args); - self.restore_state()?; - ret + self.call_guest_function_by_name_no_reset(func_name, ret_type, args) }) } - /// Restore the Sandbox's state - #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - pub(crate) fn restore_state(&mut self) -> Result<()> { - let mem_mgr = self.mem_mgr.unwrap_mgr_mut(); - let rgns_to_unmap = mem_mgr.restore_state_from_last_snapshot()?; - unsafe { self.vm.unmap_regions(rgns_to_unmap)? }; - Ok(()) - } - - pub(crate) fn call_guest_function_by_name_no_reset( + fn call_guest_function_by_name_no_reset( &mut self, function_name: &str, return_type: ReturnType, args: Vec, ) -> Result { - let fc = FunctionCall::new( - function_name.to_string(), - Some(args), - FunctionCallType::Guest, - return_type, - ); - - let buffer: Vec = fc - .try_into() - .map_err(|_| HyperlightError::Error("Failed to serialize FunctionCall".to_string()))?; - - self.get_mgr_wrapper_mut() - .as_mut() - .write_guest_function_call(&buffer)?; - - self.vm.dispatch_call_from_host( - self.dispatch_ptr.clone(), - self.out_hdl.clone(), - self.mem_hdl.clone(), - #[cfg(gdb)] - self.dbg_mem_access_fn.clone(), - )?; + let res = (|| { + let fc = FunctionCall::new( + function_name.to_string(), + Some(args), + FunctionCallType::Guest, + return_type, + ); + + let buffer: Vec = fc.try_into().map_err(|_| { + HyperlightError::Error("Failed to serialize FunctionCall".to_string()) + })?; + + self.get_mgr_wrapper_mut() + .as_mut() + .write_guest_function_call(&buffer)?; + + self.vm.dispatch_call_from_host( + self.dispatch_ptr.clone(), + self.out_hdl.clone(), + self.mem_hdl.clone(), + #[cfg(gdb)] + self.dbg_mem_access_fn.clone(), + )?; - self.check_stack_guard()?; - check_for_guest_error(self.get_mgr_wrapper_mut())?; + self.mem_mgr.check_stack_guard()?; + check_for_guest_error(self.get_mgr_wrapper_mut())?; - self.get_mgr_wrapper_mut() - .as_mut() - .get_guest_function_call_result() + self.get_mgr_wrapper_mut() + .as_mut() + .get_guest_function_call_result() + })(); + + // TODO: Do we want to allow re-entrant guest function calls? + self.get_mgr_wrapper_mut().as_mut().clear_io_buffers(); + + res } /// Get a handle to the interrupt handler for this sandbox, @@ -319,6 +262,16 @@ impl MultiUseSandbox { } } +impl Callable for MultiUseSandbox { + fn call( + &mut self, + func_name: &str, + args: impl ParameterTuple, + ) -> Result { + self.call_guest_function_by_name(func_name, args) + } +} + impl WrapperGetter for MultiUseSandbox { fn get_mgr_wrapper(&self) -> &MemMgrWrapper { &self.mem_mgr @@ -328,12 +281,6 @@ impl WrapperGetter for MultiUseSandbox { } } -impl Sandbox for MultiUseSandbox { - fn check_stack_guard(&self) -> Result { - self.mem_mgr.check_stack_guard() - } -} - impl std::fmt::Debug for MultiUseSandbox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MultiUseSandbox") @@ -342,58 +289,6 @@ impl std::fmt::Debug for MultiUseSandbox { } } -impl DevolvableSandbox> - for MultiUseSandbox -{ - /// Consume `self` and move it back to a `MultiUseSandbox` with previous state. - /// - /// The purpose of this function is to allow multiple states to be associated with a single MultiUseSandbox. - /// - /// An implementation such as HyperlightJs or HyperlightWasm can use this to call guest functions to load JS or WASM code and then evolve the sandbox causing state to be captured. - /// The new MultiUseSandbox can then be used to call guest functions to execute the loaded code. - /// The devolve can be used to return the MultiUseSandbox to the state before the code was loaded. Thus avoiding initialisation overhead - #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - fn devolve(mut self, _tsn: Noop) -> Result { - let rgns_to_unmap = self - .mem_mgr - .unwrap_mgr_mut() - .pop_and_restore_state_from_snapshot()?; - unsafe { self.vm.unmap_regions(rgns_to_unmap)? }; - Ok(self) - } -} - -impl<'a, F> - EvolvableSandbox< - MultiUseSandbox, - MultiUseSandbox, - MultiUseContextCallback<'a, MultiUseSandbox, F>, - > for MultiUseSandbox -where - F: FnOnce(&mut MultiUseGuestCallContext) -> Result<()> + 'a, -{ - /// The purpose of this function is to allow multiple states to be associated with a single MultiUseSandbox. - /// - /// An implementation such as HyperlightJs or HyperlightWasm can use this to call guest functions to load JS or WASM code and then evolve the sandbox causing state to be captured. - /// The new MultiUseSandbox can then be used to call guest functions to execute the loaded code. - /// - /// The evolve function creates a new MultiUseCallContext which is then passed to a callback function allowing the - /// callback function to call guest functions as part of the evolve process, once the callback function is complete - /// the context is finished using a crate internal method that does not restore the prior state of the Sandbox. - /// It then creates a mew memory snapshot on the snapshot stack and returns the MultiUseSandbox - #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - fn evolve( - self, - transition_func: MultiUseContextCallback<'a, MultiUseSandbox, F>, - ) -> Result { - let mut ctx = self.new_call_context(); - transition_func.call(&mut ctx)?; - let mut sbox = ctx.finish_no_reset(); - sbox.mem_mgr.unwrap_mgr_mut().push_state()?; - Ok(sbox) - } -} - #[cfg(test)] mod tests { use std::sync::{Arc, Barrier}; @@ -401,14 +296,11 @@ mod tests { use hyperlight_testing::simple_guest_as_string; - use crate::func::call_ctx::MultiUseGuestCallContext; #[cfg(target_os = "linux")] use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags, MemoryRegionType}; #[cfg(target_os = "linux")] use crate::mem::shared_mem::{ExclusiveSharedMemory, GuestSharedMemory, SharedMemory as _}; use crate::sandbox::{Callable, SandboxConfiguration}; - use crate::sandbox_state::sandbox::{DevolvableSandbox, EvolvableSandbox}; - use crate::sandbox_state::transition::{MultiUseContextCallback, Noop}; use crate::{GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox}; // Tests to ensure that many (1000) function calls can be made in a call context with a small stack (1K) and heap(14K). @@ -419,58 +311,56 @@ mod tests { cfg.set_heap_size(20 * 1024); cfg.set_stack_size(16 * 1024); - let sbox1: MultiUseSandbox = { + let mut sbox1: MultiUseSandbox = { let path = simple_guest_as_string().unwrap(); let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), Some(cfg)).unwrap(); - u_sbox.evolve(Noop::default()) + u_sbox.evolve() } .unwrap(); - let mut ctx = sbox1.new_call_context(); - for _ in 0..1000 { - ctx.call::("Echo", "hello".to_string()).unwrap(); + sbox1.call::("Echo", "hello".to_string()).unwrap(); } - let sbox2: MultiUseSandbox = { + let mut sbox2: MultiUseSandbox = { let path = simple_guest_as_string().unwrap(); let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), Some(cfg)).unwrap(); - u_sbox.evolve(Noop::default()) + u_sbox.evolve() } .unwrap(); - let mut ctx = sbox2.new_call_context(); - for i in 0..1000 { - ctx.call::( - "PrintUsingPrintf", - format!("Hello World {}\n", i).to_string(), - ) - .unwrap(); + sbox2 + .call::( + "PrintUsingPrintf", + format!("Hello World {}\n", i).to_string(), + ) + .unwrap(); } } /// Tests that evolving from MultiUseSandbox to MultiUseSandbox creates a new state - /// and devolving from MultiUseSandbox to MultiUseSandbox restores the previous state + /// and restoring a snapshot from before evolving restores the previous state #[test] - fn evolve_devolve_handles_state_correctly() { - let sbox1: MultiUseSandbox = { + fn snapshot_evolve_restore_handles_state_correctly() { + let mut sbox: MultiUseSandbox = { let path = simple_guest_as_string().unwrap(); let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap(); - u_sbox.evolve(Noop::default()) + u_sbox.evolve() } .unwrap(); - let func = Box::new(|call_ctx: &mut MultiUseGuestCallContext| { - call_ctx.call::("AddToStatic", 5i32)?; - Ok(()) - }); - let transition_func = MultiUseContextCallback::from(func); - let mut sbox2 = sbox1.evolve(transition_func).unwrap(); - let res: i32 = sbox2.call_guest_function_by_name("GetStatic", ()).unwrap(); + let snapshot = sbox.snapshot().unwrap(); + + let _ = sbox + .call_guest_function_by_name::("AddToStatic", 5i32) + .unwrap(); + + let res: i32 = sbox.call_guest_function_by_name("GetStatic", ()).unwrap(); assert_eq!(res, 5); - let mut sbox3: MultiUseSandbox = sbox2.devolve(Noop::default()).unwrap(); - let res: i32 = sbox3.call_guest_function_by_name("GetStatic", ()).unwrap(); + + sbox.restore(&snapshot).unwrap(); + let res: i32 = sbox.call_guest_function_by_name("GetStatic", ()).unwrap(); assert_eq!(res, 0); } @@ -494,7 +384,7 @@ mod tests { usbox.register("MakeGetpidSyscall", make_get_pid_syscall)?; - let mut sbox: MultiUseSandbox = usbox.evolve(Noop::default())?; + let mut sbox: MultiUseSandbox = usbox.evolve()?; let res: Result = sbox.call_guest_function_by_name("ViolateSeccompFilters", ()); @@ -530,7 +420,7 @@ mod tests { )?; // ^^^ note, we are allowing SYS_getpid - let mut sbox: MultiUseSandbox = usbox.evolve(Noop::default())?; + let mut sbox: MultiUseSandbox = usbox.evolve()?; let res: Result = sbox.call_guest_function_by_name("ViolateSeccompFilters", ()); @@ -584,7 +474,7 @@ mod tests { .unwrap(); ubox.register("Openat_Hostfunc", make_openat_syscall)?; - let mut sbox = ubox.evolve(Noop::default()).unwrap(); + let mut sbox = ubox.evolve().unwrap(); let host_func_result = sbox .call_guest_function_by_name::( "CallGivenParamlessHostFuncThatReturnsI64", @@ -614,7 +504,7 @@ mod tests { make_openat_syscall, [libc::SYS_openat], )?; - let mut sbox = ubox.evolve(Noop::default()).unwrap(); + let mut sbox = ubox.evolve().unwrap(); let host_func_result = sbox .call_guest_function_by_name::( "CallGivenParamlessHostFuncThatReturnsI64", @@ -637,7 +527,7 @@ mod tests { ) .unwrap(); - let mut multi_use_sandbox: MultiUseSandbox = usbox.evolve(Noop::default()).unwrap(); + let mut multi_use_sandbox: MultiUseSandbox = usbox.evolve().unwrap(); let res: Result<()> = multi_use_sandbox.call_guest_function_by_name("TriggerException", ()); @@ -677,8 +567,7 @@ mod tests { ) .unwrap(); - let mut multi_use_sandbox: MultiUseSandbox = - usbox.evolve(Noop::default()).unwrap(); + let mut multi_use_sandbox: MultiUseSandbox = usbox.evolve().unwrap(); let res: i32 = multi_use_sandbox .call_guest_function_by_name("GetStatic", ()) @@ -706,7 +595,7 @@ mod tests { None, ) .unwrap() - .evolve(Noop::default()) + .evolve() .unwrap(); let expected = b"hello world"; diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index c6e33c84b..07389c369 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -37,6 +37,9 @@ pub mod uninitialized; /// initialized `Sandbox`es. pub(crate) mod uninitialized_evolve; +/// Representation of a snapshot of a `Sandbox`. +pub mod snapshot; + /// Trait used by the macros to paper over the differences between hyperlight and hyperlight-wasm mod callable; @@ -101,8 +104,6 @@ mod tests { use hyperlight_testing::simple_guest_as_string; use crate::sandbox::uninitialized::GuestBinary; - use crate::sandbox_state::sandbox::EvolvableSandbox; - use crate::sandbox_state::transition::Noop; use crate::{MultiUseSandbox, UninitializedSandbox, new_error}; #[test] @@ -163,11 +164,9 @@ mod tests { )) .unwrap(); - let sandbox = uninitialized_sandbox - .evolve(Noop::default()) - .unwrap_or_else(|_| { - panic!("Failed to initialize UninitializedSandbox thread {}", i) - }); + let sandbox = uninitialized_sandbox.evolve().unwrap_or_else(|_| { + panic!("Failed to initialize UninitializedSandbox thread {}", i) + }); sq.push(sandbox).unwrap_or_else(|_| { panic!("Failed to push UninitializedSandbox thread {}", i) diff --git a/src/hyperlight_host/src/sandbox_state/mod.rs b/src/hyperlight_host/src/sandbox/snapshot.rs similarity index 63% rename from src/hyperlight_host/src/sandbox_state/mod.rs rename to src/hyperlight_host/src/sandbox/snapshot.rs index 474cad72a..d91f52437 100644 --- a/src/hyperlight_host/src/sandbox_state/mod.rs +++ b/src/hyperlight_host/src/sandbox/snapshot.rs @@ -1,5 +1,5 @@ /* -Copyright 2025 The Hyperlight Authors. +Copyright 2025 The Hyperlight Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,8 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -/// The standardized `Sandbox` trait and the ways it ban be transitioned -/// to a different `Sandbox` trait -pub mod sandbox; -/// Metadata about transitions between `Sandbox` states -pub mod transition; +use crate::mem::shared_mem_snapshot::SharedMemorySnapshot; + +/// A snapshot capturing the state of the memory in a `MultiUseSandbox`. +#[derive(Clone)] +pub struct Snapshot { + /// TODO: Use Arc + pub(crate) inner: SharedMemorySnapshot, +} diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index e27f91ff2..f5149f5cc 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -34,9 +34,7 @@ use crate::mem::memory_region::{DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegionFlags} use crate::mem::mgr::{STACK_COOKIE_LEN, SandboxMemoryManager}; use crate::mem::shared_mem::ExclusiveSharedMemory; use crate::sandbox::SandboxConfiguration; -use crate::sandbox_state::sandbox::EvolvableSandbox; -use crate::sandbox_state::transition::Noop; -use crate::{MultiUseSandbox, Result, log_then_return, new_error}; +use crate::{MultiUseSandbox, Result, new_error}; #[cfg(all(target_os = "linux", feature = "seccomp"))] const EXTRA_ALLOWED_SYSCALLS_FOR_WRITER_FUNC: &[super::ExtraAllowedSyscall] = &[ @@ -82,18 +80,6 @@ pub struct UninitializedSandbox { pub(crate) rt_cfg: SandboxRuntimeConfig, } -impl crate::sandbox_state::sandbox::UninitializedSandbox for UninitializedSandbox { - #[instrument(skip_all, parent = Span::current(), level = "Trace")] - fn get_uninitialized_sandbox(&self) -> &crate::sandbox::UninitializedSandbox { - self - } - - #[instrument(skip_all, parent = Span::current(), level = "Trace")] - fn get_uninitialized_sandbox_mut(&mut self) -> &mut crate::sandbox::UninitializedSandbox { - self - } -} - impl Debug for UninitializedSandbox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("UninitializedSandbox") @@ -102,24 +88,10 @@ impl Debug for UninitializedSandbox { } } -impl crate::sandbox_state::sandbox::Sandbox for UninitializedSandbox { - fn check_stack_guard(&self) -> Result { - log_then_return!( - "Checking the stack cookie before the sandbox is initialized is unsupported" - ); - } -} - -impl - EvolvableSandbox< - UninitializedSandbox, - MultiUseSandbox, - Noop, - > for UninitializedSandbox -{ +impl UninitializedSandbox { /// Evolve `self` to a `MultiUseSandbox` without any additional metadata. #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - fn evolve(self, _: Noop) -> Result { + pub fn evolve(self) -> Result { evolve_impl_multi_use(self) } } @@ -433,8 +405,6 @@ mod tests { use crate::sandbox::SandboxConfiguration; use crate::sandbox::uninitialized::{GuestBinary, GuestEnvironment}; - use crate::sandbox_state::sandbox::EvolvableSandbox; - use crate::sandbox_state::transition::Noop; use crate::{MultiUseSandbox, Result, UninitializedSandbox, new_error}; #[test] @@ -445,7 +415,7 @@ mod tests { GuestEnvironment::new(GuestBinary::FilePath(binary_path.clone()), Some(&buffer)); let uninitialized_sandbox = UninitializedSandbox::new(guest_env, None).unwrap(); - let mut sandbox: MultiUseSandbox = uninitialized_sandbox.evolve(Noop::default()).unwrap(); + let mut sandbox: MultiUseSandbox = uninitialized_sandbox.evolve().unwrap(); let res = sandbox .call_guest_function_by_name::>("ReadFromUserMemory", (4u64, buffer.to_vec())) @@ -489,7 +459,7 @@ mod tests { // Get a Sandbox from an uninitialized sandbox without a call back function - let _sandbox: MultiUseSandbox = uninitialized_sandbox.evolve(Noop::default()).unwrap(); + let _sandbox: MultiUseSandbox = uninitialized_sandbox.evolve().unwrap(); // Test with a valid guest binary buffer @@ -537,7 +507,7 @@ mod tests { usbox.register("test0", |arg: i32| Ok(arg + 1)).unwrap(); - let sandbox: Result = usbox.evolve(Noop::default()); + let sandbox: Result = usbox.evolve(); assert!(sandbox.is_ok()); let sandbox = sandbox.unwrap(); @@ -562,7 +532,7 @@ mod tests { usbox.register("test1", |a: i32, b: i32| Ok(a + b)).unwrap(); - let sandbox: Result = usbox.evolve(Noop::default()); + let sandbox: Result = usbox.evolve(); assert!(sandbox.is_ok()); let sandbox = sandbox.unwrap(); @@ -595,7 +565,7 @@ mod tests { }) .unwrap(); - let sandbox: Result = usbox.evolve(Noop::default()); + let sandbox: Result = usbox.evolve(); assert!(sandbox.is_ok()); let sandbox = sandbox.unwrap(); @@ -613,7 +583,7 @@ mod tests { // calling a function that doesn't exist { let usbox = uninitialized_sandbox(); - let sandbox: Result = usbox.evolve(Noop::default()); + let sandbox: Result = usbox.evolve(); assert!(sandbox.is_ok()); let sandbox = sandbox.unwrap(); @@ -836,11 +806,9 @@ mod tests { .host_print(format!("Print from UninitializedSandbox on Thread {}\n", i)) .unwrap(); - let sandbox = uninitialized_sandbox - .evolve(Noop::default()) - .unwrap_or_else(|_| { - panic!("Failed to initialize UninitializedSandbox thread {}", i) - }); + let sandbox = uninitialized_sandbox.evolve().unwrap_or_else(|_| { + panic!("Failed to initialize UninitializedSandbox thread {}", i) + }); sq.push(sandbox).unwrap_or_else(|_| { panic!("Failed to push UninitializedSandbox thread {}", i) @@ -1128,7 +1096,7 @@ mod tests { ); res.unwrap() }; - let _: Result = sbox.evolve(Noop::default()); + let _: Result = sbox.evolve(); let num_calls = TEST_LOGGER.num_log_calls(); diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index 6e97c4a9a..696eb92a1 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -41,7 +41,6 @@ use crate::sandbox::host_funcs::FunctionRegistry; use crate::sandbox::mem_access::mem_access_handler_wrapper; use crate::sandbox::outb::outb_handler_wrapper; use crate::sandbox::{HostSharedMemory, MemMgrWrapper}; -use crate::sandbox_state::sandbox::Sandbox; #[cfg(target_os = "linux")] use crate::signal_handlers::setup_signal_handlers; use crate::{MultiUseSandbox, Result, UninitializedSandbox, log_then_return, new_error}; @@ -58,7 +57,7 @@ use crate::{MultiUseSandbox, Result, UninitializedSandbox, log_then_return, new_ /// If this doesn't make sense, and you want to change this type, /// please reach out to a Hyperlight developer before making the change. #[instrument(err(Debug), skip_all, , parent = Span::current(), level = "Trace")] -fn evolve_impl( +fn evolve_impl( u_sbox: UninitializedSandbox, transform: TransformFunc, ) -> Result @@ -127,24 +126,20 @@ where #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] pub(super) fn evolve_impl_multi_use(u_sbox: UninitializedSandbox) -> Result { - evolve_impl( - u_sbox, - |hf, mut hshm, vm, out_hdl, mem_hdl, dispatch_ptr| { - { - hshm.as_mut().push_state()?; - } - Ok(MultiUseSandbox::from_uninit( - hf, - hshm.clone(), - vm, - out_hdl, - mem_hdl, - dispatch_ptr, - #[cfg(gdb)] - dbg_mem_access_handler_wrapper(hshm), - )) - }, - ) + evolve_impl(u_sbox, |hf, hshm, vm, out_hdl, mem_hdl, dispatch_ptr| { + #[cfg(gdb)] + let dbg_mem_wrapper = dbg_mem_access_handler_wrapper(hshm.clone()); + Ok(MultiUseSandbox::from_uninit( + hf, + hshm, + vm, + out_hdl, + mem_hdl, + dispatch_ptr, + #[cfg(gdb)] + dbg_mem_wrapper, + )) + }) } pub(crate) fn set_up_hypervisor_partition( diff --git a/src/hyperlight_host/src/sandbox_state/sandbox.rs b/src/hyperlight_host/src/sandbox_state/sandbox.rs deleted file mode 100644 index 4f9641af8..000000000 --- a/src/hyperlight_host/src/sandbox_state/sandbox.rs +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -use std::fmt::Debug; - -use tracing::{Span, instrument}; - -use super::transition::TransitionMetadata; -use crate::{Result, new_error}; - -/// The minimal functionality of a Hyperlight sandbox. Most of the types -/// and operations within this crate require `Sandbox` implementations. -/// -/// `Sandbox`es include the notion of an ordering in a state machine. -/// For example, a given `Sandbox` implementation may be the root node -/// in the state machine to which it belongs, and it may know how to "evolve" -/// into a next state. That "next state" may in turn know how to roll back -/// to the root node. -/// -/// These transitions are expressed as `EvolvableSandbox` and -/// `DevolvableSandbox` implementations any `Sandbox` implementation can -/// opt into. -pub trait Sandbox: Sized + Debug { - /// Check to ensure the current stack cookie matches the one that - /// was selected when the stack was constructed. - /// - /// Return an `Err` if there was an error inspecting the stack, `Ok(false)` - /// if there was no such error but the stack guard doesn't match, and - /// `Ok(true)` in the same situation where the stack guard does match. - /// - - // NOTE: this is only needed for UninitializedSandbox and MultiUseSandbox - // Those are the only types that need implement this trait - // The default implementation is provided so that types that implement Sandbox (e.g. JSSandbox) but do not need to implement this trait do not need to provide an implementation - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - fn check_stack_guard(&self) -> Result { - Err(new_error!( - "check_stack_guard not implemented for this type" - )) - } -} - -/// A utility trait to recognize a Sandbox that has not yet been initialized. -/// It allows retrieval of a strongly typed UninitializedSandbox. -pub trait UninitializedSandbox: Sandbox { - /// Retrieves reference to strongly typed `UninitializedSandbox` - fn get_uninitialized_sandbox(&self) -> &crate::sandbox::UninitializedSandbox; - - /// Retrieves mutable reference to strongly typed `UninitializedSandbox` - fn get_uninitialized_sandbox_mut(&mut self) -> &mut crate::sandbox::UninitializedSandbox; -} - -/// A `Sandbox` that knows how to "evolve" into a next state. -pub trait EvolvableSandbox>: - Sandbox -{ - /// Evolve `Self` to `Next` providing Metadata. - fn evolve(self, tsn: T) -> Result; -} - -/// A `Sandbox` that knows how to roll back to a "previous" `Sandbox` -pub trait DevolvableSandbox>: - Sandbox -{ - /// Devolve `Self` to `Prev` providing Metadata. - fn devolve(self, tsn: T) -> Result; -} diff --git a/src/hyperlight_host/src/sandbox_state/transition.rs b/src/hyperlight_host/src/sandbox_state/transition.rs deleted file mode 100644 index 3cd7aaadf..000000000 --- a/src/hyperlight_host/src/sandbox_state/transition.rs +++ /dev/null @@ -1,178 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -use std::marker::PhantomData; - -use tracing::{Span, instrument}; - -use super::sandbox::Sandbox; -use crate::Result; -use crate::func::call_ctx::MultiUseGuestCallContext; - -/// Metadata about an evolution or devolution. Any `Sandbox` implementation -/// that also implements `EvolvableSandbox` or `DevolvableSandbox` -/// can decide the following things in a type-safe way: -/// -/// 1. That transition is possible -/// 2. That transition requires a specific kind of metadata -/// -/// For example, if you have the following structs: -/// -/// ```ignore -/// struct MySandbox1 {} -/// struct MySandbox2 {} -/// -/// impl Sandbox for MySandbox1 {...} -/// impl Sandbox for MySandbox2 {...} -/// ``` -/// -/// ...then you can define a metadata-free evolve transition between -/// `MySandbox1` and `MySandbox2`, and a devolve transition that requires -/// a callback between `MySandbox2` and `MySandbox` as follows: -/// -/// ```ignore -/// impl EvolvableSandbox< -/// MySandbox1, -/// MySandbox2, -/// Noop -/// > for MySandbox1 { -/// fn evolve( -/// self, -/// _: Noop -/// ) -> Result { -/// Ok(MySandbox2{}) -/// } -/// } -/// -/// ``` -/// -/// Most transitions will likely involve `Noop`, but some may involve -/// implementing their own. -pub trait TransitionMetadata {} - -/// Transition metadata that contains and does nothing. `Noop` is a -/// placeholder when you want to implement an `EvolvableSandbox` -/// or `DevolvableSandbox` that needs no additional metadata to succeed. -/// -/// Construct one of these by using the `default()` method. -pub struct Noop { - cur_ph: PhantomData, - next_ph: PhantomData, -} - -impl Default for Noop { - fn default() -> Self { - Self { - cur_ph: PhantomData, - next_ph: PhantomData, - } - } -} - -impl TransitionMetadata for Noop {} - -/// A `TransitionMetadata` that calls a callback. The callback function takes -/// a mutable reference to a `MultiUseGuestCallContext` and returns a `Result<()>` -/// to signify success or failure of the function. -/// -/// The function use the context to call guest functions. -/// -/// Construct one of these by passing your callback to -/// `MultiUseContextCallback::from`, as in the following code (assuming `MySandbox` -/// is a `Sandbox` implementation): -/// -/// ```ignore -/// let my_cb_fn: dyn FnOnce(&mut MultiUseGuestCallContext) -> Result<()> = |_sbox| { -/// println!("hello world!"); -/// }; -/// let mutating_cb = MultiUseContextCallback::from(my_cb_fn); -/// ``` -pub struct MultiUseContextCallback<'func, Cur: Sandbox, F> -where - F: FnOnce(&mut MultiUseGuestCallContext) -> Result<()> + 'func, -{ - cur_ph: PhantomData, - fn_life_ph: PhantomData<&'func ()>, - cb: F, -} - -impl TransitionMetadata - for MultiUseContextCallback<'_, Cur, F> -where - F: FnOnce(&mut MultiUseGuestCallContext) -> Result<()>, -{ -} - -impl MultiUseContextCallback<'_, Cur, F> -where - F: FnOnce(&mut MultiUseGuestCallContext) -> Result<()>, -{ - /// Invokes the callback on the provided guest context - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - pub fn call(self, cur: &mut MultiUseGuestCallContext) -> Result<()> { - (self.cb)(cur) - } -} - -impl<'a, Cur: Sandbox, F> From for MultiUseContextCallback<'a, Cur, F> -where - F: FnOnce(&mut MultiUseGuestCallContext) -> Result<()> + 'a, -{ - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - fn from(val: F) -> Self { - MultiUseContextCallback { - cur_ph: PhantomData, - fn_life_ph: PhantomData, - cb: val, - } - } -} -#[cfg(test)] -mod tests { - use super::Noop; - use crate::Result; - use crate::sandbox_state::sandbox::{DevolvableSandbox, EvolvableSandbox, Sandbox}; - - #[derive(Debug, Eq, PartialEq, Clone)] - struct MySandbox1 {} - #[derive(Debug, Eq, PartialEq, Clone)] - struct MySandbox2 {} - - impl Sandbox for MySandbox1 {} - impl Sandbox for MySandbox2 {} - - impl EvolvableSandbox> for MySandbox1 { - fn evolve(self, _: Noop) -> Result { - Ok(MySandbox2 {}) - } - } - - impl DevolvableSandbox> for MySandbox2 { - fn devolve(self, _: Noop) -> Result { - Ok(MySandbox1 {}) - } - } - - #[test] - fn test_evolve_devolve() { - let sbox_1_1 = MySandbox1 {}; - let sbox_2_1 = sbox_1_1.clone().evolve(Noop::default()).unwrap(); - let sbox_1_2 = sbox_2_1.clone().devolve(Noop::default()).unwrap(); - let sbox_2_2 = sbox_1_2.clone().evolve(Noop::default()).unwrap(); - assert_eq!(sbox_1_1, sbox_1_2); - assert_eq!(sbox_2_1, sbox_2_2); - } -} diff --git a/src/hyperlight_host/tests/common/mod.rs b/src/hyperlight_host/tests/common/mod.rs index b3d465bf3..39d08a3e5 100644 --- a/src/hyperlight_host/tests/common/mod.rs +++ b/src/hyperlight_host/tests/common/mod.rs @@ -14,8 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ use hyperlight_host::func::HostFunction; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, MultiUseSandbox, Result, UninitializedSandbox}; use hyperlight_testing::{ c_callback_guest_as_string, c_simple_guest_as_string, callback_guest_as_string, @@ -56,7 +54,7 @@ pub fn get_simpleguest_sandboxes( if let Some(writer) = writer.clone() { sandbox.register_print(writer).unwrap(); } - sandbox.evolve(Noop::default()).unwrap() + sandbox.evolve().unwrap() }) .collect() } diff --git a/src/hyperlight_host/tests/integration_test.rs b/src/hyperlight_host/tests/integration_test.rs index 2db32b4a0..967d93c53 100644 --- a/src/hyperlight_host/tests/integration_test.rs +++ b/src/hyperlight_host/tests/integration_test.rs @@ -22,8 +22,6 @@ use std::time::Duration; use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_common::mem::PAGE_SIZE; use hyperlight_host::sandbox::SandboxConfiguration; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, HyperlightError, MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::simplelogger::{LOGGER, SimpleLogger}; use hyperlight_testing::{ @@ -61,7 +59,7 @@ fn interrupt_host_call() { .register_with_extra_allowed_syscalls("Spin", spin, vec![libc::SYS_clock_nanosleep]) .unwrap(); - let mut sandbox: MultiUseSandbox = usbox.evolve(Noop::default()).unwrap(); + let mut sandbox: MultiUseSandbox = usbox.evolve().unwrap(); let interrupt_handle = sandbox.interrupt_handle(); assert!(!interrupt_handle.dropped()); // not yet dropped @@ -83,7 +81,7 @@ fn interrupt_host_call() { /// Makes sure a running guest call can be interrupted by the host #[test] fn interrupt_in_progress_guest_call() { - let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); let barrier = Arc::new(Barrier::new(2)); let barrier2 = barrier.clone(); let interrupt_handle = sbox1.interrupt_handle(); @@ -118,7 +116,7 @@ fn interrupt_in_progress_guest_call() { /// Makes sure interrupting a vm before the guest call has started also prevents the guest call from being executed #[test] fn interrupt_guest_call_in_advance() { - let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); let barrier = Arc::new(Barrier::new(2)); let barrier2 = barrier.clone(); let interrupt_handle = sbox1.interrupt_handle(); @@ -160,9 +158,9 @@ fn interrupt_guest_call_in_advance() { /// all possible interleavings, but can hopefully increases confidence somewhat. #[test] fn interrupt_same_thread() { - let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); - let mut sbox2: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); - let mut sbox3: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); + let mut sbox2: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); + let mut sbox3: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); let barrier = Arc::new(Barrier::new(2)); let barrier2 = barrier.clone(); @@ -202,9 +200,9 @@ fn interrupt_same_thread() { /// Same test as above but with no per-iteration barrier, to get more possible interleavings. #[test] fn interrupt_same_thread_no_barrier() { - let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); - let mut sbox2: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); - let mut sbox3: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); + let mut sbox2: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); + let mut sbox3: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); let barrier = Arc::new(Barrier::new(2)); let barrier2 = barrier.clone(); @@ -248,8 +246,8 @@ fn interrupt_same_thread_no_barrier() { // and that anther sandbox on the original thread does not get incorrectly killed #[test] fn interrupt_moved_sandbox() { - let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); - let mut sbox2: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); + let mut sbox2: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); let interrupt_handle = sbox1.interrupt_handle(); let interrupt_handle2 = sbox2.interrupt_handle(); @@ -300,7 +298,7 @@ fn interrupt_custom_signal_no_and_retry_delay() { Some(config), ) .unwrap() - .evolve(Noop::default()) + .evolve() .unwrap(); let interrupt_handle = sbox1.interrupt_handle(); @@ -340,7 +338,7 @@ fn interrupt_spamming_host_call() { // do nothing }) .unwrap(); - let mut sbox1: MultiUseSandbox = uninit.evolve(Noop::default()).unwrap(); + let mut sbox1: MultiUseSandbox = uninit.evolve().unwrap(); let interrupt_handle = sbox1.interrupt_handle(); @@ -369,7 +367,7 @@ fn print_four_args_c_guest() { let path = c_simple_guest_as_string().unwrap(); let guest_path = GuestBinary::FilePath(path); let uninit = UninitializedSandbox::new(guest_path, None); - let mut sbox1 = uninit.unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = uninit.unwrap().evolve().unwrap(); let res = sbox1.call_guest_function_by_name::( "PrintFourArgs", @@ -382,7 +380,7 @@ fn print_four_args_c_guest() { // Checks that guest can abort with a specific code. #[test] fn guest_abort() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let error_code: u8 = 13; // this is arbitrary let res = sbox1 .call_guest_function_by_name::<()>("GuestAbortWithCode", error_code as i32) @@ -395,7 +393,7 @@ fn guest_abort() { #[test] fn guest_abort_with_context1() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let res = sbox1 .call_guest_function_by_name::<()>("GuestAbortWithMessage", (25_i32, "Oh no".to_string())) @@ -408,7 +406,7 @@ fn guest_abort_with_context1() { #[test] fn guest_abort_with_context2() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); // The buffer size for the panic context is 1024 bytes. // This test will see what happens if the panic message is longer than that @@ -462,7 +460,7 @@ fn guest_abort_c_guest() { let path = c_simple_guest_as_string().unwrap(); let guest_path = GuestBinary::FilePath(path); let uninit = UninitializedSandbox::new(guest_path, None); - let mut sbox1 = uninit.unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = uninit.unwrap().evolve().unwrap(); let res = sbox1 .call_guest_function_by_name::<()>( @@ -479,7 +477,7 @@ fn guest_abort_c_guest() { #[test] fn guest_panic() { // this test is rust-specific - let mut sbox1 = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let res = sbox1 .call_guest_function_by_name::<()>("guest_panic", "Error... error...".to_string()) @@ -493,7 +491,7 @@ fn guest_panic() { #[test] fn guest_malloc() { // this test is rust-only - let mut sbox1 = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let size_to_allocate = 2000_i32; sbox1 @@ -503,7 +501,7 @@ fn guest_malloc() { #[test] fn guest_allocate_vec() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let size_to_allocate = 2000_i32; @@ -520,7 +518,7 @@ fn guest_allocate_vec() { // checks that malloc failures are captured correctly #[test] fn guest_malloc_abort() { - let mut sbox1 = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let size = 20000000_i32; // some big number that should fail when allocated @@ -544,7 +542,7 @@ fn guest_malloc_abort() { Some(cfg), ) .unwrap(); - let mut sbox2 = uninit.evolve(Noop::default()).unwrap(); + let mut sbox2 = uninit.evolve().unwrap(); let res = sbox2.call_guest_function_by_name::( "CallMalloc", // uses the rust allocator to allocate a vector on heap @@ -564,7 +562,7 @@ fn dynamic_stack_allocate_c_guest() { let path = c_simple_guest_as_string().unwrap(); let guest_path = GuestBinary::FilePath(path); let uninit = UninitializedSandbox::new(guest_path, None); - let mut sbox1: MultiUseSandbox = uninit.unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1: MultiUseSandbox = uninit.unwrap().evolve().unwrap(); let res: i32 = sbox1 .call_guest_function_by_name("StackAllocate", 100_i32) @@ -580,7 +578,7 @@ fn dynamic_stack_allocate_c_guest() { // checks that a small buffer on stack works #[test] fn static_stack_allocate() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let res: i32 = sbox1.call_guest_function_by_name("SmallVar", ()).unwrap(); assert_eq!(res, 1024); @@ -589,7 +587,7 @@ fn static_stack_allocate() { // checks that a huge buffer on stack fails with stackoverflow #[test] fn static_stack_allocate_overflow() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let res = sbox1 .call_guest_function_by_name::("LargeVar", ()) .unwrap_err(); @@ -599,7 +597,7 @@ fn static_stack_allocate_overflow() { // checks that a recursive function with stack allocation works, (that chkstk can be called without overflowing) #[test] fn recursive_stack_allocate() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let iterations = 1_i32; @@ -629,7 +627,7 @@ fn guard_page_check() { for offset in offsets_from_page_guard_start { // we have to create a sandbox each iteration because can't reuse after MMIO error in release mode - let mut sbox1 = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let result = sbox1.call_guest_function_by_name::("test_write_raw_ptr", offset); if guard_range.contains(&offset) { // should have failed @@ -646,7 +644,7 @@ fn guard_page_check() { #[test] fn guard_page_check_2() { // this test is rust-guest only - let mut sbox1 = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let result = sbox1 .call_guest_function_by_name::<()>("InfiniteRecursion", ()) @@ -656,7 +654,7 @@ fn guard_page_check_2() { #[test] fn execute_on_stack() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let result = sbox1 .call_guest_function_by_name::("ExecuteOnStack", ()) @@ -672,7 +670,7 @@ fn execute_on_stack() { #[test] #[ignore] // ran from Justfile because requires feature "executable_heap" fn execute_on_heap() { - let mut sbox1 = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let result = sbox1.call_guest_function_by_name::("ExecuteOnHeap", ()); println!("{:#?}", result); @@ -688,22 +686,10 @@ fn execute_on_heap() { } } -#[test] -fn memory_resets_after_failed_guestcall() { - let mut sbox1 = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); - sbox1 - .call_guest_function_by_name::("AddToStaticAndFail", ()) - .unwrap_err(); - let res = sbox1 - .call_guest_function_by_name::("GetStatic", ()) - .unwrap(); - assert_eq!(res, 0, "Expected 0, got {:?}", res); -} - // checks that a recursive function with stack allocation eventually fails with stackoverflow #[test] fn recursive_stack_allocate_overflow() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let iterations = 10_i32; @@ -778,7 +764,7 @@ fn log_test_messages(levelfilter: Option) { sbox.set_max_guest_log_level(levelfilter); } - let mut sbox1 = sbox.evolve(Noop::default()).unwrap(); + let mut sbox1 = sbox.evolve().unwrap(); let message = format!("Hello from log_message level {}", level as i32); sbox1 diff --git a/src/hyperlight_host/tests/sandbox_host_tests.rs b/src/hyperlight_host/tests/sandbox_host_tests.rs index 1c8bf92b6..7ca0ba5dc 100644 --- a/src/hyperlight_host/tests/sandbox_host_tests.rs +++ b/src/hyperlight_host/tests/sandbox_host_tests.rs @@ -20,8 +20,6 @@ use std::sync::{Arc, Mutex}; use common::new_uninit; use hyperlight_host::sandbox::{Callable, SandboxConfiguration}; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{ GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox, new_error, }; @@ -35,16 +33,16 @@ use crate::common::{get_callbackguest_uninit_sandboxes, get_simpleguest_sandboxe #[test] #[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn pass_byte_array() { - for sandbox in get_simpleguest_sandboxes(None).into_iter() { - let mut ctx = sandbox.new_call_context(); + for mut sandbox in get_simpleguest_sandboxes(None).into_iter() { const LEN: usize = 10; let bytes = vec![1u8; LEN]; - let res: Vec = ctx + let res: Vec = sandbox .call("SetByteArrayToZero", bytes.clone()) .expect("Expected VecBytes"); assert_eq!(res, [0; LEN]); - ctx.call::("SetByteArrayToZeroNoLength", bytes.clone()) + sandbox + .call::("SetByteArrayToZeroNoLength", bytes.clone()) .unwrap_err(); // missing length param } } @@ -85,7 +83,7 @@ fn float_roundtrip() { f32::NAN, -f32::NAN, ]; - let mut sandbox: MultiUseSandbox = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sandbox: MultiUseSandbox = new_uninit().unwrap().evolve().unwrap(); for f in doubles.iter() { let res: f64 = sandbox .call_guest_function_by_name("EchoDouble", *f) @@ -332,7 +330,7 @@ fn callback_test_helper() -> Result<()> { })?; // call guest function that calls host function - let mut init_sandbox: MultiUseSandbox = sandbox.evolve(Noop::default())?; + let mut init_sandbox: MultiUseSandbox = sandbox.evolve()?; let msg = "Hello world"; init_sandbox.call_guest_function_by_name::("GuestMethod1", msg.to_string())?; @@ -374,7 +372,7 @@ fn host_function_error() -> Result<()> { })?; // call guest function that calls host function - let mut init_sandbox: MultiUseSandbox = sandbox.evolve(Noop::default())?; + let mut init_sandbox: MultiUseSandbox = sandbox.evolve()?; let msg = "Hello world"; let res = init_sandbox .call_guest_function_by_name::("GuestMethod1", msg.to_string()) diff --git a/src/hyperlight_host/tests/wit_test.rs b/src/hyperlight_host/tests/wit_test.rs index 6262b8480..8a12e1433 100644 --- a/src/hyperlight_host/tests/wit_test.rs +++ b/src/hyperlight_host/tests/wit_test.rs @@ -18,7 +18,7 @@ limitations under the License. use std::sync::{Arc, Mutex}; use hyperlight_common::resource::BorrowedResourceGuard; -use hyperlight_host::{GuestBinary, MultiUseGuestCallContext, UninitializedSandbox}; +use hyperlight_host::{GuestBinary, MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::wit_guest_as_string; extern crate alloc; @@ -280,7 +280,7 @@ impl test::wit::TestImports for Host { } } -fn sb() -> TestSandbox { +fn sb() -> TestSandbox { let path = wit_guest_as_string().unwrap(); let guest_path = GuestBinary::FilePath(path); let uninit = UninitializedSandbox::new(guest_path, None).unwrap(); From 5a8bcefbf5bd186ed3bbdb2149c84000443d5310 Mon Sep 17 00:00:00 2001 From: Mark Rossetti Date: Fri, 18 Jul 2025 16:00:06 -0700 Subject: [PATCH 031/271] Making mshv3 the default mshv hypervisor in hyperlight_host (instead of mshv2) (#703) Signed-off-by: Mark Rossett --- .github/workflows/Benchmarks.yml | 2 +- .github/workflows/dep_rust.yml | 10 +++++----- Justfile | 6 +++--- src/hyperlight_host/Cargo.toml | 3 ++- src/hyperlight_host/build.rs | 8 ++++---- src/hyperlight_host/examples/guest-debugging/main.rs | 6 +++--- 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/.github/workflows/Benchmarks.yml b/.github/workflows/Benchmarks.yml index 64df29bb2..5fd12f922 100644 --- a/.github/workflows/Benchmarks.yml +++ b/.github/workflows/Benchmarks.yml @@ -57,7 +57,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Run Benchmarks - run: just bench-ci main release ${{ matrix.hypervisor == 'mshv3' && 'mshv3' || ''}} + run: just bench-ci main release ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} - uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index fe7d0f203..f08958515 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -128,7 +128,7 @@ jobs: CARGO_TERM_COLOR: always run: | # with default features - just test ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv3' && 'mshv3' || ''}} + just test ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} # with only one driver enabled (driver mshv/kvm feature is ignored on windows) + seccomp just test ${{ matrix.config }} seccomp,${{ matrix.hypervisor == 'mshv' && 'mshv2' || matrix.hypervisor == 'mshv3' && 'mshv3' || 'kvm' }} @@ -154,20 +154,20 @@ jobs: env: CARGO_TERM_COLOR: always RUST_LOG: debug - run: just run-rust-examples-linux ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv3' && 'mshv3' || ''}} + run: just run-rust-examples-linux ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} - name: Run Rust Gdb tests - linux if: runner.os == 'Linux' env: CARGO_TERM_COLOR: always RUST_LOG: debug - run: just test-rust-gdb-debugging ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv3' && 'mshv3' || ''}} + run: just test-rust-gdb-debugging ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} - name: Run Rust Crashdump tests env: CARGO_TERM_COLOR: always RUST_LOG: debug - run: just test-rust-crashdump ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv3' && 'mshv3' || ''}} + run: just test-rust-crashdump ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} - name: Download benchmarks from "latest" run: just bench-download ${{ runner.os }} ${{ matrix.hypervisor }} ${{ matrix.cpu}} dev-latest # compare to prerelease @@ -178,5 +178,5 @@ jobs: - name: Run benchmarks run: | - just bench-ci main ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv3' && 'mshv3' || ''}} + just bench-ci main ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} if: ${{ matrix.config == 'release' }} diff --git a/Justfile b/Justfile index ffd7f7c39..276c7985d 100644 --- a/Justfile +++ b/Justfile @@ -73,7 +73,7 @@ clean-rust: # convenience recipe to run all tests with the given target and features (similar to CI) test-like-ci config=default-target hypervisor="kvm": @# with default features - just test {{config}} {{ if hypervisor == "mshv3" {"mshv3"} else {""} }} + just test {{config}} {{ if hypervisor == "mshv" {"mshv2"} else {""} }} @# with only one driver enabled + seccomp + build-metadata + init-paging just test {{config}} seccomp,build-metadata,init-paging,{{ if hypervisor == "mshv" {"mshv2"} else if hypervisor == "mshv3" {"mshv3"} else {"kvm"} }} @@ -119,7 +119,7 @@ test-integration guest target=default-target features="": test-seccomp target=default-target features="": @# run seccomp test with feature "seccomp" on and off cargo test --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host test_violate_seccomp_filters --lib {{ if features =="" {''} else { "--features " + features } }} -- --ignored - cargo test --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host test_violate_seccomp_filters --no-default-features {{ if features =~"mshv3" {"--features init-paging,mshv3"} else {"--features mshv2,init-paging,kvm" } }} --lib -- --ignored + cargo test --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host test_violate_seccomp_filters --no-default-features {{ if features =~"mshv2" {"--features init-paging,mshv2"} else {"--features mshv3,init-paging,kvm" } }} --lib -- --ignored # tests compilation with no default features on different platforms test-compilation-no-default-features target=default-target: @@ -239,7 +239,7 @@ tar-static-lib: (build-rust-capi "release") (build-rust-capi "debug") # Downloads the benchmarks result from the given release tag. # If tag is not given, defaults to latest release # Options for os: "Windows", or "Linux" -# Options for Linux hypervisor: "kvm", "mshv" +# Options for Linux hypervisor: "kvm", "mshv", "mshv3" # Options for Windows hypervisor: "hyperv" # Options for cpu: "amd", "intel" bench-download os hypervisor cpu tag="": diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index bc744c05c..ac56a57b0 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -118,7 +118,7 @@ cfg_aliases = "0.2.1" built = { version = "0.8.0", optional = true, features = ["chrono", "git2"] } [features] -default = ["kvm", "mshv2", "seccomp", "build-metadata", "init-paging"] +default = ["kvm", "mshv3", "seccomp", "build-metadata", "init-paging"] seccomp = ["dep:seccompiler"] function_call_metrics = [] executable_heap = [] @@ -127,6 +127,7 @@ print_debug = [] # Dumps the VM state to a file on unexpected errors or crashes. The path of the file will be printed on stdout and logged. crashdump = ["dep:chrono"] kvm = ["dep:kvm-bindings", "dep:kvm-ioctls"] +# This feature is deprecated in favor of mshv3 mshv2 = ["dep:mshv-bindings2", "dep:mshv-ioctls2"] mshv3 = ["dep:mshv-bindings3", "dep:mshv-ioctls3"] # This enables easy debug in the guest diff --git a/src/hyperlight_host/build.rs b/src/hyperlight_host/build.rs index ca2fd8bf2..6c90a485f 100644 --- a/src/hyperlight_host/build.rs +++ b/src/hyperlight_host/build.rs @@ -96,11 +96,11 @@ fn main() -> Result<()> { crashdump: { all(feature = "crashdump") }, // print_debug feature is aliased with debug_assertions to make it only available in debug-builds. print_debug: { all(feature = "print_debug", debug_assertions) }, - // the following features are mutually exclusive but rather than enforcing that here we are enabling mshv3 to override mshv2 when both are enabled - // because mshv2 is in the default feature set we want to allow users to enable mshv3 without having to set --no-default-features and the re-enable + // the following features are mutually exclusive but rather than enforcing that here we are enabling mshv2 to override mshv3 when both are enabled + // because mshv3 is in the default feature set we want to allow users to enable mshv2 without having to set --no-default-features and the re-enable // the other features they want. - mshv2: { all(feature = "mshv2", not(feature="mshv3"), target_os = "linux") }, - mshv3: { all(feature = "mshv3", target_os = "linux") }, + mshv2: { all(feature = "mshv2", target_os = "linux") }, + mshv3: { all(feature = "mshv3", not(feature="mshv2"), target_os = "linux") }, } #[cfg(feature = "build-metadata")] diff --git a/src/hyperlight_host/examples/guest-debugging/main.rs b/src/hyperlight_host/examples/guest-debugging/main.rs index 6b1f46677..cc39b1705 100644 --- a/src/hyperlight_host/examples/guest-debugging/main.rs +++ b/src/hyperlight_host/examples/guest-debugging/main.rs @@ -146,9 +146,9 @@ mod tests { write_cmds_file(&cmd_file_path, &out_file_path) .expect("Failed to write gdb commands to file"); - #[cfg(mshv3)] - let features = "gdb,mshv3"; - #[cfg(not(mshv3))] + #[cfg(mshv2)] // mshv3 is a default feature is mutually exclusive with the mshv2 feature + let features = "gdb,mshv2"; + #[cfg(not(mshv2))] let features = "gdb"; let mut guest_child = Command::new("cargo") From 0f2f193b352a34b712fe80f3dc2fb1c586612636 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 04:26:08 +0000 Subject: [PATCH 032/271] Bump serde_json from 1.0.140 to 1.0.141 (#719) --- updated-dependencies: - dependency-name: serde_json dependency-version: 1.0.141 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41c263955..53b046bf5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2545,9 +2545,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" dependencies = [ "itoa", "memchr", From 61e60f9392622927387e37281b09f3f38a6d2145 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 04:32:19 +0000 Subject: [PATCH 033/271] Bump cc from 1.2.29 to 1.2.30 (#718) --- updated-dependencies: - dependency-name: cc dependency-version: 1.2.30 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53b046bf5..31e341fb8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -292,9 +292,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.29" +version = "1.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" dependencies = [ "jobserver", "libc", From 97ee46e8251472687bce30cad639689c4e652402 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 04:36:23 +0000 Subject: [PATCH 034/271] Bump rand from 0.9.1 to 0.9.2 (#720) --- updated-dependencies: - dependency-name: rand dependency-version: 0.9.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 31e341fb8..40f25ed72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2186,9 +2186,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha", "rand_core", From 1a702dec3c99ec2ed0e6dd38852bc368761aa254 Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Sat, 19 Oct 2024 03:42:19 +0100 Subject: [PATCH 035/271] [hyperlight_host] Restrict OutBHandler{Caller,Wrapper} to pub(crate) In the future, the outb handler will need to take a Hypervisor instance in order to be able to access register and memory state of the VM, so it doesn't make sense for these interfaces to be more public than the `Hypervisor` trait. Nobody outside of Hyperlight seems to use these at the moment, so it's probably simplest to restrict these to `pub(crate)`. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- src/hyperlight_host/src/hypervisor/handlers.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hyperlight_host/src/hypervisor/handlers.rs b/src/hyperlight_host/src/hypervisor/handlers.rs index 9a091b2b1..3fa6c3db2 100644 --- a/src/hyperlight_host/src/hypervisor/handlers.rs +++ b/src/hyperlight_host/src/hypervisor/handlers.rs @@ -23,7 +23,7 @@ use crate::{Result, new_error}; /// The trait representing custom logic to handle the case when /// a Hypervisor's virtual CPU (vCPU) informs Hyperlight the guest /// has initiated an outb operation. -pub trait OutBHandlerCaller: Sync + Send { +pub(crate) trait OutBHandlerCaller: Sync + Send { /// Function that gets called when an outb operation has occurred. fn call(&mut self, port: u16, payload: u32) -> Result<()>; } @@ -34,7 +34,7 @@ pub trait OutBHandlerCaller: Sync + Send { /// Note: This needs to be wrapped in a Mutex to be able to grab a mutable /// reference to the underlying data (i.e., handle_outb in `Sandbox` takes /// a &mut self). -pub type OutBHandlerWrapper = Arc>; +pub(crate) type OutBHandlerWrapper = Arc>; pub(crate) type OutBHandlerFunction = Box Result<()> + Send>; From c3d65fc833da5997c3406becb68a37b846ccfac0 Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Sat, 19 Oct 2024 03:50:09 +0100 Subject: [PATCH 036/271] [hyperlight_host] Plumb a trace file descriptor around MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds (unused) support for creating trace files for sandboxes and passing them around to relevant sandbox event handler code. This will be used for collecting debug trace and profiling information. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> Signed-off-by: Doru Blânzeanu --- Cargo.lock | 10 ++++++ src/hyperlight_host/Cargo.toml | 3 ++ .../src/hypervisor/handlers.rs | 27 ++++++++++++++-- .../src/hypervisor/hyperv_linux.rs | 19 ++++++++++- .../src/hypervisor/hyperv_windows.rs | 16 +++++++++- src/hyperlight_host/src/hypervisor/kvm.rs | 17 +++++++++- src/hyperlight_host/src/hypervisor/mod.rs | 19 +++++++---- src/hyperlight_host/src/sandbox/mod.rs | 32 +++++++++++++++++++ src/hyperlight_host/src/sandbox/outb.rs | 22 ++++++++----- .../src/sandbox/uninitialized_evolve.rs | 11 +++++++ 10 files changed, 156 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 40f25ed72..0706e2281 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -616,6 +616,15 @@ dependencies = [ "log", ] +[[package]] +name = "envy" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f47e0157f2cb54f5ae1bd371b30a2ae4311e1c028f575cd4e81de7353215965" +dependencies = [ + "serde", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1079,6 +1088,7 @@ dependencies = [ "crossbeam-queue", "elfcore", "env_logger", + "envy", "flatbuffers", "gdbstub", "gdbstub_arch", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index ac56a57b0..d1e6d2965 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -44,6 +44,7 @@ anyhow = "1.0" metrics = "0.24.2" serde_json = "1.0" elfcore = "2.0" +uuid = { version = "1.17.0", features = ["v4"] } [target.'cfg(windows)'.dependencies] windows = { version = "0.61", features = [ @@ -79,6 +80,7 @@ mshv-ioctls3 = { package="mshv-ioctls", version = "=0.3.2", optional = true} [dev-dependencies] uuid = { version = "1.17.0", features = ["v4"] } signal-hook-registry = "1.4.5" +envy = { version = "0.4.2" } serde = "1.0" proptest = "1.7.0" tempfile = "3.20.0" @@ -126,6 +128,7 @@ executable_heap = [] print_debug = [] # Dumps the VM state to a file on unexpected errors or crashes. The path of the file will be printed on stdout and logged. crashdump = ["dep:chrono"] +trace_guest = [] kvm = ["dep:kvm-bindings", "dep:kvm-ioctls"] # This feature is deprecated in favor of mshv3 mshv2 = ["dep:mshv-bindings2", "dep:mshv-ioctls2"] diff --git a/src/hyperlight_host/src/hypervisor/handlers.rs b/src/hyperlight_host/src/hypervisor/handlers.rs index 3fa6c3db2..186c030e2 100644 --- a/src/hyperlight_host/src/hypervisor/handlers.rs +++ b/src/hyperlight_host/src/hypervisor/handlers.rs @@ -18,6 +18,8 @@ use std::sync::{Arc, Mutex}; use tracing::{Span, instrument}; +#[cfg(feature = "trace_guest")] +use super::Hypervisor; use crate::{Result, new_error}; /// The trait representing custom logic to handle the case when @@ -25,7 +27,12 @@ use crate::{Result, new_error}; /// has initiated an outb operation. pub(crate) trait OutBHandlerCaller: Sync + Send { /// Function that gets called when an outb operation has occurred. - fn call(&mut self, port: u16, payload: u32) -> Result<()>; + fn call( + &mut self, + #[cfg(feature = "trace_guest")] hv: &mut dyn Hypervisor, + port: u16, + payload: u32, + ) -> Result<()>; } /// A convenient type representing a common way `OutBHandler` implementations @@ -36,6 +43,10 @@ pub(crate) trait OutBHandlerCaller: Sync + Send { /// a &mut self). pub(crate) type OutBHandlerWrapper = Arc>; +#[cfg(feature = "trace_guest")] +pub(crate) type OutBHandlerFunction = + Box Result<()> + Send>; +#[cfg(not(feature = "trace_guest"))] pub(crate) type OutBHandlerFunction = Box Result<()> + Send>; /// A `OutBHandler` implementation using a `OutBHandlerFunction` @@ -52,12 +63,22 @@ impl From for OutBHandler { impl OutBHandlerCaller for OutBHandler { #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - fn call(&mut self, port: u16, payload: u32) -> Result<()> { + fn call( + &mut self, + #[cfg(feature = "trace_guest")] hv: &mut dyn Hypervisor, + port: u16, + payload: u32, + ) -> Result<()> { let mut func = self .0 .try_lock() .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?; - func(port, payload) + func( + #[cfg(feature = "trace_guest")] + hv, + port, + payload, + ) } } diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index d9160b6f2..dd03bcb57 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -72,6 +72,8 @@ use crate::HyperlightError; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::{GuestPtr, RawPtr}; use crate::sandbox::SandboxConfiguration; +#[cfg(feature = "trace_guest")] +use crate::sandbox::TraceInfo; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; use crate::{Result, log_then_return, new_error}; @@ -311,6 +313,9 @@ pub(crate) struct HypervLinuxDriver { gdb_conn: Option>, #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, + #[cfg(feature = "trace_guest")] + #[allow(dead_code)] + trace_info: TraceInfo, } impl HypervLinuxDriver { @@ -322,6 +327,8 @@ impl HypervLinuxDriver { /// the underlying virtual CPU after this function returns. Call the /// `apply_registers` method to do that, or more likely call /// `initialise` to do it for you. + #[allow(clippy::too_many_arguments)] + // TODO: refactor this function to take fewer arguments. Add trace_info to rt_cfg #[instrument(skip_all, parent = Span::current(), level = "Trace")] pub(crate) fn new( mem_regions: Vec, @@ -331,6 +338,7 @@ impl HypervLinuxDriver { config: &SandboxConfiguration, #[cfg(gdb)] gdb_conn: Option>, #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, + #[cfg(feature = "trace_guest")] trace_info: TraceInfo, ) -> Result { let mshv = Mshv::new()?; let pr = Default::default(); @@ -438,6 +446,8 @@ impl HypervLinuxDriver { gdb_conn, #[cfg(crashdump)] rt_cfg, + #[cfg(feature = "trace_guest")] + trace_info, }; // Send the interrupt handle to the GDB thread if debugging is enabled @@ -668,7 +678,12 @@ impl Hypervisor for HypervLinuxDriver { outb_handle_fn .try_lock() .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .call(port, val)?; + .call( + #[cfg(feature = "trace_guest")] + self, + port, + val, + )?; // update rip self.vcpu_fd.set_reg(&[hv_register_assoc { @@ -1164,6 +1179,8 @@ mod tests { #[cfg(crashdump)] guest_core_dump: true, }, + #[cfg(feature = "trace_guest")] + TraceInfo::new().unwrap(), ) .unwrap(); } diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index a057c41cc..94204e1e2 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -60,6 +60,8 @@ use crate::hypervisor::fpu::FP_CONTROL_WORD_DEFAULT; use crate::hypervisor::wrappers::WHvGeneralRegisters; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::{GuestPtr, RawPtr}; +#[cfg(feature = "trace_guest")] +use crate::sandbox::TraceInfo; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; use crate::{Result, debug, log_then_return, new_error}; @@ -283,6 +285,9 @@ pub(crate) struct HypervWindowsDriver { gdb_conn: Option>, #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, + #[cfg(feature = "trace_guest")] + #[allow(dead_code)] + trace_info: TraceInfo, } /* This does not automatically impl Send/Sync because the host * address of the shared memory region is a raw pointer, which are @@ -294,6 +299,7 @@ unsafe impl Sync for HypervWindowsDriver {} impl HypervWindowsDriver { #[allow(clippy::too_many_arguments)] + // TODO: refactor this function to take fewer arguments. Add trace_info to rt_cfg #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] pub(crate) fn new( mem_regions: Vec, @@ -304,6 +310,7 @@ impl HypervWindowsDriver { mmap_file_handle: HandleWrapper, #[cfg(gdb)] gdb_conn: Option>, #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, + #[cfg(feature = "trace_guest")] trace_info: TraceInfo, ) -> Result { // create and setup hypervisor partition let mut partition = VMPartition::new(1)?; @@ -354,6 +361,8 @@ impl HypervWindowsDriver { gdb_conn, #[cfg(crashdump)] rt_cfg, + #[cfg(feature = "trace_guest")] + trace_info, }; // Send the interrupt handle to the GDB thread if debugging is enabled @@ -683,7 +692,12 @@ impl Hypervisor for HypervWindowsDriver { outb_handle_fn .try_lock() .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .call(port, val)?; + .call( + #[cfg(feature = "trace_guest")] + self, + port, + val, + )?; let mut regs = self.processor.get_regs()?; regs.rip = rip + instruction_length; diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index 0802ecb6b..bdc9887cd 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -46,6 +46,8 @@ use crate::HyperlightError; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::{GuestPtr, RawPtr}; use crate::sandbox::SandboxConfiguration; +#[cfg(feature = "trace_guest")] +use crate::sandbox::TraceInfo; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; use crate::{Result, log_then_return, new_error}; @@ -298,12 +300,17 @@ pub(crate) struct KVMDriver { gdb_conn: Option>, #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, + #[cfg(feature = "trace_guest")] + #[allow(dead_code)] + trace_info: TraceInfo, } impl KVMDriver { /// Create a new instance of a `KVMDriver`, with only control registers /// set. Standard registers will not be set, and `initialise` must /// be called to do so. + #[allow(clippy::too_many_arguments)] + // TODO: refactor this function to take fewer arguments. Add trace_info to rt_cfg #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] pub(crate) fn new( mem_regions: Vec, @@ -313,6 +320,7 @@ impl KVMDriver { config: &SandboxConfiguration, #[cfg(gdb)] gdb_conn: Option>, #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, + #[cfg(feature = "trace_guest")] trace_info: TraceInfo, ) -> Result { let kvm = Kvm::new()?; @@ -380,6 +388,8 @@ impl KVMDriver { gdb_conn, #[cfg(crashdump)] rt_cfg, + #[cfg(feature = "trace_guest")] + trace_info, }; // Send the interrupt handle to the GDB thread if debugging is enabled @@ -586,7 +596,12 @@ impl Hypervisor for KVMDriver { outb_handle_fn .try_lock() .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .call(port, value)?; + .call( + #[cfg(feature = "trace_guest")] + self, + port, + value, + )?; } Ok(()) diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index ecf6acbc5..bb058a1f1 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -503,10 +503,12 @@ pub(crate) mod tests { use hyperlight_testing::dummy_guest_as_string; - use super::handlers::{MemAccessHandler, OutBHandler}; + use super::handlers::{MemAccessHandler, OutBHandler, OutBHandlerFunction}; #[cfg(gdb)] use crate::hypervisor::DbgMemAccessHandlerCaller; use crate::mem::ptr::RawPtr; + #[cfg(feature = "trace_guest")] + use crate::sandbox::TraceInfo; use crate::sandbox::uninitialized::GuestBinary; #[cfg(any(crashdump, gdb))] use crate::sandbox::uninitialized::SandboxRuntimeConfig; @@ -538,11 +540,6 @@ pub(crate) mod tests { return Ok(()); } - let outb_handler: Arc> = { - let func: Box Result<()> + Send> = - Box::new(|_, _| -> Result<()> { Ok(()) }); - Arc::new(Mutex::new(OutBHandler::from(func))) - }; let mem_access_handler = { let func: Box Result<()> + Send> = Box::new(|| -> Result<()> { Ok(()) }); Arc::new(Mutex::new(MemAccessHandler::from(func))) @@ -563,7 +560,17 @@ pub(crate) mod tests { &config, #[cfg(any(crashdump, gdb))] &rt_cfg, + #[cfg(feature = "trace_guest")] + TraceInfo::new()?, )?; + let outb_handler: Arc> = { + #[cfg(feature = "trace_guest")] + #[allow(clippy::type_complexity)] + let func: OutBHandlerFunction = Box::new(|_, _, _| -> Result<()> { Ok(()) }); + #[cfg(not(feature = "trace_guest"))] + let func: OutBHandlerFunction = Box::new(|_, _| -> Result<()> { Ok(()) }); + Arc::new(Mutex::new(OutBHandler::from(func))) + }; vm.initialise( RawPtr::from(0x230000), 1234567890, diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index 07389c369..209fb167c 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -43,6 +43,9 @@ pub mod snapshot; /// Trait used by the macros to paper over the differences between hyperlight and hyperlight-wasm mod callable; +#[cfg(feature = "trace_guest")] +use std::sync::{Arc, Mutex}; + /// Trait used by the macros to paper over the differences between hyperlight and hyperlight-wasm pub use callable::Callable; /// Re-export for `SandboxConfiguration` type @@ -89,6 +92,35 @@ pub fn is_hypervisor_present() -> bool { hypervisor::get_available_hypervisor().is_some() } +#[cfg(feature = "trace_guest")] +#[derive(Clone)] +/// The information that trace collection requires in order to write +/// an accurate trace. +pub(crate) struct TraceInfo { + /// The epoch against which trace events are timed; at least as + /// early as the creation of the sandbox being traced. + #[allow(dead_code)] + pub epoch: std::time::Instant, + /// The file to which the trace is being written + #[allow(dead_code)] + pub file: Arc>, +} +#[cfg(feature = "trace_guest")] +impl TraceInfo { + /// Create a new TraceInfo by saving the current time as the epoch + /// and generating a random filename. + pub fn new() -> crate::Result { + let mut path = std::env::current_dir()?; + path.push("trace"); + path.push(uuid::Uuid::new_v4().to_string()); + path.set_extension("trace"); + Ok(Self { + epoch: std::time::Instant::now(), + file: Arc::new(Mutex::new(std::fs::File::create_new(path)?)), + }) + } +} + pub(crate) trait WrapperGetter { #[allow(dead_code)] fn get_mgr_wrapper(&self) -> &MemMgrWrapper; diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index dcdd96589..8ac8a2e6b 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -26,6 +26,8 @@ use tracing_log::format_trace; use super::host_funcs::FunctionRegistry; use super::mem_mgr::MemMgrWrapper; +#[cfg(feature = "trace_guest")] +use crate::hypervisor::Hypervisor; use crate::hypervisor::handlers::{OutBHandler, OutBHandlerFunction, OutBHandlerWrapper}; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; @@ -149,6 +151,7 @@ fn outb_abort(mem_mgr: &mut MemMgrWrapper, data: u32) -> Resul fn handle_outb_impl( mem_mgr: &mut MemMgrWrapper, host_funcs: Arc>, + #[cfg(feature = "trace_guest")] _hv: &mut dyn Hypervisor, port: u16, data: u32, ) -> Result<()> { @@ -192,14 +195,17 @@ pub(crate) fn outb_handler_wrapper( mut mem_mgr_wrapper: MemMgrWrapper, host_funcs_wrapper: Arc>, ) -> OutBHandlerWrapper { - let outb_func: OutBHandlerFunction = Box::new(move |port, payload| { - handle_outb_impl( - &mut mem_mgr_wrapper, - host_funcs_wrapper.clone(), - port, - payload, - ) - }); + let outb_func: OutBHandlerFunction = + Box::new(move |#[cfg(feature = "trace_guest")] hv, port, payload| { + handle_outb_impl( + &mut mem_mgr_wrapper, + host_funcs_wrapper.clone(), + #[cfg(feature = "trace_guest")] + hv, + port, + payload, + ) + }); let outb_hdl = OutBHandler::from(outb_func); Arc::new(Mutex::new(outb_hdl)) } diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index 696eb92a1..07747dd9d 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -35,6 +35,8 @@ use crate::mem::ptr_offset::Offset; use crate::mem::shared_mem::GuestSharedMemory; #[cfg(any(feature = "init-paging", target_os = "windows"))] use crate::mem::shared_mem::SharedMemory; +#[cfg(feature = "trace_guest")] +use crate::sandbox::TraceInfo; #[cfg(gdb)] use crate::sandbox::config::DebugInfo; use crate::sandbox::host_funcs::FunctionRegistry; @@ -77,6 +79,8 @@ where &u_sbox.config, #[cfg(any(crashdump, gdb))] &u_sbox.rt_cfg, + #[cfg(feature = "trace_guest")] + TraceInfo::new()?, )?; let outb_hdl = outb_handler_wrapper(hshm.clone(), u_sbox.host_funcs.clone()); @@ -146,6 +150,7 @@ pub(crate) fn set_up_hypervisor_partition( mgr: &mut SandboxMemoryManager, #[cfg_attr(target_os = "windows", allow(unused_variables))] config: &SandboxConfiguration, #[cfg(any(crashdump, gdb))] rt_cfg: &SandboxRuntimeConfig, + #[cfg(feature = "trace_guest")] trace_info: TraceInfo, ) -> Result> { #[cfg(feature = "init-paging")] let rsp_ptr = { @@ -217,6 +222,8 @@ pub(crate) fn set_up_hypervisor_partition( gdb_conn, #[cfg(crashdump)] rt_cfg.clone(), + #[cfg(feature = "trace_guest")] + trace_info, )?; Ok(Box::new(hv)) } @@ -233,6 +240,8 @@ pub(crate) fn set_up_hypervisor_partition( gdb_conn, #[cfg(crashdump)] rt_cfg.clone(), + #[cfg(feature = "trace_guest")] + trace_info, )?; Ok(Box::new(hv)) } @@ -255,6 +264,8 @@ pub(crate) fn set_up_hypervisor_partition( gdb_conn, #[cfg(crashdump)] rt_cfg.clone(), + #[cfg(feature = "trace_guest")] + trace_info, )?; Ok(Box::new(hv)) } From 21cf19bd989cd1985878371b8a6f6e837e2a9e2c Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Thu, 5 Dec 2024 08:20:33 +0000 Subject: [PATCH 037/271] [hyperlight_host/exe] Allow load() to consume the exe_info This will be useful in the near future, when it will allow transforming the exe_info into unwind information without an extra copy. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- src/hyperlight_host/src/mem/elf.rs | 2 +- src/hyperlight_host/src/mem/exe.rs | 4 ++-- src/hyperlight_host/src/mem/mgr.rs | 6 +++--- src/hyperlight_host/src/sandbox/outb.rs | 15 ++++++--------- src/hyperlight_host/src/sandbox/uninitialized.rs | 4 ++-- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/hyperlight_host/src/mem/elf.rs b/src/hyperlight_host/src/mem/elf.rs index 3efe09b4f..afe7ea4a5 100644 --- a/src/hyperlight_host/src/mem/elf.rs +++ b/src/hyperlight_host/src/mem/elf.rs @@ -73,7 +73,7 @@ impl ElfInfo { .unwrap(); (max_phdr.p_vaddr + max_phdr.p_memsz - self.get_base_va()) as usize } - pub(crate) fn load_at(&self, load_addr: usize, target: &mut [u8]) -> Result<()> { + pub(crate) fn load_at(&mut self, load_addr: usize, target: &mut [u8]) -> Result<()> { let base_va = self.get_base_va(); for phdr in self.phdrs.iter().filter(|phdr| phdr.p_type == PT_LOAD) { let start_va = (phdr.p_vaddr - base_va) as usize; diff --git a/src/hyperlight_host/src/mem/exe.rs b/src/hyperlight_host/src/mem/exe.rs index bf1724317..6f72b7cae 100644 --- a/src/hyperlight_host/src/mem/exe.rs +++ b/src/hyperlight_host/src/mem/exe.rs @@ -71,9 +71,9 @@ impl ExeInfo { // copying into target, but the PE loader chooses to apply // relocations in its owned representation of the PE contents, // which requires it to be &mut. - pub fn load(&mut self, load_addr: usize, target: &mut [u8]) -> Result<()> { + pub fn load(self, load_addr: usize, target: &mut [u8]) -> Result<()> { match self { - ExeInfo::Elf(elf) => { + ExeInfo::Elf(mut elf) => { elf.load_at(load_addr, target)?; } } diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index f6ce32c26..856e9b361 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -311,7 +311,7 @@ impl SandboxMemoryManager { #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] pub(crate) fn load_guest_binary_into_memory( cfg: SandboxConfiguration, - exe_info: &mut ExeInfo, + exe_info: ExeInfo, guest_blob: Option<&GuestBlob>, ) -> Result { let guest_blob_size = guest_blob.map(|b| b.data.len()).unwrap_or(0); @@ -320,8 +320,8 @@ impl SandboxMemoryManager { let layout = SandboxMemoryLayout::new( cfg, exe_info.loaded_size(), - usize::try_from(cfg.get_stack_size(exe_info))?, - usize::try_from(cfg.get_heap_size(exe_info))?, + usize::try_from(cfg.get_stack_size(&exe_info))?, + usize::try_from(cfg.get_heap_size(&exe_info))?, guest_blob_size, guest_blob_mem_flags, )?; diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index 8ac8a2e6b..5b25248ae 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -246,13 +246,10 @@ mod tests { let sandbox_cfg = SandboxConfiguration::default(); let new_mgr = || { - let mut exe_info = simple_guest_exe_info().unwrap(); - let mut mgr = SandboxMemoryManager::load_guest_binary_into_memory( - sandbox_cfg, - &mut exe_info, - None, - ) - .unwrap(); + let exe_info = simple_guest_exe_info().unwrap(); + let mut mgr = + SandboxMemoryManager::load_guest_binary_into_memory(sandbox_cfg, exe_info, None) + .unwrap(); let mem_size = mgr.get_shared_mem_mut().mem_size(); let layout = mgr.layout; let shared_mem = mgr.get_shared_mem_mut(); @@ -361,10 +358,10 @@ mod tests { let sandbox_cfg = SandboxConfiguration::default(); tracing::subscriber::with_default(subscriber.clone(), || { let new_mgr = || { - let mut exe_info = simple_guest_exe_info().unwrap(); + let exe_info = simple_guest_exe_info().unwrap(); let mut mgr = SandboxMemoryManager::load_guest_binary_into_memory( sandbox_cfg, - &mut exe_info, + exe_info, None, ) .unwrap(); diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index f5149f5cc..b2a69cd29 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -281,12 +281,12 @@ impl UninitializedSandbox { guest_binary: &GuestBinary, guest_blob: Option<&GuestBlob>, ) -> Result> { - let mut exe_info = match guest_binary { + let exe_info = match guest_binary { GuestBinary::FilePath(bin_path_str) => ExeInfo::from_file(bin_path_str)?, GuestBinary::Buffer(buffer) => ExeInfo::from_buf(buffer)?, }; - SandboxMemoryManager::load_guest_binary_into_memory(cfg, &mut exe_info, guest_blob) + SandboxMemoryManager::load_guest_binary_into_memory(cfg, exe_info, guest_blob) } /// Set the max log level to be used by the guest. From 77c6ce728084ec58cb59ea351b46ae720be76719 Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Sat, 19 Oct 2024 05:06:21 +0100 Subject: [PATCH 038/271] [hyperlight_host/trace] Add HV interface for reading trace registers This adds a new interface which tracing code can use to request the values of registers from the hypervisor supervising a sandbox. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- src/hyperlight_host/Cargo.toml | 3 ++ .../src/hypervisor/hyperv_linux.rs | 31 +++++++++++++++++++ .../src/hypervisor/hyperv_windows.rs | 14 +++++++++ src/hyperlight_host/src/hypervisor/kvm.rs | 14 +++++++++ src/hyperlight_host/src/hypervisor/mod.rs | 19 ++++++++++++ 5 files changed, 81 insertions(+) diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index d1e6d2965..a27121d76 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -129,6 +129,9 @@ print_debug = [] # Dumps the VM state to a file on unexpected errors or crashes. The path of the file will be printed on stdout and logged. crashdump = ["dep:chrono"] trace_guest = [] +# This feature enables unwinding the guest stack from the host, in +# order to produce stack traces for debugging or profiling. +unwind_guest = [ "trace_guest" ] kvm = ["dep:kvm-bindings", "dep:kvm-ioctls"] # This feature is deprecated in favor of mshv3 mshv2 = ["dep:mshv-bindings2", "dep:mshv-ioctls2"] diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index dd03bcb57..5059188dc 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -48,11 +48,18 @@ use mshv_bindings::{ hv_partition_property_code_HV_PARTITION_PROPERTY_SYNTHETIC_PROC_FEATURES, hv_partition_synthetic_processor_features, }; +#[cfg(feature = "unwind_guest")] +use mshv_bindings::{ + hv_register_name, hv_register_name_HV_X64_REGISTER_RAX, hv_register_name_HV_X64_REGISTER_RBP, + hv_register_name_HV_X64_REGISTER_RCX, hv_register_name_HV_X64_REGISTER_RSP, +}; use mshv_ioctls::{Mshv, MshvError, VcpuFd, VmFd}; use tracing::{Span, instrument}; #[cfg(crashdump)] use {super::crashdump, std::path::Path}; +#[cfg(feature = "unwind_guest")] +use super::TraceRegister; use super::fpu::{FP_CONTROL_WORD_DEFAULT, FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT}; #[cfg(gdb)] use super::gdb::{ @@ -547,6 +554,19 @@ impl Debug for HypervLinuxDriver { } } +#[cfg(feature = "unwind_guest")] +impl From for hv_register_name { + fn from(r: TraceRegister) -> Self { + match r { + TraceRegister::RAX => hv_register_name_HV_X64_REGISTER_RAX, + TraceRegister::RCX => hv_register_name_HV_X64_REGISTER_RCX, + TraceRegister::RIP => hv_register_name_HV_X64_REGISTER_RIP, + TraceRegister::RSP => hv_register_name_HV_X64_REGISTER_RSP, + TraceRegister::RBP => hv_register_name_HV_X64_REGISTER_RBP, + } + } +} + impl Hypervisor for HypervLinuxDriver { #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] fn initialise( @@ -1093,6 +1113,17 @@ impl Hypervisor for HypervLinuxDriver { Ok(()) } + + #[cfg(feature = "unwind_guest")] + fn read_trace_reg(&self, reg: TraceRegister) -> Result { + let mut assoc = [hv_register_assoc { + name: reg.into(), + ..Default::default() + }]; + self.vcpu_fd.get_reg(&mut assoc)?; + // safety: all registers that we currently support are 64-bit + unsafe { Ok(assoc[0].value.reg64) } + } } impl Drop for HypervLinuxDriver { diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index 94204e1e2..e1263a810 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -44,6 +44,8 @@ use { std::sync::Mutex, }; +#[cfg(feature = "unwind_guest")] +use super::TraceRegister; use super::fpu::{FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT}; use super::handlers::{MemAccessHandlerWrapper, OutBHandlerWrapper}; use super::surrogate_process::SurrogateProcess; @@ -1043,6 +1045,18 @@ impl Hypervisor for HypervWindowsDriver { Ok(()) } + + #[cfg(feature = "unwind_guest")] + fn read_trace_reg(&self, reg: TraceRegister) -> Result { + let regs = self.processor.get_regs()?; + match reg { + TraceRegister::RAX => Ok(regs.rax), + TraceRegister::RCX => Ok(regs.rcx), + TraceRegister::RIP => Ok(regs.rip), + TraceRegister::RSP => Ok(regs.rsp), + TraceRegister::RBP => Ok(regs.rbp), + } + } } impl Drop for HypervWindowsDriver { diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index bdc9887cd..a9adc1c82 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -29,6 +29,8 @@ use tracing::{Span, instrument}; #[cfg(crashdump)] use {super::crashdump, std::path::Path}; +#[cfg(feature = "unwind_guest")] +use super::TraceRegister; use super::fpu::{FP_CONTROL_WORD_DEFAULT, FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT}; #[cfg(gdb)] use super::gdb::{DebugCommChannel, DebugMsg, DebugResponse, GuestDebug, KvmDebug, VcpuStopReason}; @@ -962,6 +964,18 @@ impl Hypervisor for KVMDriver { Ok(()) } + + #[cfg(feature = "unwind_guest")] + fn read_trace_reg(&self, reg: TraceRegister) -> Result { + let regs = self.vcpu_fd.get_regs()?; + Ok(match reg { + TraceRegister::RAX => regs.rax, + TraceRegister::RCX => regs.rcx, + TraceRegister::RIP => regs.rip, + TraceRegister::RSP => regs.rsp, + TraceRegister::RBP => regs.rbp, + }) + } } impl Drop for KVMDriver { diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index bb058a1f1..38e0ddfae 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -116,6 +116,21 @@ pub enum HyperlightExit { Retry(), } +/// Registers which may be useful for tracing/stack unwinding +#[cfg(feature = "trace_guest")] +pub enum TraceRegister { + /// RAX + RAX, + /// RCX + RCX, + /// RIP + RIP, + /// RSP + RSP, + /// RBP + RBP, +} + /// A common set of hypervisor functionality pub(crate) trait Hypervisor: Debug + Sync + Send { /// Initialise the internally stored vCPU with the given PEB address and @@ -251,6 +266,10 @@ pub(crate) trait Hypervisor: Debug + Sync + Send { ) -> Result<()> { unimplemented!() } + + /// Read a register for trace/unwind purposes + #[cfg(feature = "unwind_guest")] + fn read_trace_reg(&self, reg: TraceRegister) -> Result; } /// A virtual CPU that can be run until an exit occurs From f5a8084077c87580f265e5d23f3d5ecbc28b3b36 Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Thu, 5 Dec 2024 08:56:17 +0000 Subject: [PATCH 039/271] [hyperlight_host/trace] Support collecting guest stacktraces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> Signed-off-by: Doru Blânzeanu --- Cargo.lock | 607 +++++++++--------- src/hyperlight_common/Cargo.toml | 3 +- src/hyperlight_common/src/outb.rs | 5 + src/hyperlight_host/Cargo.toml | 5 +- .../src/hypervisor/hyperv_linux.rs | 13 +- .../src/hypervisor/hyperv_windows.rs | 5 + src/hyperlight_host/src/hypervisor/kvm.rs | 5 + src/hyperlight_host/src/hypervisor/mod.rs | 13 +- src/hyperlight_host/src/mem/elf.rs | 110 +++- src/hyperlight_host/src/mem/exe.rs | 44 +- src/hyperlight_host/src/mem/mgr.rs | 9 +- src/hyperlight_host/src/sandbox/mod.rs | 43 +- src/hyperlight_host/src/sandbox/outb.rs | 82 ++- .../src/sandbox/uninitialized.rs | 13 +- .../src/sandbox/uninitialized_evolve.rs | 12 +- 15 files changed, 636 insertions(+), 333 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0706e2281..c92a5ed2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,20 +13,20 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy 0.7.35", + "zerocopy 0.8.26", ] [[package]] @@ -61,9 +61,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", @@ -76,36 +76,36 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", - "once_cell", + "once_cell_polyfill", "windows-sys 0.59.0", ] @@ -124,6 +124,18 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "async-trait" version = "0.1.88" @@ -137,15 +149,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -209,6 +221,19 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +[[package]] +name = "blake3" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -249,9 +274,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "byteorder" @@ -376,18 +401,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.36" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.36" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -397,15 +422,21 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "constant_time_eq" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "core-foundation-sys" @@ -500,9 +531,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" @@ -633,14 +664,20 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.11" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + [[package]] name = "fastrand" version = "2.3.0" @@ -678,6 +715,20 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "framehop" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a5a3f0acb82df800ca3aa50c0d60d286c5d13d4cfc3114b3a9663f13b032fe" +dependencies = [ + "arrayvec", + "cfg-if", + "fallible-iterator", + "gimli", + "macho-unwind-info", + "pe-unwind-info", +] + [[package]] name = "futures" version = "0.3.31" @@ -793,15 +844,16 @@ dependencies = [ [[package]] name = "generator" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" +checksum = "d18470a76cb7f8ff746cf1f7470914f900252ec36bbc40b569d74b1258446827" dependencies = [ + "cc", "cfg-if", "libc", "log", "rustversion", - "windows 0.58.0", + "windows", ] [[package]] @@ -816,20 +868,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", @@ -842,12 +894,16 @@ name = "gimli" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +dependencies = [ + "fallible-iterator", + "stable_deref_trait", +] [[package]] name = "git2" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5220b8ba44c68a9a7f7a7659e864dd73692e417ef0211bea133c7b74e031eeb9" +checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" dependencies = [ "bitflags 2.9.1", "libc", @@ -898,9 +954,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "foldhash", "serde", @@ -1079,6 +1135,7 @@ version = "0.7.0" dependencies = [ "anyhow", "bitflags 2.9.1", + "blake3", "built", "cfg-if", "cfg_aliases", @@ -1089,7 +1146,9 @@ dependencies = [ "elfcore", "env_logger", "envy", + "fallible-iterator", "flatbuffers", + "framehop", "gdbstub", "gdbstub_arch", "goblin", @@ -1138,8 +1197,8 @@ dependencies = [ "tracing-tracy", "uuid", "vmm-sys-util", - "windows 0.61.3", - "windows-result 0.3.4", + "windows", + "windows-result", "windows-sys 0.60.2", "windows-version", ] @@ -1182,7 +1241,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.61.2", + "windows-core", ] [[package]] @@ -1196,21 +1255,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -1219,31 +1279,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -1251,67 +1291,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "idna" version = "1.0.3" @@ -1325,9 +1352,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -1335,9 +1362,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", "hashbrown", @@ -1412,9 +1439,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.8" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ad87c89110f55e4cd4dc2893a9790820206729eaf221555f742d540b0724a0" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" dependencies = [ "jiff-static", "log", @@ -1425,9 +1452,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.8" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d076d5b64a7e2fe6f0743f02c43ca4a6725c0f904203bfe276a5b3e793103605" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", @@ -1440,7 +1467,7 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "libc", ] @@ -1499,9 +1526,9 @@ dependencies = [ [[package]] name = "libgit2-sys" -version = "0.18.1+1.9.0" +version = "0.18.2+1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1dcb20f84ffcdd825c7a311ae347cce604a6f084a767dec4a4929829645290e" +checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" dependencies = [ "cc", "libc", @@ -1511,12 +1538,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.53.2", ] [[package]] @@ -1532,9 +1559,9 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" dependencies = [ "bitflags 2.9.1", "libc", @@ -1560,15 +1587,15 @@ checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -1595,13 +1622,24 @@ dependencies = [ [[package]] name = "mach2" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" dependencies = [ "libc", ] +[[package]] +name = "macho-unwind-info" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149" +dependencies = [ + "thiserror 2.0.12", + "zerocopy 0.8.26", + "zerocopy-derive 0.8.26", +] + [[package]] name = "managed" version = "0.8.0" @@ -1619,9 +1657,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "metrics" @@ -1675,22 +1713,22 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] @@ -1714,7 +1752,7 @@ dependencies = [ "libc", "num_enum", "vmm-sys-util", - "zerocopy 0.8.24", + "zerocopy 0.8.26", ] [[package]] @@ -1792,18 +1830,19 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ "proc-macro2", "quote", @@ -1825,6 +1864,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + [[package]] name = "oorandom" version = "11.1.5" @@ -1943,9 +1988,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -1953,9 +1998,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -1970,6 +2015,19 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pe-unwind-info" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500fa4cdeacd98997c5865e3d0d1cb8fe7e9d7d75ecc775e07989a433a9a9a59" +dependencies = [ + "arrayvec", + "bitflags 2.9.1", + "thiserror 2.0.12", + "zerocopy 0.8.26", + "zerocopy-derive 0.8.26", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -2050,9 +2108,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "portable-atomic-util" @@ -2063,13 +2121,22 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "ppv-lite86" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.24", + "zerocopy 0.8.26", ] [[package]] @@ -2150,15 +2217,15 @@ dependencies = [ [[package]] name = "quanta" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" dependencies = [ "crossbeam-utils", "libc", "once_cell", "raw-cpuid", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "web-sys", "winapi", ] @@ -2180,9 +2247,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "radix_trie" @@ -2220,7 +2287,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", ] [[package]] @@ -2272,9 +2339,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ "bitflags 2.9.1", ] @@ -2285,7 +2352,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 2.0.12", ] @@ -2336,9 +2403,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.21" +version = "0.12.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8cea6b35bcceb099f30173754403d2eba0a5dc18cea3630fccd88251909288" +checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" dependencies = [ "base64", "bytes", @@ -2406,9 +2473,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustc-hash" @@ -2427,9 +2494,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags 2.9.1", "errno", @@ -2440,9 +2507,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "rusty-fork" @@ -2473,9 +2540,9 @@ dependencies = [ [[package]] name = "scc" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea091f6cac2595aa38993f04f4ee692ed43757035c36e67c180b6828356385b1" +checksum = "22b2d775fb28f245817589471dd49c5edf64237f4a19d10ce9a92ff4651a27f4" dependencies = [ "sdd", ] @@ -2567,9 +2634,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -2613,9 +2680,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -2676,24 +2743,21 @@ checksum = "c1e9a774a6c28142ac54bb25d25562e6bcf957493a184f15ad4eebccb23e410a" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -2751,9 +2815,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", @@ -2767,7 +2831,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.3", "once_cell", "rustix", "windows-sys 0.59.0", @@ -2824,19 +2888,18 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -2896,9 +2959,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -2908,26 +2971,33 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tonic" version = "0.13.1" @@ -3008,9 +3078,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", @@ -3123,9 +3193,9 @@ dependencies = [ [[package]] name = "tracy-client" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d90a2c01305b02b76fdd89ac8608bae27e173c829a35f7d76a345ab5d33836db" +checksum = "ef54005d3d760186fd662dad4b7bb27ecd5531cdef54d1573ebd3f20a9205ed7" dependencies = [ "loom", "once_cell", @@ -3134,9 +3204,9 @@ dependencies = [ [[package]] name = "tracy-client-sys" -version = "0.24.3" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69fff37da548239c3bf9e64a12193d261e8b22b660991c6fd2df057c168f435f" +checksum = "5f9612d9503675b07b244922ea6f6f3cdd88c43add1b3498084613fc88cdf69d" dependencies = [ "cc", "windows-targets 0.52.6", @@ -3177,12 +3247,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -3201,7 +3265,7 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "js-sys", "serde", "wasm-bindgen", @@ -3265,9 +3329,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" @@ -3413,16 +3477,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.61.3" @@ -3430,7 +3484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ "windows-collections", - "windows-core 0.61.2", + "windows-core", "windows-future", "windows-link", "windows-numerics", @@ -3442,20 +3496,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core 0.61.2", -] - -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", + "windows-core", ] [[package]] @@ -3464,11 +3505,11 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", + "windows-implement", + "windows-interface", "windows-link", - "windows-result 0.3.4", - "windows-strings 0.4.2", + "windows-result", + "windows-strings", ] [[package]] @@ -3477,22 +3518,11 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "windows-core 0.61.2", + "windows-core", "windows-link", "windows-threading", ] -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-implement" version = "0.60.0" @@ -3504,17 +3534,6 @@ dependencies = [ "syn", ] -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-interface" version = "0.59.1" @@ -3538,19 +3557,10 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core 0.61.2", + "windows-core", "windows-link", ] -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-result" version = "0.3.4" @@ -3560,16 +3570,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows-strings" version = "0.4.2" @@ -3754,9 +3754,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.6" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" dependencies = [ "memchr", ] @@ -3770,23 +3770,17 @@ dependencies = [ "bitflags 2.9.1", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -3796,9 +3790,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", @@ -3818,11 +3812,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ - "zerocopy-derive 0.8.24", + "zerocopy-derive 0.8.26", ] [[package]] @@ -3838,9 +3832,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", @@ -3868,11 +3862,22 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -3881,9 +3886,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", diff --git a/src/hyperlight_common/Cargo.toml b/src/hyperlight_common/Cargo.toml index 1afea5022..42024e36d 100644 --- a/src/hyperlight_common/Cargo.toml +++ b/src/hyperlight_common/Cargo.toml @@ -25,6 +25,7 @@ spin = "0.10.0" [features] default = ["tracing"] fuzzing = ["dep:arbitrary"] +unwind_guest = [] std = [] [dev-dependencies] @@ -32,4 +33,4 @@ hyperlight-testing = { workspace = true } [lib] bench = false # see https://bheisler.github.io/criterion.rs/book/faq.html#cargo-bench-gives-unrecognized-option-errors-for-valid-command-line-options -doctest = false # reduce noise in test output \ No newline at end of file +doctest = false # reduce noise in test output diff --git a/src/hyperlight_common/src/outb.rs b/src/hyperlight_common/src/outb.rs index 1d15cfb90..efa42aeba 100644 --- a/src/hyperlight_common/src/outb.rs +++ b/src/hyperlight_common/src/outb.rs @@ -90,11 +90,14 @@ impl TryFrom for Exception { /// - CallFunction: makes a call to a host function, /// - Abort: aborts the execution of the guest, /// - DebugPrint: prints a message to the host +/// - TraceRecordStack: records the stack trace of the guest pub enum OutBAction { Log = 99, CallFunction = 101, Abort = 102, DebugPrint = 103, + #[cfg(feature = "unwind_guest")] + TraceRecordStack = 104, } impl TryFrom for OutBAction { @@ -105,6 +108,8 @@ impl TryFrom for OutBAction { 101 => Ok(OutBAction::CallFunction), 102 => Ok(OutBAction::Abort), 103 => Ok(OutBAction::DebugPrint), + #[cfg(feature = "unwind_guest")] + 104 => Ok(OutBAction::TraceRecordStack), _ => Err(anyhow::anyhow!("Invalid OutBAction value: {}", val)), } } diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index a27121d76..0a2311588 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -28,6 +28,8 @@ rand = { version = "0.9" } cfg-if = { version = "1.0.1" } libc = { version = "0.2.174" } flatbuffers = "25.2.10" +framehop = { version = "0.13.1", optional = true } +fallible-iterator = { version = "0.3.0", optional = true } page_size = "0.6.0" termcolor = "1.2.0" bitflags = "2.9.1" @@ -45,6 +47,7 @@ metrics = "0.24.2" serde_json = "1.0" elfcore = "2.0" uuid = { version = "1.17.0", features = ["v4"] } +blake3 = "1.8.2" [target.'cfg(windows)'.dependencies] windows = { version = "0.61", features = [ @@ -131,7 +134,7 @@ crashdump = ["dep:chrono"] trace_guest = [] # This feature enables unwinding the guest stack from the host, in # order to produce stack traces for debugging or profiling. -unwind_guest = [ "trace_guest" ] +unwind_guest = [ "trace_guest", "dep:framehop", "dep:fallible-iterator", "hyperlight-common/unwind_guest" ] kvm = ["dep:kvm-bindings", "dep:kvm-ioctls"] # This feature is deprecated in favor of mshv3 mshv2 = ["dep:mshv-bindings2", "dep:mshv-ioctls2"] diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 5059188dc..ef56a7044 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -1124,6 +1124,11 @@ impl Hypervisor for HypervLinuxDriver { // safety: all registers that we currently support are 64-bit unsafe { Ok(assoc[0].value.reg64) } } + + #[cfg(feature = "trace_guest")] + fn trace_info_as_ref(&self) -> &TraceInfo { + &self.trace_info + } } impl Drop for HypervLinuxDriver { @@ -1143,6 +1148,8 @@ impl Drop for HypervLinuxDriver { #[cfg(test)] mod tests { use super::*; + #[cfg(feature = "unwind_guest")] + use crate::mem::exe::DummyUnwindInfo; use crate::mem::memory_region::MemoryRegionVecBuilder; use crate::mem::shared_mem::{ExclusiveSharedMemory, SharedMemory}; @@ -1211,7 +1218,11 @@ mod tests { guest_core_dump: true, }, #[cfg(feature = "trace_guest")] - TraceInfo::new().unwrap(), + TraceInfo::new( + #[cfg(feature = "unwind_guest")] + Arc::new(DummyUnwindInfo {}), + ) + .unwrap(), ) .unwrap(); } diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index e1263a810..55b01e8bb 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -1057,6 +1057,11 @@ impl Hypervisor for HypervWindowsDriver { TraceRegister::RBP => Ok(regs.rbp), } } + + #[cfg(feature = "trace_guest")] + fn trace_info_as_ref(&self) -> &TraceInfo { + &self.trace_info + } } impl Drop for HypervWindowsDriver { diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index a9adc1c82..b63c44eb4 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -976,6 +976,11 @@ impl Hypervisor for KVMDriver { TraceRegister::RBP => regs.rbp, }) } + + #[cfg(feature = "trace_guest")] + fn trace_info_as_ref(&self) -> &TraceInfo { + &self.trace_info + } } impl Drop for KVMDriver { diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index 38e0ddfae..2be3fdf28 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -20,6 +20,8 @@ use tracing::{Span, instrument}; use crate::error::HyperlightError::ExecutionCanceledByHost; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::metrics::METRIC_GUEST_CANCELLATION; +#[cfg(feature = "trace_guest")] +use crate::sandbox::TraceInfo; use crate::{HyperlightError, Result, log_then_return, new_error}; /// Util for handling x87 fpu state @@ -270,6 +272,10 @@ pub(crate) trait Hypervisor: Debug + Sync + Send { /// Read a register for trace/unwind purposes #[cfg(feature = "unwind_guest")] fn read_trace_reg(&self, reg: TraceRegister) -> Result; + + /// Get a reference of the trace info for the guest + #[cfg(feature = "trace_guest")] + fn trace_info_as_ref(&self) -> &TraceInfo; } /// A virtual CPU that can be run until an exit occurs @@ -278,7 +284,7 @@ pub struct VirtualCPU {} impl VirtualCPU { /// Run the given hypervisor until a halt instruction is reached #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - pub fn run( + pub(crate) fn run( hv: &mut dyn Hypervisor, outb_handle_fn: Arc>, mem_access_fn: Arc>, @@ -526,8 +532,6 @@ pub(crate) mod tests { #[cfg(gdb)] use crate::hypervisor::DbgMemAccessHandlerCaller; use crate::mem::ptr::RawPtr; - #[cfg(feature = "trace_guest")] - use crate::sandbox::TraceInfo; use crate::sandbox::uninitialized::GuestBinary; #[cfg(any(crashdump, gdb))] use crate::sandbox::uninitialized::SandboxRuntimeConfig; @@ -579,8 +583,7 @@ pub(crate) mod tests { &config, #[cfg(any(crashdump, gdb))] &rt_cfg, - #[cfg(feature = "trace_guest")] - TraceInfo::new()?, + sandbox.load_info, )?; let outb_handler: Arc> = { #[cfg(feature = "trace_guest")] diff --git a/src/hyperlight_host/src/mem/elf.rs b/src/hyperlight_host/src/mem/elf.rs index afe7ea4a5..ff83d42c8 100644 --- a/src/hyperlight_host/src/mem/elf.rs +++ b/src/hyperlight_host/src/mem/elf.rs @@ -14,6 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ +#[cfg(feature = "unwind_guest")] +use std::sync::Arc; + #[cfg(target_arch = "aarch64")] use goblin::elf::reloc::{R_AARCH64_NONE, R_AARCH64_RELATIVE}; #[cfg(target_arch = "x86_64")] @@ -26,13 +29,85 @@ use goblin::elf64::program_header::PT_LOAD; use crate::{Result, log_then_return, new_error}; +#[cfg(feature = "unwind_guest")] +struct ResolvedSectionHeader { + name: String, + addr: u64, + offset: u64, + size: u64, +} + pub(crate) struct ElfInfo { payload: Vec, phdrs: ProgramHeaders, + #[cfg(feature = "unwind_guest")] + shdrs: Vec, entry: u64, relocs: Vec, } +#[cfg(feature = "unwind_guest")] +struct UnwindInfo { + payload: Vec, + load_addr: u64, + va_size: u64, + base_svma: u64, + shdrs: Vec, +} + +#[cfg(feature = "unwind_guest")] +impl super::exe::UnwindInfo for UnwindInfo { + fn as_module(&self) -> framehop::Module> { + framehop::Module::new( + // TODO: plumb through a name from from_file if this + // came from a file + "guest".to_string(), + self.load_addr..self.load_addr + self.va_size, + self.load_addr, + self, + ) + } + fn hash(&self) -> blake3::Hash { + blake3::hash(&self.payload) + } +} + +#[cfg(feature = "unwind_guest")] +impl UnwindInfo { + fn resolved_section_header(&self, name: &[u8]) -> Option<&ResolvedSectionHeader> { + self.shdrs + .iter() + .find(|&sh| sh.name.as_bytes()[0..core::cmp::min(name.len(), sh.name.len())] == *name) + } +} + +#[cfg(feature = "unwind_guest")] +impl framehop::ModuleSectionInfo> for &UnwindInfo { + fn base_svma(&self) -> u64 { + self.base_svma + } + fn section_svma_range(&mut self, name: &[u8]) -> Option> { + let shdr = self.resolved_section_header(name)?; + Some(shdr.addr..shdr.addr + shdr.size) + } + fn section_data(&mut self, name: &[u8]) -> Option> { + if name == b".eh_frame" && self.resolved_section_header(b".debug_frame").is_some() { + /* Rustc does not always emit enough information for stack + * unwinding in .eh_frame, presumably because we use panic = + * abort in the guest. Framehop defaults to ignoring + * .debug_frame if .eh_frame exists, but we want the opposite + * behaviour here, since .debug_frame will actually contain + * frame information whereas .eh_frame often doesn't because + * of the aforementioned behaviour. Consequently, we hack + * around this by pretending that .eh_frame doesn't exist if + * .debug_frame does. */ + return None; + } + let shdr = self.resolved_section_header(name)?; + Some(self.payload[shdr.offset as usize..(shdr.offset + shdr.size) as usize].to_vec()) + } +} + impl ElfInfo { pub(crate) fn new(bytes: &[u8]) -> Result { let elf = Elf::parse(bytes)?; @@ -47,6 +122,19 @@ impl ElfInfo { Ok(ElfInfo { payload: bytes.to_vec(), phdrs: elf.program_headers, + #[cfg(feature = "unwind_guest")] + shdrs: elf + .section_headers + .iter() + .filter_map(|sh| { + Some(ResolvedSectionHeader { + name: elf.shdr_strtab.get_at(sh.sh_name)?.to_string(), + addr: sh.sh_addr, + offset: sh.sh_offset, + size: sh.sh_size, + }) + }) + .collect(), entry: elf.entry, relocs, }) @@ -73,7 +161,11 @@ impl ElfInfo { .unwrap(); (max_phdr.p_vaddr + max_phdr.p_memsz - self.get_base_va()) as usize } - pub(crate) fn load_at(&mut self, load_addr: usize, target: &mut [u8]) -> Result<()> { + pub(crate) fn load_at( + self, + load_addr: usize, + target: &mut [u8], + ) -> Result { let base_va = self.get_base_va(); for phdr in self.phdrs.iter().filter(|phdr| phdr.p_type == PT_LOAD) { let start_va = (phdr.p_vaddr - base_va) as usize; @@ -113,6 +205,20 @@ impl ElfInfo { } } } - Ok(()) + cfg_if::cfg_if! { + if #[cfg(feature = "unwind_guest")] { + let va_size = self.get_va_size() as u64; + let base_svma = self.get_base_va(); + Ok(Arc::new(UnwindInfo { + payload: self.payload, + load_addr: load_addr as u64, + va_size, + base_svma, + shdrs: self.shdrs, + })) + } else { + Ok(()) + } + } } } diff --git a/src/hyperlight_host/src/mem/exe.rs b/src/hyperlight_host/src/mem/exe.rs index 6f72b7cae..064d58cde 100644 --- a/src/hyperlight_host/src/mem/exe.rs +++ b/src/hyperlight_host/src/mem/exe.rs @@ -16,6 +16,8 @@ limitations under the License. use std::fs::File; use std::io::Read; +#[cfg(feature = "unwind_guest")] +use std::sync::Arc; use std::vec::Vec; use super::elf::ElfInfo; @@ -37,6 +39,41 @@ pub enum ExeInfo { const DEFAULT_ELF_STACK_RESERVE: u64 = 65536; const DEFAULT_ELF_HEAP_RESERVE: u64 = 131072; +#[cfg(feature = "unwind_guest")] +pub(crate) trait UnwindInfo: Send + Sync { + fn as_module(&self) -> framehop::Module>; + fn hash(&self) -> blake3::Hash; +} + +#[cfg(feature = "unwind_guest")] +pub(crate) struct DummyUnwindInfo {} +#[cfg(feature = "unwind_guest")] +impl UnwindInfo for DummyUnwindInfo { + fn as_module(&self) -> framehop::Module> { + framehop::Module::new("unsupported".to_string(), 0..0, 0, self) + } + fn hash(&self) -> blake3::Hash { + blake3::Hash::from_bytes([0; 32]) + } +} +#[cfg(feature = "unwind_guest")] +impl framehop::ModuleSectionInfo for &DummyUnwindInfo { + fn base_svma(&self) -> u64 { + 0 + } + fn section_svma_range(&mut self, _name: &[u8]) -> Option> { + None + } + fn section_data(&mut self, _name: &[u8]) -> Option { + None + } +} + +#[cfg(feature = "unwind_guest")] +pub(crate) type LoadInfo = Arc; +#[cfg(not(feature = "unwind_guest"))] +pub(crate) type LoadInfo = (); + impl ExeInfo { pub fn from_file(path: &str) -> Result { let mut file = File::open(path)?; @@ -71,12 +108,9 @@ impl ExeInfo { // copying into target, but the PE loader chooses to apply // relocations in its owned representation of the PE contents, // which requires it to be &mut. - pub fn load(self, load_addr: usize, target: &mut [u8]) -> Result<()> { + pub fn load(self, load_addr: usize, target: &mut [u8]) -> Result { match self { - ExeInfo::Elf(mut elf) => { - elf.load_at(load_addr, target)?; - } + ExeInfo::Elf(elf) => elf.load_at(load_addr, target), } - Ok(()) } } diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 856e9b361..2f268c409 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -313,7 +313,7 @@ impl SandboxMemoryManager { cfg: SandboxConfiguration, exe_info: ExeInfo, guest_blob: Option<&GuestBlob>, - ) -> Result { + ) -> Result<(Self, super::exe::LoadInfo)> { let guest_blob_size = guest_blob.map(|b| b.data.len()).unwrap_or(0); let guest_blob_mem_flags = guest_blob.map(|b| b.permissions); @@ -339,12 +339,15 @@ impl SandboxMemoryManager { shared_mem.write_u64(offset, load_addr_u64)?; } - exe_info.load( + let load_info = exe_info.load( load_addr.clone().try_into()?, &mut shared_mem.as_mut_slice()[layout.get_guest_code_offset()..], )?; - Ok(Self::new(layout, shared_mem, load_addr, entrypoint_offset)) + Ok(( + Self::new(layout, shared_mem, load_addr, entrypoint_offset), + load_info, + )) } /// Writes host function details to memory diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index 209fb167c..5a2f7be71 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -43,6 +43,8 @@ pub mod snapshot; /// Trait used by the macros to paper over the differences between hyperlight and hyperlight-wasm mod callable; +#[cfg(feature = "unwind_guest")] +use std::io::Write; #[cfg(feature = "trace_guest")] use std::sync::{Arc, Mutex}; @@ -50,6 +52,8 @@ use std::sync::{Arc, Mutex}; pub use callable::Callable; /// Re-export for `SandboxConfiguration` type pub use config::SandboxConfiguration; +#[cfg(feature = "unwind_guest")] +use framehop::Unwinder; /// Re-export for the `MultiUseSandbox` type pub use initialized_multi_use::MultiUseSandbox; use tracing::{Span, instrument}; @@ -104,20 +108,53 @@ pub(crate) struct TraceInfo { /// The file to which the trace is being written #[allow(dead_code)] pub file: Arc>, + /// The unwind information for the current guest + #[cfg(feature = "unwind_guest")] + #[allow(dead_code)] + pub unwind_module: Arc, + /// The framehop unwinder for the current guest + #[cfg(feature = "unwind_guest")] + pub unwinder: framehop::x86_64::UnwinderX86_64>, + /// The framehop cache + #[cfg(feature = "unwind_guest")] + pub unwind_cache: Arc>, } #[cfg(feature = "trace_guest")] impl TraceInfo { /// Create a new TraceInfo by saving the current time as the epoch /// and generating a random filename. - pub fn new() -> crate::Result { + pub fn new( + #[cfg(feature = "unwind_guest")] unwind_module: Arc, + ) -> crate::Result { let mut path = std::env::current_dir()?; path.push("trace"); path.push(uuid::Uuid::new_v4().to_string()); path.set_extension("trace"); - Ok(Self { + #[cfg(feature = "unwind_guest")] + let hash = unwind_module.hash(); + #[cfg(feature = "unwind_guest")] + let (unwinder, unwind_cache) = { + let mut unwinder = framehop::x86_64::UnwinderX86_64::new(); + unwinder.add_module(unwind_module.clone().as_module()); + let cache = framehop::x86_64::CacheX86_64::new(); + (unwinder, Arc::new(Mutex::new(cache))) + }; + let ret = Self { epoch: std::time::Instant::now(), file: Arc::new(Mutex::new(std::fs::File::create_new(path)?)), - }) + #[cfg(feature = "unwind_guest")] + unwind_module, + #[cfg(feature = "unwind_guest")] + unwinder, + #[cfg(feature = "unwind_guest")] + unwind_cache, + }; + /* write a frame identifying the binary */ + #[cfg(feature = "unwind_guest")] + self::outb::record_trace_frame(&ret, 0, |f| { + let _ = f.write_all(hash.as_bytes()); + })?; + Ok(ret) } } diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index 5b25248ae..c1b210c44 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -14,8 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ +#[cfg(feature = "unwind_guest")] +use std::io::Write; use std::sync::{Arc, Mutex}; +#[cfg(feature = "unwind_guest")] +use fallible_iterator::FallibleIterator; +#[cfg(feature = "unwind_guest")] +use framehop::Unwinder; use hyperlight_common::flatbuffer_wrappers::function_types::ParameterValue; use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_common::flatbuffer_wrappers::guest_log_data::GuestLogData; @@ -26,12 +32,14 @@ use tracing_log::format_trace; use super::host_funcs::FunctionRegistry; use super::mem_mgr::MemMgrWrapper; -#[cfg(feature = "trace_guest")] -use crate::hypervisor::Hypervisor; use crate::hypervisor::handlers::{OutBHandler, OutBHandlerFunction, OutBHandlerWrapper}; +#[cfg(feature = "unwind_guest")] +use crate::mem::layout::SandboxMemoryLayout; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; use crate::{HyperlightError, Result, new_error}; +#[cfg(feature = "trace_guest")] +use crate::{hypervisor::Hypervisor, sandbox::TraceInfo}; #[instrument(err(Debug), skip_all, parent = Span::current(), level="Trace")] pub(super) fn outb_log(mgr: &mut SandboxMemoryManager) -> Result<()> { @@ -142,7 +150,64 @@ fn outb_abort(mem_mgr: &mut MemMgrWrapper, data: u32) -> Resul buffer.push(b); } + Ok(()) +} + +#[cfg(feature = "unwind_guest")] +fn unwind( + hv: &dyn Hypervisor, + mem: &SandboxMemoryManager, + trace_info: &TraceInfo, +) -> Result> { + let mut read_stack = |addr| { + mem.shared_mem + .read::((addr - SandboxMemoryLayout::BASE_ADDRESS as u64) as usize) + .map_err(|_| ()) + }; + let mut cache = trace_info + .unwind_cache + .try_lock() + .map_err(|e| new_error!("could not lock unwinder cache {}\n", e))?; + let iter = trace_info.unwinder.iter_frames( + hv.read_trace_reg(crate::hypervisor::TraceRegister::RIP)?, + framehop::x86_64::UnwindRegsX86_64::new( + hv.read_trace_reg(crate::hypervisor::TraceRegister::RIP)?, + hv.read_trace_reg(crate::hypervisor::TraceRegister::RSP)?, + hv.read_trace_reg(crate::hypervisor::TraceRegister::RBP)?, + ), + &mut *cache, + &mut read_stack, + ); + iter.map(|f| Ok(f.address() - mem.layout.get_guest_code_address() as u64)) + .collect() + .map_err(|e| new_error!("couldn't unwind: {}", e)) +} + +#[cfg(feature = "unwind_guest")] +fn write_stack(out: &mut std::fs::File, stack: &[u64]) { + let _ = out.write_all(&stack.len().to_ne_bytes()); + for frame in stack { + let _ = out.write_all(&frame.to_ne_bytes()); + } +} +#[cfg(feature = "unwind_guest")] +pub(super) fn record_trace_frame( + trace_info: &TraceInfo, + frame_id: u64, + write_frame: F, +) -> Result<()> { + let Ok(mut out) = trace_info.file.lock() else { + return Ok(()); + }; + // frame structure: + // 16 bytes timestamp + let now = std::time::Instant::now().saturating_duration_since(trace_info.epoch); + let _ = out.write_all(&now.as_micros().to_ne_bytes()); + // 8 bytes frame type id + let _ = out.write_all(&frame_id.to_ne_bytes()); + // frame data + write_frame(&mut out); Ok(()) } @@ -183,6 +248,15 @@ fn handle_outb_impl( eprint!("{}", ch); Ok(()) } + #[cfg(feature = "unwind_guest")] + OutBAction::TraceRecordStack => { + let Ok(stack) = unwind(_hv, mem_mgr.as_ref(), _hv.trace_info_as_ref()) else { + return Ok(()); + }; + record_trace_frame(_hv.trace_info_as_ref(), 1u64, |f| { + write_stack(f, &stack); + }) + } } } @@ -247,7 +321,7 @@ mod tests { let new_mgr = || { let exe_info = simple_guest_exe_info().unwrap(); - let mut mgr = + let (mut mgr, _) = SandboxMemoryManager::load_guest_binary_into_memory(sandbox_cfg, exe_info, None) .unwrap(); let mem_size = mgr.get_shared_mem_mut().mem_size(); @@ -359,7 +433,7 @@ mod tests { tracing::subscriber::with_default(subscriber.clone(), || { let new_mgr = || { let exe_info = simple_guest_exe_info().unwrap(); - let mut mgr = SandboxMemoryManager::load_guest_binary_into_memory( + let (mut mgr, _) = SandboxMemoryManager::load_guest_binary_into_memory( sandbox_cfg, exe_info, None, diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index b2a69cd29..cfac5979c 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -78,6 +78,7 @@ pub struct UninitializedSandbox { pub(crate) config: SandboxConfiguration, #[cfg(any(crashdump, gdb))] pub(crate) rt_cfg: SandboxRuntimeConfig, + pub(crate) load_info: crate::mem::exe::LoadInfo, } impl Debug for UninitializedSandbox { @@ -222,8 +223,8 @@ impl UninitializedSandbox { } }; - let mut mem_mgr_wrapper = { - let mut mgr = UninitializedSandbox::load_guest_binary( + let (mut mem_mgr_wrapper, load_info) = { + let (mut mgr, load_info) = UninitializedSandbox::load_guest_binary( sandbox_cfg, &guest_binary, guest_blob.as_ref(), @@ -231,7 +232,7 @@ impl UninitializedSandbox { let stack_guard = Self::create_stack_guard(); mgr.set_stack_guard(&stack_guard)?; - MemMgrWrapper::new(mgr, stack_guard) + (MemMgrWrapper::new(mgr, stack_guard), load_info) }; mem_mgr_wrapper.write_memory_layout()?; @@ -250,6 +251,7 @@ impl UninitializedSandbox { config: sandbox_cfg, #[cfg(any(crashdump, gdb))] rt_cfg, + load_info, }; // If we were passed a writer for host print register it otherwise use the default. @@ -280,7 +282,10 @@ impl UninitializedSandbox { cfg: SandboxConfiguration, guest_binary: &GuestBinary, guest_blob: Option<&GuestBlob>, - ) -> Result> { + ) -> Result<( + SandboxMemoryManager, + crate::mem::exe::LoadInfo, + )> { let exe_info = match guest_binary { GuestBinary::FilePath(bin_path_str) => ExeInfo::from_file(bin_path_str)?, GuestBinary::Buffer(buffer) => ExeInfo::from_buf(buffer)?, diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index 07747dd9d..ca6eb9e35 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -28,6 +28,7 @@ use super::uninitialized::SandboxRuntimeConfig; use crate::HyperlightError::NoHypervisorFound; use crate::hypervisor::Hypervisor; use crate::hypervisor::handlers::{MemAccessHandlerCaller, OutBHandlerCaller}; +use crate::mem::exe::LoadInfo; use crate::mem::layout::SandboxMemoryLayout; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::ptr::{GuestPtr, RawPtr}; @@ -79,8 +80,7 @@ where &u_sbox.config, #[cfg(any(crashdump, gdb))] &u_sbox.rt_cfg, - #[cfg(feature = "trace_guest")] - TraceInfo::new()?, + u_sbox.load_info, )?; let outb_hdl = outb_handler_wrapper(hshm.clone(), u_sbox.host_funcs.clone()); @@ -150,7 +150,7 @@ pub(crate) fn set_up_hypervisor_partition( mgr: &mut SandboxMemoryManager, #[cfg_attr(target_os = "windows", allow(unused_variables))] config: &SandboxConfiguration, #[cfg(any(crashdump, gdb))] rt_cfg: &SandboxRuntimeConfig, - #[cfg(feature = "trace_guest")] trace_info: TraceInfo, + _load_info: LoadInfo, ) -> Result> { #[cfg(feature = "init-paging")] let rsp_ptr = { @@ -209,6 +209,12 @@ pub(crate) fn set_up_hypervisor_partition( None }; + #[cfg(feature = "trace_guest")] + let trace_info = TraceInfo::new( + #[cfg(feature = "unwind_guest")] + _load_info, + )?; + match *get_available_hypervisor() { #[cfg(mshv)] Some(HypervisorType::Mshv) => { From e027582b4824e6ef2927b47e74375e3cd7d8d653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Thu, 3 Jul 2025 12:13:32 +0300 Subject: [PATCH 040/271] allow dead code for unused functions triggered by previous commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- src/hyperlight_host/src/mem/layout.rs | 5 +++++ src/hyperlight_host/src/mem/mgr.rs | 1 + src/hyperlight_host/src/mem/ptr_offset.rs | 2 ++ src/hyperlight_host/src/mem/shared_mem.rs | 2 ++ src/hyperlight_host/src/mem/shared_mem_snapshot.rs | 2 +- src/hyperlight_host/src/sandbox/host_funcs.rs | 1 + 6 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/hyperlight_host/src/mem/layout.rs b/src/hyperlight_host/src/mem/layout.rs index 04edc9bcc..a8a1e5fc9 100644 --- a/src/hyperlight_host/src/mem/layout.rs +++ b/src/hyperlight_host/src/mem/layout.rs @@ -381,6 +381,7 @@ impl SandboxMemoryLayout { /// Get the offset in guest memory to the OutB pointer. #[instrument(skip_all, parent = Span::current(), level= "Trace")] + #[allow(dead_code)] pub(super) fn get_outb_pointer_offset(&self) -> usize { // The outb pointer is immediately after the code pointer // in the `CodeAndOutBPointers` struct which is a u64 @@ -389,6 +390,7 @@ impl SandboxMemoryLayout { /// Get the offset in guest memory to the OutB context. #[instrument(skip_all, parent = Span::current(), level= "Trace")] + #[allow(dead_code)] pub(super) fn get_outb_context_offset(&self) -> usize { // The outb context is immediately after the outb pointer // in the `CodeAndOutBPointers` struct which is a u64 @@ -416,6 +418,7 @@ impl SandboxMemoryLayout { /// This function exists to accommodate the macro that generates C API /// compatible functions. #[instrument(skip_all, parent = Span::current(), level= "Trace")] + #[allow(dead_code)] pub(crate) fn get_output_data_offset(&self) -> usize { self.output_data_buffer_offset } @@ -452,6 +455,7 @@ impl SandboxMemoryLayout { /// Get the offset in guest memory to the PEB address #[instrument(skip_all, parent = Span::current(), level= "Trace")] + #[allow(dead_code)] pub(super) fn get_in_process_peb_offset(&self) -> usize { self.peb_offset } @@ -486,6 +490,7 @@ impl SandboxMemoryLayout { /// Get the offset to the guest guard page #[instrument(skip_all, parent = Span::current(), level= "Trace")] + #[allow(dead_code)] pub fn get_guard_page_offset(&self) -> usize { self.guard_page_offset } diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 2f268c409..3abdb11fe 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -285,6 +285,7 @@ where /// `shared_mem` to indicate the address of the outb pointer and context /// for calling outb function #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] + #[allow(dead_code)] pub(crate) fn set_outb_address_and_context(&mut self, addr: u64, context: u64) -> Result<()> { let pointer_offset = self.layout.get_outb_pointer_offset(); let context_offset = self.layout.get_outb_context_offset(); diff --git a/src/hyperlight_host/src/mem/ptr_offset.rs b/src/hyperlight_host/src/mem/ptr_offset.rs index 673767e36..a8105ed70 100644 --- a/src/hyperlight_host/src/mem/ptr_offset.rs +++ b/src/hyperlight_host/src/mem/ptr_offset.rs @@ -32,11 +32,13 @@ pub(crate) struct Offset(u64); impl Offset { /// Get the offset representing `0` #[instrument(skip_all, parent = Span::current(), level= "Trace")] + #[allow(dead_code)] pub(super) fn zero() -> Self { Self::default() } /// round up to the nearest multiple of `alignment` + #[allow(dead_code)] pub(super) fn round_up_to(self, alignment: u64) -> Self { let remainder = self.0 % alignment; let multiples = self.0 / alignment; diff --git a/src/hyperlight_host/src/mem/shared_mem.rs b/src/hyperlight_host/src/mem/shared_mem.rs index 50c809f44..23d0b7fcf 100644 --- a/src/hyperlight_host/src/mem/shared_mem.rs +++ b/src/hyperlight_host/src/mem/shared_mem.rs @@ -502,6 +502,7 @@ impl ExclusiveSharedMemory { }) } + #[allow(dead_code)] pub(super) fn make_memory_executable(&self) -> Result<()> { #[cfg(target_os = "windows")] { @@ -616,6 +617,7 @@ impl ExclusiveSharedMemory { /// Return the address of memory at an offset to this `SharedMemory` checking /// that the memory is within the bounds of the `SharedMemory`. #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] + #[allow(dead_code)] pub(crate) fn calculate_address(&self, offset: usize) -> Result { bounds_check!(offset, 0, self.mem_size()); Ok(self.base_addr() + offset) diff --git a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs index b7f461716..dfa54430c 100644 --- a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs +++ b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs @@ -44,7 +44,7 @@ impl SharedMemorySnapshot { /// Take another snapshot of the internally-stored `SharedMemory`, /// then store it internally. #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - + #[allow(dead_code)] pub(super) fn replace_snapshot(&mut self, shared_mem: &mut S) -> Result<()> { self.snapshot = shared_mem.with_exclusivity(|e| e.copy_all_to_vec())??; Ok(()) diff --git a/src/hyperlight_host/src/sandbox/host_funcs.rs b/src/hyperlight_host/src/sandbox/host_funcs.rs index 96751f391..6d3c8d98a 100644 --- a/src/hyperlight_host/src/sandbox/host_funcs.rs +++ b/src/hyperlight_host/src/sandbox/host_funcs.rs @@ -93,6 +93,7 @@ impl FunctionRegistry { /// Return `Ok` if the function was found and was of the right signature, /// and `Err` otherwise. #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] + #[allow(dead_code)] pub(super) fn host_print(&mut self, msg: String) -> Result { let res = self.call_host_func_impl("HostPrint", vec![ParameterValue::String(msg)])?; res.try_into() From d26ccba949aa22006bd40a09dba6860a76beea06 Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Fri, 6 Dec 2024 12:41:55 +0000 Subject: [PATCH 041/271] Add trace support for recording memory allocations and frees MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows for producing profiles of memory usage. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> Signed-off-by: Doru Blânzeanu --- src/hyperlight_common/Cargo.toml | 1 + src/hyperlight_common/src/outb.rs | 10 ++++ src/hyperlight_guest_bin/Cargo.toml | 1 + src/hyperlight_guest_bin/src/lib.rs | 68 ++++++++++++++++++++++++- src/hyperlight_host/Cargo.toml | 3 +- src/hyperlight_host/src/sandbox/outb.rs | 30 +++++++++++ 6 files changed, 111 insertions(+), 2 deletions(-) diff --git a/src/hyperlight_common/Cargo.toml b/src/hyperlight_common/Cargo.toml index 42024e36d..cf317bd9d 100644 --- a/src/hyperlight_common/Cargo.toml +++ b/src/hyperlight_common/Cargo.toml @@ -26,6 +26,7 @@ spin = "0.10.0" default = ["tracing"] fuzzing = ["dep:arbitrary"] unwind_guest = [] +mem_profile = [] std = [] [dev-dependencies] diff --git a/src/hyperlight_common/src/outb.rs b/src/hyperlight_common/src/outb.rs index efa42aeba..43f07a9cf 100644 --- a/src/hyperlight_common/src/outb.rs +++ b/src/hyperlight_common/src/outb.rs @@ -91,6 +91,8 @@ impl TryFrom for Exception { /// - Abort: aborts the execution of the guest, /// - DebugPrint: prints a message to the host /// - TraceRecordStack: records the stack trace of the guest +/// - TraceMemoryAlloc: records memory allocation events +/// - TraceMemoryFree: records memory deallocation events pub enum OutBAction { Log = 99, CallFunction = 101, @@ -98,6 +100,10 @@ pub enum OutBAction { DebugPrint = 103, #[cfg(feature = "unwind_guest")] TraceRecordStack = 104, + #[cfg(feature = "mem_profile")] + TraceMemoryAlloc, + #[cfg(feature = "mem_profile")] + TraceMemoryFree, } impl TryFrom for OutBAction { @@ -110,6 +116,10 @@ impl TryFrom for OutBAction { 103 => Ok(OutBAction::DebugPrint), #[cfg(feature = "unwind_guest")] 104 => Ok(OutBAction::TraceRecordStack), + #[cfg(feature = "mem_profile")] + 105 => Ok(OutBAction::TraceMemoryAlloc), + #[cfg(feature = "mem_profile")] + 106 => Ok(OutBAction::TraceMemoryFree), _ => Err(anyhow::anyhow!("Invalid OutBAction value: {}", val)), } } diff --git a/src/hyperlight_guest_bin/Cargo.toml b/src/hyperlight_guest_bin/Cargo.toml index 1b8202f51..a0347f866 100644 --- a/src/hyperlight_guest_bin/Cargo.toml +++ b/src/hyperlight_guest_bin/Cargo.toml @@ -17,6 +17,7 @@ and third-party code used by our C-API needed to build a native hyperlight-guest default = ["libc", "printf"] libc = [] # compile musl libc printf = [] # compile printf +mem_profile = ["hyperlight-common/unwind_guest","hyperlight-common/mem_profile"] [dependencies] hyperlight-guest = { workspace = true, default-features = false } diff --git a/src/hyperlight_guest_bin/src/lib.rs b/src/hyperlight_guest_bin/src/lib.rs index 5f153ebd2..133e282e7 100644 --- a/src/hyperlight_guest_bin/src/lib.rs +++ b/src/hyperlight_guest_bin/src/lib.rs @@ -28,6 +28,8 @@ use guest_function::register::GuestFunctionRegister; use guest_logger::init_logger; use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_common::mem::HyperlightPEB; +#[cfg(feature = "mem_profile")] +use hyperlight_common::outb::OutBAction; use hyperlight_guest::exit::{abort_with_code_and_message, halt}; use hyperlight_guest::guest_handle::handle::GuestHandle; use log::LevelFilter; @@ -54,9 +56,69 @@ pub mod host_comm; pub mod memory; pub mod paging; +// Globals +#[cfg(feature = "mem_profile")] +struct ProfiledLockedHeap(LockedHeap); +#[cfg(feature = "mem_profile")] +unsafe impl alloc::alloc::GlobalAlloc for ProfiledLockedHeap { + unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { + let addr = unsafe { self.0.alloc(layout) }; + unsafe { + core::arch::asm!("out dx, al", + in("dx") OutBAction::TraceMemoryAlloc as u16, + in("rax") layout.size() as u64, + in("rcx") addr as u64); + } + addr + } + unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { + unsafe { + core::arch::asm!("out dx, al", + in("dx") OutBAction::TraceMemoryFree as u16, + in("rax") layout.size() as u64, + in("rcx") ptr as u64); + self.0.dealloc(ptr, layout) + } + } + unsafe fn alloc_zeroed(&self, layout: core::alloc::Layout) -> *mut u8 { + let addr = unsafe { self.0.alloc_zeroed(layout) }; + unsafe { + core::arch::asm!("out dx, al", + in("dx") OutBAction::TraceMemoryAlloc as u16, + in("rax") layout.size() as u64, + in("rcx") addr as u64); + } + addr + } + unsafe fn realloc( + &self, + ptr: *mut u8, + layout: core::alloc::Layout, + new_size: usize, + ) -> *mut u8 { + let new_ptr = unsafe { self.0.realloc(ptr, layout, new_size) }; + unsafe { + core::arch::asm!("out dx, al", + in("dx") OutBAction::TraceMemoryFree as u16, + in("rax") layout.size() as u64, + in("rcx") ptr); + core::arch::asm!("out dx, al", + in("dx") OutBAction::TraceMemoryAlloc as u16, + in("rax") new_size as u64, + in("rcx") new_ptr); + } + new_ptr + } +} + // === Globals === +#[cfg(not(feature = "mem_profile"))] #[global_allocator] pub(crate) static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::empty(); +#[cfg(feature = "mem_profile")] +#[global_allocator] +pub(crate) static HEAP_ALLOCATOR: ProfiledLockedHeap<32> = + ProfiledLockedHeap(LockedHeap::<32>::empty()); pub(crate) static mut GUEST_HANDLE: GuestHandle = GuestHandle::new(); pub(crate) static mut REGISTERED_GUEST_FUNCTIONS: GuestFunctionRegister = @@ -129,7 +191,11 @@ pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_leve let heap_start = (*peb_ptr).guest_heap.ptr as usize; let heap_size = (*peb_ptr).guest_heap.size as usize; - HEAP_ALLOCATOR + #[cfg(not(feature = "mem_profile"))] + let heap_allocator = &HEAP_ALLOCATOR; + #[cfg(feature = "mem_profile")] + let heap_allocator = &HEAP_ALLOCATOR.0; + heap_allocator .try_lock() .expect("Failed to access HEAP_ALLOCATOR") .init(heap_start, heap_size); diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 0a2311588..76a152b38 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -30,6 +30,7 @@ libc = { version = "0.2.174" } flatbuffers = "25.2.10" framehop = { version = "0.13.1", optional = true } fallible-iterator = { version = "0.3.0", optional = true } +blake3 = "1.8.2" page_size = "0.6.0" termcolor = "1.2.0" bitflags = "2.9.1" @@ -47,7 +48,6 @@ metrics = "0.24.2" serde_json = "1.0" elfcore = "2.0" uuid = { version = "1.17.0", features = ["v4"] } -blake3 = "1.8.2" [target.'cfg(windows)'.dependencies] windows = { version = "0.61", features = [ @@ -135,6 +135,7 @@ trace_guest = [] # This feature enables unwinding the guest stack from the host, in # order to produce stack traces for debugging or profiling. unwind_guest = [ "trace_guest", "dep:framehop", "dep:fallible-iterator", "hyperlight-common/unwind_guest" ] +mem_profile = [ "unwind_guest", "hyperlight-common/mem_profile" ] kvm = ["dep:kvm-bindings", "dep:kvm-ioctls"] # This feature is deprecated in favor of mshv3 mshv2 = ["dep:mshv-bindings2", "dep:mshv-ioctls2"] diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index c1b210c44..5a559321a 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -257,6 +257,36 @@ fn handle_outb_impl( write_stack(f, &stack); }) } + #[cfg(feature = "mem_profile")] + OutBAction::TraceMemoryAlloc => { + let Ok(stack) = unwind(_hv, mem_mgr.as_ref(), _hv.trace_info_as_ref()) else { + return Ok(()); + }; + let Ok(amt) = _hv.read_trace_reg(crate::hypervisor::TraceRegister::RAX) else { + return Ok(()); + }; + let Ok(ptr) = _hv.read_trace_reg(crate::hypervisor::TraceRegister::RCX) else { + return Ok(()); + }; + record_trace_frame(_hv.trace_info_as_ref(), 2u64, |f| { + let _ = f.write_all(&ptr.to_ne_bytes()); + let _ = f.write_all(&amt.to_ne_bytes()); + write_stack(f, &stack); + }) + } + #[cfg(feature = "mem_profile")] + OutBAction::TraceMemoryFree => { + let Ok(stack) = unwind(_hv, mem_mgr.as_ref(), _hv.trace_info_as_ref()) else { + return Ok(()); + }; + let Ok(ptr) = _hv.read_trace_reg(crate::hypervisor::TraceRegister::RCX) else { + return Ok(()); + }; + record_trace_frame(_hv.trace_info_as_ref(), 3u64, |f| { + let _ = f.write_all(&ptr.to_ne_bytes()); + write_stack(f, &stack); + }) + } } } From 7cc9a7afac0ce74c0eb43be1d405e3a259862ab0 Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Fri, 6 Dec 2024 12:54:05 +0000 Subject: [PATCH 042/271] Add basic utility for dumping logs and memory statistics from traces Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- Cargo.lock | 717 ++++++++++++++++++++++++++++++-- Cargo.toml | 1 + src/trace_dump/Cargo.toml | 14 + src/trace_dump/main.rs | 831 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 1529 insertions(+), 34 deletions(-) create mode 100644 src/trace_dump/Cargo.toml create mode 100644 src/trace_dump/main.rs diff --git a/Cargo.lock b/Cargo.lock index c92a5ed2c..709611f13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,14 @@ version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ + "cpp_demangle", + "fallible-iterator", "gimli", + "memmap2", + "object", + "rustc-demangle", + "smallvec", + "typed-arena", ] [[package]] @@ -136,6 +143,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "associative-cache" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46016233fc1bb55c23b856fe556b7db6ccd05119a0a392e04f0b3b7c79058f16" + [[package]] name = "async-trait" version = "0.1.88" @@ -144,7 +157,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -191,7 +204,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 2.0.104", ] [[package]] @@ -290,6 +303,31 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +[[package]] +name = "cairo-rs" +version = "0.16.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3125b15ec28b84c238f6f476c6034016a5f6cc0221cb514ca46c532139fc97d" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror 1.0.69", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c48f4af05fabdcfa9658178e1326efa061853f040ce7d72e33af6885196f421" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + [[package]] name = "cast" version = "0.3.0" @@ -303,14 +341,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "975982cdb7ad6a142be15bdf84aea7ec6a9e5d4d797c004d43185b24cfe4e684" dependencies = [ "clap", - "heck", + "heck 0.5.0", "indexmap", "log", "proc-macro2", "quote", "serde", "serde_json", - "syn", + "syn 2.0.104", "tempfile", "toml", ] @@ -335,6 +373,16 @@ dependencies = [ "nom", ] +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.1" @@ -438,12 +486,67 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "core-text" +version = "19.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" +dependencies = [ + "core-foundation", + "core-graphics", + "foreign-types", + "libc", +] + +[[package]] +name = "cpp_demangle" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96e58d342ad113c2b878f16d5d034c03be492ae460cdbc02b7f0f2284d310c7d" +dependencies = [ + "cfg-if", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -453,6 +556,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "criterion" version = "0.6.0" @@ -553,7 +665,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -595,7 +707,19 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", +] + +[[package]] +name = "dwrote" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfe1f192fcce01590bd8d839aca53ce0d11d803bf291b2a6c4ad925a8f0024be" +dependencies = [ + "lazy_static", + "libc", + "winapi", + "wio", ] [[package]] @@ -684,6 +808,15 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + [[package]] name = "flatbuffers" version = "25.2.10" @@ -694,6 +827,16 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -706,6 +849,21 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -785,7 +943,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -899,6 +1057,39 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gio" +version = "0.16.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1c84b4534a290a29160ef5c6eff2a9c95833111472e824fc5cb78b513dd092" +dependencies = [ + "bitflags 1.3.2", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "gio-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9b693b8e39d042a95547fc258a7b07349b1f0b48f4b2fa3108ba3c51c0b5229" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + [[package]] name = "git2" version = "0.20.2" @@ -912,6 +1103,53 @@ dependencies = [ "url", ] +[[package]] +name = "glib" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16aa2475c9debed5a32832cb5ff2af5a3f9e1ab9e69df58eaadc1ab2004d6eba" +dependencies = [ + "bitflags 1.3.2", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "once_cell", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "glib-macros" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb1a9325847aa46f1e96ffea37611b9d51fc4827e67f79e7de502a297560a67b" +dependencies = [ + "anyhow", + "heck 0.4.1", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "glib-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61a4f46316d06bfa33a7ac22df6f0524c8be58e3db2d9ca99ccb1f357b62a65" +dependencies = [ + "libc", + "system-deps", +] + [[package]] name = "glob" version = "0.3.2" @@ -931,6 +1169,17 @@ dependencies = [ "regex-syntax 0.8.5", ] +[[package]] +name = "gobject-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3520bb9c07ae2a12c7f2fbb24d4efc11231c8146a86956413fb1a79bb760a0f1" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + [[package]] name = "goblin" version = "0.10.0" @@ -962,6 +1211,12 @@ dependencies = [ "serde", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "heck" version = "0.5.0" @@ -1080,7 +1335,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn", + "syn 2.0.104", "wasmparser", ] @@ -1093,7 +1348,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn", + "syn 2.0.104", "wasmparser", ] @@ -1458,7 +1713,7 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1481,6 +1736,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kurbo" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd85a5776cd9500c2e2059c8c76c3b01528566b7fcbaf8098b55a33fc298849b" +dependencies = [ + "arrayvec", +] + [[package]] name = "kvm-bindings" version = "0.13.0" @@ -1655,12 +1919,27 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + [[package]] name = "memchr" version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +[[package]] +name = "memmap2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +dependencies = [ + "libc", +] + [[package]] name = "metrics" version = "0.24.2" @@ -1718,6 +1997,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -1846,7 +2126,7 @@ checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1855,7 +2135,9 @@ version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ + "flate2", "memchr", + "ruzstd", ] [[package]] @@ -1986,6 +2268,59 @@ dependencies = [ "winapi", ] +[[package]] +name = "pango" +version = "0.16.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdff66b271861037b89d028656184059e03b0b6ccb36003820be19f7200b1e94" +dependencies = [ + "bitflags 1.3.2", + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e134909a9a293e04d2cc31928aa95679c5e4df954d0b85483159bd20d8f047f" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "pangocairo" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ad2ec87789371b551fd2367c10aa37060412ffd3e60abd99491b21b93a3f9b" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "glib", + "libc", + "pango", + "pangocairo-sys", +] + +[[package]] +name = "pangocairo-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "848d2df9b7f1a8c7a19d994de443bcbe5d4382610ccb8e64247f932be74fcf76" +dependencies = [ + "cairo-sys-rs", + "glib-sys", + "libc", + "pango-sys", + "system-deps", +] + [[package]] name = "parking_lot" version = "0.12.4" @@ -2034,6 +2369,93 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "piet" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e381186490a3e2017a506d62b759ea8eaf4be14666b13ed53973e8ae193451b1" +dependencies = [ + "kurbo", + "unic-bidi", +] + +[[package]] +name = "piet-cairo" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc0b38ac300c79deb9bfc8c7f91a08f2b080338648f7202981094b22321bb9" +dependencies = [ + "cairo-rs", + "pango", + "pangocairo", + "piet", + "unicode-segmentation", + "xi-unicode", +] + +[[package]] +name = "piet-common" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd8497cc0bcfecb1e14e027428c5e3eaf9af6e14761176e1212006d8bdba387" +dependencies = [ + "cairo-rs", + "cairo-sys-rs", + "cfg-if", + "core-graphics", + "piet", + "piet-cairo", + "piet-coregraphics", + "piet-direct2d", + "piet-web", + "png", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "piet-coregraphics" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a819b41d2ddb1d8abf3e45e49422f866cba281b4abb5e2fb948bba06e2c3d3f7" +dependencies = [ + "associative-cache", + "core-foundation", + "core-foundation-sys", + "core-graphics", + "core-text", + "foreign-types", + "piet", +] + +[[package]] +name = "piet-direct2d" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd00e91df4f987be40eb13042afe6ee9e54468466bdb7486390b40d4fef0993e" +dependencies = [ + "associative-cache", + "dwrote", + "piet", + "utf16_lit", + "winapi", + "wio", +] + +[[package]] +name = "piet-web" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a560232a94e535979923d49062d1c6d5407b3804bcd0d0b4cb9e25a9b41db1e" +dependencies = [ + "js-sys", + "piet", + "unicode-segmentation", + "wasm-bindgen", + "web-sys", + "xi-unicode", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -2051,7 +2473,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2106,6 +2528,19 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "portable-atomic" version = "1.11.1" @@ -2146,7 +2581,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.104", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", ] [[package]] @@ -2212,7 +2681,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2456,7 +2925,7 @@ dependencies = [ "quote", "rust-embed-utils", "shellexpand", - "syn", + "syn 2.0.104", "walkdir", ] @@ -2523,6 +2992,15 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "ruzstd" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad02996bfc73da3e301efe90b1837be9ed8f4a462b6ed410aa35d00381de89f" +dependencies = [ + "twox-hash", +] + [[package]] name = "ryu" version = "1.0.20" @@ -2576,7 +3054,7 @@ checksum = "22fc4f90c27b57691bbaf11d8ecc7cfbfe98a4da6dbe60226115d322aa80c06e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2617,7 +3095,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2675,7 +3153,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2735,6 +3213,12 @@ dependencies = [ "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "sketches-ddsketch" version = "0.3.0" @@ -2787,12 +3271,29 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.104" @@ -2821,9 +3322,28 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + [[package]] name = "tempfile" version = "3.20.0" @@ -2872,7 +3392,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2883,7 +3403,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2943,7 +3463,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2966,7 +3486,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.22.27", ] [[package]] @@ -2978,6 +3498,17 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + [[package]] name = "toml_edit" version = "0.22.27" @@ -2989,7 +3520,7 @@ dependencies = [ "serde_spanned", "toml_datetime", "toml_write", - "winnow", + "winnow 0.7.11", ] [[package]] @@ -3064,6 +3595,15 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" +[[package]] +name = "trace_dump" +version = "0.0.0" +dependencies = [ + "addr2line", + "blake3", + "piet-common", +] + [[package]] name = "tracing" version = "0.1.41" @@ -3084,7 +3624,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3218,6 +3758,22 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + [[package]] name = "typenum" version = "1.18.0" @@ -3230,12 +3786,69 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" +[[package]] +name = "unic-bidi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1356b759fb6a82050666f11dce4b6fe3571781f1449f3ef78074e408d468ec09" +dependencies = [ + "matches", + "unic-ucd-bidi", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-ucd-bidi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1d568b51222484e1f8209ce48caa6b430bf352962b877d592c29ab31fb53d8c" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "url" version = "2.5.4" @@ -3247,6 +3860,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf16_lit" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14706d2a800ee8ff38c1d3edb873cd616971ea59eb7c0d046bb44ef59b06a1ae" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -3283,6 +3902,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + [[package]] name = "version_check" version = "0.9.5" @@ -3364,7 +3989,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 2.0.104", "wasm-bindgen-shared", ] @@ -3399,7 +4024,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3531,7 +4156,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3542,7 +4167,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3752,6 +4377,15 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" version = "0.7.11" @@ -3761,6 +4395,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi", +] + [[package]] name = "wit-bindgen-rt" version = "0.39.0" @@ -3776,6 +4419,12 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +[[package]] +name = "xi-unicode" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" + [[package]] name = "yoke" version = "0.8.0" @@ -3796,7 +4445,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", "synstructure", ] @@ -3827,7 +4476,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3838,7 +4487,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3858,7 +4507,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", "synstructure", ] @@ -3892,5 +4541,5 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] diff --git a/Cargo.toml b/Cargo.toml index 2c16795c3..28ca73d70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "src/hyperlight_guest_bin", "src/hyperlight_component_util", "src/hyperlight_component_macro", + "src/trace_dump", ] # Guests have custom linker flags, so we need to exclude them from the workspace exclude = [ diff --git a/src/trace_dump/Cargo.toml b/src/trace_dump/Cargo.toml new file mode 100644 index 000000000..0149980e8 --- /dev/null +++ b/src/trace_dump/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "trace_dump" +version = "0.0.0" +publish = false +edition = "2021" + +[dependencies] +addr2line = "0.24.2" +piet-common = { version = "0.6.2", features = [ "png" ] } +blake3 = { version = "1.5.5" } + +[[bin]] +name = "trace_dump" +path = "main.rs" diff --git a/src/trace_dump/main.rs b/src/trace_dump/main.rs new file mode 100644 index 000000000..c187efac1 --- /dev/null +++ b/src/trace_dump/main.rs @@ -0,0 +1,831 @@ +use std::collections::HashMap; +use std::env; +use std::fs::File; +use std::io::{Read, Seek, SeekFrom, Write}; +use std::path::PathBuf; +use std::rc::Rc; +use std::sync::Mutex; +use std::time::Duration; + +use piet_common::{kurbo, Color, RenderContext, Text, TextLayout, TextLayoutBuilder}; + +fn read_u128(inf: &mut File) -> Result { + let mut bytes: [u8; 16] = [0; 16]; + inf.read_exact(&mut bytes)?; + Ok(u128::from_ne_bytes(bytes)) +} +fn read_u64(inf: &mut File) -> Option { + let mut bytes: [u8; 8] = [0; 8]; + inf.read_exact(&mut bytes).ok()?; + Some(u64::from_ne_bytes(bytes)) +} +fn read_u64_vec(inf: &mut File) -> Option> { + let len = read_u64(inf)?; + let mut vec = Vec::with_capacity(len as usize); + for _ in 0..len { + vec.push(read_u64(inf)?); + } + Some(vec) +} +fn read_blake3_hash(inf: &mut File) -> Option { + let mut bytes: [u8; 32] = [0; 32]; + inf.read_exact(&mut bytes).ok()?; + Some(blake3::Hash::from_bytes(bytes)) +} + +fn dump_stack(state: &mut State, trace: Rc<[u64]>) { + for frame in &*trace { + println!(" {:x} {}", frame, state.symbol_cache.format_symbol(*frame)); + } +} + +fn dump_ident(_state: &mut State, _rs: &mut (), now: Duration, hash: blake3::Hash) -> Option<()> { + println!("\n[{:9?}] BLAKE3 hash of binary is {}", now, hash); + Some(()) +} + +fn dump_unwind(state: &mut State, _rs: &mut (), now: Duration, trace: Rc<[u64]>) -> Option<()> { + println!("\n[{:9?}] Guest requested stack trace", now); + dump_stack(state, trace); + Some(()) +} + +fn dump_alloc( + state: &mut State, + _rs: &mut (), + now: Duration, + ptr: u64, + amt: u64, + trace: Rc<[u64]>, +) -> Option<()> { + println!("\n[{:9?}] Allocated {} bytes at 0x{:x}", now, amt, ptr); + dump_stack(state, trace); + Some(()) +} + +fn dump_free( + state: &mut State, + _rs: &mut (), + now: Duration, + ptr: u64, + amt: u64, + trace: Rc<[u64]>, +) -> Option<()> { + println!("\n[{:9?}] Freed {} bytes at 0x{:x}", now, amt, ptr); + dump_stack(state, trace); + Some(()) +} + +// todo: this should use something more reasonable than a hash table +// for each node. let's measure the out-degree and see if a small +// array is better, to start. +struct TraceTrie { + value: T, + children: HashMap>, +} +impl TraceTrie { + fn new() -> Self { + Self { + value: Default::default(), + children: HashMap::new(), + } + } + fn apply_path<'a, 'i, F: Fn(&mut T), I: Iterator>( + &'a mut self, + trace: I, + f: F, + ) { + let mut node = self; + for frame in trace { + f(&mut node.value); + node = (*node).children.entry(*frame).or_insert(Self::new()) + } + f(&mut node.value); + } +} + +struct SymbolCache { + loader: addr2line::Loader, + symbol_cache: HashMap)>>, +} +impl SymbolCache { + fn resolve_symbol<'c>(&'c mut self, addr: u64) -> &'c Option<(String, Option)> { + self.symbol_cache.entry(addr).or_insert_with(|| { + let frame = &self.loader.find_frames(addr).ok()?.next().ok()??; + let function = frame.function.as_ref()?; + let demangled = + addr2line::demangle_auto(function.name.to_string_lossy(), function.language) + .to_string(); + Some((demangled, frame.location.as_ref()?.line)) + }) + } + fn format_symbol(&mut self, addr: u64) -> String { + match self.resolve_symbol(addr) { + None => format!("{}", addr), + Some((f, None)) => f.clone(), + Some((f, Some(l))) => format!("{}:{}", f, l), + } + } +} + +enum Visualisation { + Bar, + Flame, +} +impl std::fmt::Display for Visualisation { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Visualisation::Bar => write!(f, "bar"), + Visualisation::Flame => write!(f, "flame"), + } + } +} + +struct State { + inf: File, + symbol_cache: SymbolCache, + out_dir: Option, + start_time: Option, + end_time: Option, + allocs: HashMap)>, + sites: HashMap, + traces: TraceTrie, + total: u64, + max_total: u64, + max_duration: Duration, + num_durations: u64, +} + +struct ViewParams { + margin: f64, + width: f64, + height: f64, + label_gap: f64, + amount_gap: f64, + bar_start: f64, + bar_height: f64, + bar_leading: f64, + bar_brush: R::Brush, +} + +fn draw_bg(render_context: &mut R, v: &ViewParams) { + let bg_brush = render_context.solid_brush(Color::rgb8(255, 255, 255)); + render_context.fill( + kurbo::Rect { + x0: 0.0, + y0: 0.0, + x1: v.width + v.margin * 2.0, + y1: v.height + v.margin * 2.0, + }, + &bg_brush, + ); +} +fn draw_bar( + render_context: &mut R, + v: &ViewParams, + stroke: bool, + n: u64, + label: String, + value: u64, + max_value: u64, +) -> Option<()> { + let left = v.margin + v.bar_start; + let top = v.margin + (n as f64) * (v.bar_height + v.bar_leading); + if stroke { + render_context.stroke( + kurbo::Rect { + x0: left, + y0: top, + //x1: v.margin + v.width, + x1: left + (v.width - v.bar_start), + y1: top + v.bar_height, + }, + &v.bar_brush, + 1.0, + ); + } + let right = left + (v.width - v.bar_start) * value as f64 / max_value as f64; + render_context.fill( + kurbo::Rect { + x0: left, + y0: top, + x1: right, + y1: top + v.bar_height, + }, + &v.bar_brush, + ); + let layout = render_context.text().new_text_layout(label).build().ok()?; + let metric = layout + .line_metric(0) + .expect("there must be at least one line metric"); + render_context.draw_text( + &layout, + kurbo::Point { + x: left - v.label_gap - layout.trailing_whitespace_width(), + y: top - metric.y_offset + (v.bar_height - metric.baseline) / 2.0, + }, + ); + let layout = render_context + .text() + .new_text_layout(format!("{}", value)) + .default_attribute(piet_common::TextAttribute::TextColor(Color::rgb8( + 255, 255, 255, + ))) + .build() + .ok()?; + let metric = layout + .line_metric(0) + .expect("there must be at least one line metric"); + if right - left > v.amount_gap + layout.trailing_whitespace_width() { + render_context.draw_text( + &layout, + kurbo::Point { + x: right - v.amount_gap - layout.trailing_whitespace_width(), + y: top + (v.bar_height - metric.height) / 2.0, + }, + ); + } else { + // hopefully the choice of colour doesn't affect the layout much + let layout = render_context + .text() + .new_text_layout(format!("{}", value)) + .build() + .ok()?; + let metric = layout + .line_metric(0) + .expect("there must be at least one line metric"); + render_context.draw_text( + &layout, + kurbo::Point { + x: right + v.amount_gap, + y: top + (v.bar_height - metric.height) / 2.0, + }, + ); + } + Some(()) +} + +trait RenderWrapper { + fn render(&mut self, ctx: &mut R, width: u64, height: u64) -> Option<()>; +} +fn render_bitmap( + mut out: O, + device: &mut piet_common::Device, + mut render: F, +) -> Option<()> { + let width = 1920; + let height = 1080; + let mut bitmap = device.bitmap_target(width, height, 1.0).ok()?; + { + let mut render_context = bitmap.render_context(); + render.render(&mut render_context, width as u64, height as u64)?; + render_context.finish().ok()?; + } + out.write_all( + bitmap + .to_image_buf(piet_common::ImageFormat::RgbaPremul) + .expect("unable to access image buffer") + .raw_pixels(), + ) + .expect("write to stdout"); + Some(()) +} + +impl ViewParams { + fn new(ctx: &mut R, ht: u64, wd: u64) -> Self { + let margin = 20.0; + let width = wd as f64 - margin * 2.0; + let height = ht as f64 - margin * 2.0; + let bar_brush = ctx.solid_brush(Color::rgb8(128, 0, 128)); + Self { + margin, + width, + height, + label_gap: 10.0, + amount_gap: 5.0, + bar_start: width / 4.0, + bar_height: 12.0, + bar_leading: 4.0, + bar_brush: bar_brush, + } + } +} + +struct BarRenderer<'r> { + state: &'r mut State, + now: Duration, +} +impl<'r, 'a, 's> RenderWrapper for BarRenderer<'r> { + fn render(&mut self, ctx: &mut R, wd: u64, ht: u64) -> Option<()> { + let v = ViewParams::new(ctx, ht, wd); + draw_bg(ctx, &v); + draw_bar( + ctx, + &v, + true, + 0, + "Execution time".to_string(), + self.now.as_micros() as u64, + self.state.max_duration.as_micros() as u64, + )?; + draw_bar( + ctx, + &v, + true, + 1, + "Total memory consumption".to_string(), + self.state.total, + self.state.max_total, + )?; + + let mut points: Vec<(&u64, &u64)> = self.state.sites.iter().collect(); + points.sort_by_key(|(_, size)| *size); + for (i, (site, size)) in points.iter().rev().enumerate() { + draw_bar( + ctx, + &v, + false, + (3 + i) as u64, + (&mut self.state.symbol_cache).format_symbol(**site), + **size, + self.state.total, + )?; + } + Some(()) + } +} + +struct FlameRenderer<'r> { + state: &'r mut State, + now: Duration, +} +#[derive(Clone, Copy)] +struct FlameView { + total_allocated: u64, + bottom: f64, + left: f64, + color: u8, +} +fn draw_flame( + ctx: &mut R, + v: &ViewParams, + fv: &FlameView, + sc: &mut SymbolCache, + t: &TraceTrie, + addr: Option, +) -> Option<()> { + let rect = kurbo::Rect { + x0: v.margin + fv.left, + y0: v.margin + fv.bottom - v.bar_height, + x1: v.margin + fv.left + (t.value as f64) * v.width / (fv.total_allocated as f64), + y1: v.margin + fv.bottom, + }; + ctx.fill(rect, &Color::rgb8(255, 0, fv.color)); + if let Some(addr) = addr { + ctx.save().ok()?; + ctx.clip(rect); + let layout = ctx + .text() + .new_text_layout(sc.format_symbol(addr)) + .default_attribute(piet_common::TextAttribute::FontSize(9.0)) + .build() + .ok()?; + ctx.draw_text( + &layout, + kurbo::Point { + x: v.margin + fv.left, + y: v.margin + fv.bottom - v.bar_height, + }, + ); + ctx.restore().ok()?; + } + let mut child_fv = FlameView { + total_allocated: fv.total_allocated, + bottom: fv.bottom - v.bar_height, + left: fv.left, + color: fv.color, + }; + for (addr, child) in &t.children { + draw_flame(ctx, v, &child_fv, sc, child, Some(*addr))?; + child_fv.left += (child.value as f64) * v.width / (fv.total_allocated as f64); + child_fv.color = child_fv.color.wrapping_add(85); + } + Some(()) +} +impl<'r, 'a, 's> RenderWrapper for FlameRenderer<'r> { + fn render(&mut self, ctx: &mut R, wd: u64, ht: u64) -> Option<()> { + let mut v = ViewParams::new(ctx, ht, wd); + v.bar_start = v.width / 8.0; + draw_bg(ctx, &v); + draw_bar( + ctx, + &v, + true, + 0, + "Execution time".to_string(), + self.now.as_micros() as u64, + self.state.max_duration.as_micros() as u64, + )?; + draw_bar( + ctx, + &v, + true, + 1, + "Total memory consumption".to_string(), + self.state.total, + self.state.max_total, + )?; + + let fv = FlameView { + total_allocated: self.state.total, + bottom: v.height, + left: 0.0, + color: 0, + }; + draw_flame( + ctx, + &v, + &fv, + &mut self.state.symbol_cache, + &self.state.traces, + None, + )?; + Some(()) + } +} + +struct RenderState<'a> { + device: &'a mut piet_common::Device, + bar_out: std::process::ChildStdin, + flame_out: std::process::ChildStdin, +} +fn render_state(state: &mut State, rs: &mut RenderState, now: Duration) -> Option<()> { + let late_enough = state.start_time.map(|t| now >= t).unwrap_or(true); + let early_enough = state.end_time.map(|t| now <= t).unwrap_or(true); + if late_enough && early_enough { + render_bitmap(&mut rs.bar_out, rs.device, BarRenderer { state, now })?; + render_bitmap(&mut rs.flame_out, rs.device, FlameRenderer { state, now })?; + } + Some(()) +} + +fn render_ident( + _state: &mut State, + _rs: &mut RenderState, + _now: Duration, + _hash: blake3::Hash, +) -> Option<()> { + Some(()) +} + +fn render_unwind( + _state: &mut State, + _rs: &mut RenderState, + _now: Duration, + _trace: Rc<[u64]>, +) -> Option<()> { + Some(()) +} + +fn render_alloc( + state: &mut State, + rs: &mut RenderState, + now: Duration, + _ptr: u64, + amt: u64, + trace: Rc<[u64]>, +) -> Option<()> { + for frame in trace.as_ref() { + *state.sites.entry(*frame).or_insert(0) += amt; + } + state.traces.apply_path(trace.iter().rev(), |t| *t += amt); + render_state(state, rs, now)?; + Some(()) +} + +fn render_free( + state: &mut State, + rs: &mut RenderState, + now: Duration, + ptr: u64, + _amt: u64, + _trace: Rc<[u64]>, +) -> Option<()> { + let (amt, trace) = state + .allocs + .get(&ptr) + .expect("free of un-allocated address"); + for frame in trace.as_ref() { + *state + .sites + .get_mut(frame) + .expect("free of un-allocated site") -= amt; + } + state.traces.apply_path(trace.iter().rev(), |t| *t -= amt); + render_state(state, rs, now)?; + Some(()) +} + +fn read_file( + state: &mut State, + mut handle_state: S, + handle_ident: I, + handle_unwind: U, + handle_alloc: A, + handle_free: F, +) -> Option<()> +where + I: Fn(&mut State, &mut S, Duration, blake3::Hash) -> Option<()>, + U: Fn(&mut State, &mut S, Duration, Rc<[u64]>) -> Option<()>, + A: Fn(&mut State, &mut S, Duration, u64, u64, Rc<[u64]>) -> Option<()>, + F: Fn(&mut State, &mut S, Duration, u64, u64, Rc<[u64]>) -> Option<()>, +{ + loop { + let time = match read_u128(&mut state.inf) { + Ok(t) => t, + Err(e) => { + if e.kind() == std::io::ErrorKind::UnexpectedEof { + break; + } else { + return None; + } + } + }; + let now = Duration::from_micros(time.try_into().expect("duration too large for u64")); + state.max_duration = std::cmp::max(state.max_duration, now); + state.num_durations += 1; + + let frame_id = read_u64(&mut state.inf)?; + + if frame_id == 0 { + let hash = read_blake3_hash(&mut state.inf)?; + handle_ident(state, &mut handle_state, now, hash)?; + } else if frame_id == 1 { + let trace: Rc<[u64]> = read_u64_vec(&mut state.inf)?.into(); + handle_unwind(state, &mut handle_state, now, trace)?; + } else if frame_id == 2 { + let ptr = read_u64(&mut state.inf)?; + let amt = read_u64(&mut state.inf)?; + let trace: Rc<[u64]> = read_u64_vec(&mut state.inf)?.into(); + state.allocs.insert(ptr, (amt, trace.clone())); + state.total += amt; + if state.total > state.max_total { + state.max_total = state.total; + } + handle_alloc(state, &mut handle_state, now, ptr, amt, trace)?; + } else if frame_id == 3 { + let ptr = read_u64(&mut state.inf)?; + let _ = read_u64_vec(&mut state.inf)?; + let amt_trace = state + .allocs + .get(&ptr) + .expect("free of un-allocated address"); + let amt = amt_trace.0; + let trace = amt_trace.1.clone(); + state.total -= amt; + handle_free(state, &mut handle_state, now, ptr, amt, trace)?; + } else { + return None; + } + } + Some(()) +} + +fn mkv_for(out_dir: &PathBuf, vis: Visualisation, start: Duration) -> PathBuf { + out_dir.join(format!("{:08}.{}.mkv", start.as_micros(), vis)) +} +fn ffmpeg_for( + out_dir: &PathBuf, + vis: Visualisation, + start: Duration, +) -> Option { + let out = std::fs::File::create(out_dir.join(format!("{:08}.{}.out", start.as_micros(), vis))) + .ok()?; + let err = std::fs::File::create(out_dir.join(format!("{:08}.{}.err", start.as_micros(), vis))) + .ok()?; + let mkv = mkv_for(out_dir, vis, start); + let _ = std::fs::remove_file(&mkv); + std::process::Command::new("ffmpeg") + .args([ + "-f", + "rawvideo", + "-pix_fmt", + "rgba", + "-framerate", + "60", + "-video_size", + "1920x1080", + "-i", + "-", + "-c:v", + "libvpx-vp9", + "-crf", + "15", + "-b:v", + "0", + ]) + .arg(mkv) + .stdin(std::process::Stdio::piped()) + .stdout(std::process::Stdio::from(out)) + .stderr(std::process::Stdio::from(err)) + .spawn() + .ok() +} + +fn spawn_render_thread( + state: &mut State, + exe_file_name: String, + in_file_name: String, + interval: (Duration, Duration), +) -> std::thread::JoinHandle> { + let out_dir = state.out_dir.clone(); + let max_total = state.max_total; + let max_duration = state.max_duration; + std::thread::spawn(move || { + let out_dir = out_dir?; + eprintln!( + "> {:08} -- {:08}", + interval.0.as_micros(), + interval.1.as_micros() + ); + let loader = addr2line::Loader::new(exe_file_name).ok()?; + let inf = File::open(in_file_name).expect("could not open dump file"); + let mut bar_ffmpeg = ffmpeg_for(&out_dir, Visualisation::Bar, interval.0)?; + let mut flame_ffmpeg = ffmpeg_for(&out_dir, Visualisation::Flame, interval.0)?; + let mut job_state = State { + inf: inf, + symbol_cache: SymbolCache { + loader, + symbol_cache: HashMap::new(), + }, + start_time: Some(interval.0), + end_time: Some(interval.1), + out_dir: Some(out_dir), + allocs: HashMap::new(), + sites: HashMap::new(), + traces: TraceTrie::new(), + total: 0, + max_total, + max_duration, + num_durations: 0, + }; + /* plot each individual frame */ + let mut device = piet_common::Device::new().expect("could not create Piet device"); + let rs = RenderState { + device: &mut device, + bar_out: bar_ffmpeg.stdin.take().expect("bar ffmpeg stdin"), + flame_out: flame_ffmpeg.stdin.take().expect("flame ffmpeg stdin"), + }; + read_file( + &mut job_state, + rs, + render_ident, + render_unwind, + render_alloc, + render_free, + )?; + bar_ffmpeg.wait().ok()?; + flame_ffmpeg.wait().ok()?; + Some(()) + }) +} + +fn main() { + let args: Vec = env::args().collect(); + let is_list = args.len() == 4 && args[3] == "list_frames"; + let is_plot = args.len() == 6 && args[3] == "plot_mem"; + if !is_list && !is_plot { + eprintln!("usage: {} list_frames", args[0]); + eprintln!( + "usage: {} plot_mem ", + args[0] + ); + return; + } + let Ok(loader) = addr2line::Loader::new(&args[1]) else { + eprintln!("could not load guest binary {}", args[1]); + return; + }; + let inf = File::open(args[2].clone()).expect("could not open trace file"); + let state = State { + inf: inf, + symbol_cache: SymbolCache { + loader: loader, + symbol_cache: HashMap::new(), + }, + start_time: None, + end_time: None, + out_dir: None, + allocs: HashMap::new(), + sites: HashMap::new(), + traces: TraceTrie::new(), + total: 0, + max_total: 0, + max_duration: Duration::ZERO, + num_durations: 0, + }; + if is_list { + dump_trace(state); + } else if is_plot { + plot_mem(args, state); + } +} + +fn dump_trace(mut state: State) { + read_file( + &mut state, + (), + dump_ident, + dump_unwind, + dump_alloc, + dump_free, + ); +} + +fn plot_mem(args: Vec, mut state: State) { + let out_dir = PathBuf::from(args[4].clone()); + state.out_dir = Some(out_dir.clone()); + std::fs::create_dir_all(&out_dir).expect("could not create output dir"); + + /* first pass: compute the maximum memory usage */ + match read_file( + &mut state, + (), + |_, _, _, _| Some(()), + |_, _, _, _| Some(()), + |_, _, _, _, _, _| Some(()), + |_, _, _, _, _, _| Some(()), + ) { + Some(()) => (), + None => { + eprintln!("i/o error encountered"); + () + } + } + eprintln!("max total memory used is {}", state.max_total); + state + .inf + .seek(SeekFrom::Start(0)) + .expect("couldn't seek back"); + state.allocs = HashMap::new(); + state.total = 0; + + /* second pass: compute fair durations so that each parallel job + * processes the same number of frames */ + let num_segments = str::parse::(&args[5]).expect("number of segments must be a number"); + let durations_per_segment = (state.num_durations - 1) / num_segments + 1; + state.num_durations = 0; + let jobs = Mutex::new(Vec::new()); + let start_duration = Mutex::new(Duration::ZERO); + let count_frame = |s: &mut State, _: &mut (), n: Duration, _, _, _| { + if s.num_durations == 1 { + *start_duration.lock().unwrap() = n; + } + if s.num_durations == durations_per_segment { + (*jobs.lock().unwrap()).push((*start_duration.lock().unwrap(), n)); + s.num_durations = 0; + } + Some(()) + }; + read_file( + &mut state, + (), + |_, _, _, _| Some(()), + |_, _, _, _| Some(()), + count_frame, + count_frame, + ); + if state.num_durations > 0 { + (*jobs.lock().unwrap()).push((*start_duration.lock().unwrap(), state.max_duration)); + } + + /* third pass: render in parallel */ + let mut handles = Vec::new(); + for job in &*jobs.lock().unwrap() { + handles.push(spawn_render_thread( + &mut state, + args[1].clone(), + args[2].clone(), + *job, + )); + } + for handle in handles { + handle.join().expect("thread died"); + } + + /* merge all the parallel rendered segments */ + let mut merge_bar = std::process::Command::new("mkvmerge"); + merge_bar.arg("-o").arg(out_dir.join("bar.mkv")); + let mut merge_flame = std::process::Command::new("mkvmerge"); + merge_flame.arg("-o").arg(out_dir.join("flame.mkv")); + for (n, job) in (*jobs.lock().unwrap()).iter().enumerate() { + if n > 0 { + merge_bar.arg("+"); + merge_flame.arg("+"); + } + merge_bar.arg(mkv_for(&out_dir, Visualisation::Bar, job.0)); + merge_flame.arg(mkv_for(&out_dir, Visualisation::Flame, job.0)); + } + merge_bar.status().unwrap(); + merge_flame.status().unwrap(); +} From 5d74e1950a2bab6fedbd7562f046ef16ec26bfd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Mon, 7 Jul 2025 19:43:03 +0300 Subject: [PATCH 043/271] add license header to trace_dump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- src/trace_dump/main.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/trace_dump/main.rs b/src/trace_dump/main.rs index c187efac1..afd3f8b81 100644 --- a/src/trace_dump/main.rs +++ b/src/trace_dump/main.rs @@ -1,3 +1,19 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + use std::collections::HashMap; use std::env; use std::fs::File; From 407a2f40c5210d5a1c9201c3747fd0478b2b0e55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Tue, 8 Jul 2025 17:25:53 +0300 Subject: [PATCH 044/271] Fix clippy warnings for unrelated work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- src/hyperlight_host/src/hypervisor/surrogate_process.rs | 2 -- src/hyperlight_host/src/mem/layout.rs | 6 ++++++ src/hyperlight_host/src/mem/mgr.rs | 3 +++ src/hyperlight_host/src/sandbox/initialized_multi_use.rs | 2 ++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/hyperlight_host/src/hypervisor/surrogate_process.rs b/src/hyperlight_host/src/hypervisor/surrogate_process.rs index caaa79d00..d026362d2 100644 --- a/src/hyperlight_host/src/hypervisor/surrogate_process.rs +++ b/src/hyperlight_host/src/hypervisor/surrogate_process.rs @@ -83,7 +83,6 @@ impl Drop for SurrogateProcess { "Failed to return surrogate process to surrogate process manager when dropping : {:?}", e ); - return; } }, Err(e) => { @@ -91,7 +90,6 @@ impl Drop for SurrogateProcess { "Failed to get surrogate process manager when dropping SurrogateProcess: {:?}", e ); - return; } } } diff --git a/src/hyperlight_host/src/mem/layout.rs b/src/hyperlight_host/src/mem/layout.rs index a8a1e5fc9..b453d90fb 100644 --- a/src/hyperlight_host/src/mem/layout.rs +++ b/src/hyperlight_host/src/mem/layout.rs @@ -224,18 +224,24 @@ impl SandboxMemoryLayout { pub(crate) const PML4_OFFSET: usize = 0x0000; /// The offset into the sandbox's memory where the Page Directory Pointer /// Table starts. + #[cfg(feature = "init-paging")] pub(super) const PDPT_OFFSET: usize = 0x1000; /// The offset into the sandbox's memory where the Page Directory starts. + #[cfg(feature = "init-paging")] pub(super) const PD_OFFSET: usize = 0x2000; /// The offset into the sandbox's memory where the Page Tables start. + #[cfg(feature = "init-paging")] pub(super) const PT_OFFSET: usize = 0x3000; /// The address (not the offset) to the start of the page directory + #[cfg(feature = "init-paging")] pub(super) const PD_GUEST_ADDRESS: usize = Self::BASE_ADDRESS + Self::PD_OFFSET; /// The address (not the offset) into sandbox memory where the Page /// Directory Pointer Table starts + #[cfg(feature = "init-paging")] pub(super) const PDPT_GUEST_ADDRESS: usize = Self::BASE_ADDRESS + Self::PDPT_OFFSET; /// The address (not the offset) into sandbox memory where the Page /// Tables start + #[cfg(feature = "init-paging")] pub(super) const PT_GUEST_ADDRESS: usize = Self::BASE_ADDRESS + Self::PT_OFFSET; /// The maximum amount of memory a single sandbox will be allowed. /// The addressable virtual memory with current paging setup is virtual address 0x0 - 0x40000000 (excl.), diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 3abdb11fe..4e4aa0112 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -340,6 +340,9 @@ impl SandboxMemoryManager { shared_mem.write_u64(offset, load_addr_u64)?; } + // The load method returns a LoadInfo which can also be a different type once the + // `unwind_guest` feature is enabled. + #[allow(clippy::let_unit_value)] let load_info = exe_info.load( load_addr.clone().try_into()?, &mut shared_mem.as_mut_slice()[layout.get_guest_code_offset()..], diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 6208d8f85..e1d805d41 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -136,6 +136,7 @@ impl MultiUseSandbox { /// `rgn.region_type` is ignored, since guest PTEs are not created /// for the new memory. /// + /// # Safety /// It is the caller's responsibility to ensure that the host side /// of the region remains intact and is not written to until this /// mapping is removed, either due to the destruction of the @@ -161,6 +162,7 @@ impl MultiUseSandbox { /// Map the contents of a file into the guest at a particular address /// /// Returns the length of the mapping + #[allow(dead_code)] #[instrument(err(Debug), skip(self, _fp, _guest_base), parent = Span::current())] pub(crate) fn map_file_cow(&mut self, _fp: &Path, _guest_base: u64) -> Result { #[cfg(windows)] From 63d5130737d6a28ef4c5d17372bb46e4655834f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Tue, 8 Jul 2025 15:08:16 +0300 Subject: [PATCH 045/271] [hyperlight-guest-tracing] Add crates that generate guest tracing records MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `hyperlight-guest-tracing` defines a `TraceBuffer` that keeps `TraceRecord`s that the guest issues. When the buffer capacity is reached, it automatically issues an `Out` instruction with the corresponding info for the host to retrieve the buffer. - The guest can issue `TraceRecord`s by using the `hyperlight-guest-tracing-macro` crate that pushes new records to the buffer. - `hyperlight_common` contains the definitions for the frame types a guest can send to the host using the `Out` instruction. Signed-off-by: Doru Blânzeanu --- Cargo.lock | 18 ++ Cargo.toml | 4 + src/hyperlight_common/Cargo.toml | 1 + src/hyperlight_common/src/outb.rs | 9 +- src/hyperlight_guest_tracing/Cargo.toml | 17 ++ src/hyperlight_guest_tracing/src/lib.rs | 277 ++++++++++++++++++ src/hyperlight_guest_tracing_macro/Cargo.toml | 25 ++ src/hyperlight_guest_tracing_macro/src/lib.rs | 250 ++++++++++++++++ 8 files changed, 599 insertions(+), 2 deletions(-) create mode 100644 src/hyperlight_guest_tracing/Cargo.toml create mode 100644 src/hyperlight_guest_tracing/src/lib.rs create mode 100644 src/hyperlight_guest_tracing_macro/Cargo.toml create mode 100644 src/hyperlight_guest_tracing_macro/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 709611f13..a39331791 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1384,6 +1384,24 @@ dependencies = [ "spin 0.10.0", ] +[[package]] +name = "hyperlight-guest-tracing" +version = "0.7.0" +dependencies = [ + "hyperlight-common", + "spin 0.10.0", +] + +[[package]] +name = "hyperlight-guest-tracing-macro" +version = "0.7.0" +dependencies = [ + "hyperlight-guest-tracing", + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "hyperlight-host" version = "0.7.0" diff --git a/Cargo.toml b/Cargo.toml index 28ca73d70..18a311405 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,8 @@ members = [ "src/hyperlight_guest", "src/hyperlight_host", "src/hyperlight_guest_capi", + "src/hyperlight_guest_tracing", + "src/hyperlight_guest_tracing_macro", "src/hyperlight_testing", "fuzz", "src/hyperlight_guest_bin", @@ -40,6 +42,8 @@ hyperlight-host = { path = "src/hyperlight_host", version = "0.7.0", default-fea hyperlight-guest = { path = "src/hyperlight_guest", version = "0.7.0", default-features = false } hyperlight-guest-bin = { path = "src/hyperlight_guest_bin", version = "0.7.0", default-features = false } hyperlight-testing = { path = "src/hyperlight_testing", default-features = false } +hyperlight-guest-tracing = { path = "src/hyperlight_guest_tracing", default-features = false } +hyperlight-guest-tracing-macro = { path = "src/hyperlight_guest_tracing_macro", default-features = false } hyperlight-component-util = { path = "src/hyperlight_component_util", version = "0.7.0", default-features = false } hyperlight-component-macro = { path = "src/hyperlight_component_macro", version = "0.7.0", default-features = false } diff --git a/src/hyperlight_common/Cargo.toml b/src/hyperlight_common/Cargo.toml index cf317bd9d..ac83d6322 100644 --- a/src/hyperlight_common/Cargo.toml +++ b/src/hyperlight_common/Cargo.toml @@ -25,6 +25,7 @@ spin = "0.10.0" [features] default = ["tracing"] fuzzing = ["dep:arbitrary"] +trace_guest = [] unwind_guest = [] mem_profile = [] std = [] diff --git a/src/hyperlight_common/src/outb.rs b/src/hyperlight_common/src/outb.rs index 43f07a9cf..54bba6f74 100644 --- a/src/hyperlight_common/src/outb.rs +++ b/src/hyperlight_common/src/outb.rs @@ -93,6 +93,7 @@ impl TryFrom for Exception { /// - TraceRecordStack: records the stack trace of the guest /// - TraceMemoryAlloc: records memory allocation events /// - TraceMemoryFree: records memory deallocation events +/// - TraceRecord: records a trace event in the guest pub enum OutBAction { Log = 99, CallFunction = 101, @@ -101,9 +102,11 @@ pub enum OutBAction { #[cfg(feature = "unwind_guest")] TraceRecordStack = 104, #[cfg(feature = "mem_profile")] - TraceMemoryAlloc, + TraceMemoryAlloc = 105, #[cfg(feature = "mem_profile")] - TraceMemoryFree, + TraceMemoryFree = 106, + #[cfg(feature = "trace_guest")] + TraceRecord = 107, } impl TryFrom for OutBAction { @@ -120,6 +123,8 @@ impl TryFrom for OutBAction { 105 => Ok(OutBAction::TraceMemoryAlloc), #[cfg(feature = "mem_profile")] 106 => Ok(OutBAction::TraceMemoryFree), + #[cfg(feature = "trace_guest")] + 107 => Ok(OutBAction::TraceRecord), _ => Err(anyhow::anyhow!("Invalid OutBAction value: {}", val)), } } diff --git a/src/hyperlight_guest_tracing/Cargo.toml b/src/hyperlight_guest_tracing/Cargo.toml new file mode 100644 index 000000000..e77144eaa --- /dev/null +++ b/src/hyperlight_guest_tracing/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "hyperlight-guest-tracing" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +readme.workspace = true +description = """Provides the tracing functionality for the hyperlight guest.""" + +[dependencies] +hyperlight-common = { workspace = true, default-features = false, features = ["trace_guest"] } +spin = "0.10.0" + +[lints] +workspace = true diff --git a/src/hyperlight_guest_tracing/src/lib.rs b/src/hyperlight_guest_tracing/src/lib.rs new file mode 100644 index 000000000..8d7ae0e6a --- /dev/null +++ b/src/hyperlight_guest_tracing/src/lib.rs @@ -0,0 +1,277 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#![no_std] + +// === Dependencies === +extern crate alloc; + +use core::mem::MaybeUninit; + +use hyperlight_common::outb::OutBAction; +use spin::Mutex; + +/// Type alias for the function that sends trace records to the host. +type SendToHostFn = fn(u64, &[TraceRecord]); + +/// Global trace buffer for storing trace records. +static TRACE_BUFFER: Mutex> = Mutex::new(TraceBuffer::new(send_to_host)); + +/// Maximum number of entries in the trace buffer. +/// From local testing, 32 entries seems to be a good balance between performance and memory usage. +const MAX_NO_OF_ENTRIES: usize = 32; + +/// Maximum length of a trace message in bytes. +pub const MAX_TRACE_MSG_LEN: usize = 64; + +#[derive(Debug, Copy, Clone)] +/// Represents a trace record of a guest with a number of cycles and a message. +pub struct TraceRecord { + /// The number of CPU cycles returned by the invariant TSC. + pub cycles: u64, + /// The length of the message in bytes. + pub msg_len: usize, + /// The message associated with the trace record. + pub msg: [u8; MAX_TRACE_MSG_LEN], +} + +impl From<&str> for TraceRecord { + fn from(mut msg: &str) -> Self { + if msg.len() > MAX_TRACE_MSG_LEN { + // If the message is too long, truncate it to fit the maximum length + msg = &msg[..MAX_TRACE_MSG_LEN]; + } + + let cycles = invariant_tsc::read_tsc(); + + TraceRecord { + cycles, + msg: { + let mut arr = [0u8; MAX_TRACE_MSG_LEN]; + arr[..msg.len()].copy_from_slice(msg.as_bytes()); + arr + }, + msg_len: msg.len(), + } + } +} + +/// A buffer for storing trace records. +struct TraceBuffer { + /// The entries in the trace buffer. + entries: [TraceRecord; MAX_NO_OF_ENTRIES], + /// The index where the next entry will be written. + write_index: usize, + /// Function to send the trace records to the host. + send_to_host: F, +} + +impl TraceBuffer { + /// Creates a new `TraceBuffer` with uninitialized entries. + const fn new(f: F) -> Self { + Self { + entries: unsafe { [MaybeUninit::zeroed().assume_init(); MAX_NO_OF_ENTRIES] }, + write_index: 0, + send_to_host: f, + } + } + + /// Push a new trace record into the buffer. + /// If the buffer is full, it sends the records to the host. + fn push(&mut self, entry: TraceRecord) { + let mut write_index = self.write_index; + + self.entries[write_index] = entry; + write_index = (write_index + 1) % MAX_NO_OF_ENTRIES; + + self.write_index = write_index; + + if write_index == 0 { + // If buffer is full send to host + (self.send_to_host)(MAX_NO_OF_ENTRIES as u64, &self.entries); + } + } + + /// Flush the trace buffer, sending any remaining records to the host. + fn flush(&mut self) { + if self.write_index > 0 { + (self.send_to_host)(self.write_index as u64, &self.entries); + self.write_index = 0; // Reset write index after flushing + } + } +} + +/// Send the trace records to the host. +fn send_to_host(len: u64, records: &[TraceRecord]) { + unsafe { + core::arch::asm!("out dx, al", + in("dx") OutBAction::TraceRecord as u16, + in("rax") len, + in("rcx") records.as_ptr() as u64); + } +} + +/// Module for checking invariant TSC support and reading the timestamp counter +pub mod invariant_tsc { + use core::arch::x86_64::{__cpuid, _rdtsc}; + + /// Check if the processor supports invariant TSC + /// + /// Returns true if CPUID.80000007H:EDX[8] is set, indicating invariant TSC support + pub fn has_invariant_tsc() -> bool { + // Check if extended CPUID functions are available + let max_extended = unsafe { __cpuid(0x80000000) }; + if max_extended.eax < 0x80000007 { + return false; + } + + // Query CPUID.80000007H for invariant TSC support + let cpuid_result = unsafe { __cpuid(0x80000007) }; + + // Check bit 8 of EDX register for invariant TSC support + (cpuid_result.edx & (1 << 8)) != 0 + } + + /// Read the timestamp counter + /// + /// This function provides a high-performance timestamp by reading the TSC. + /// Should only be used when invariant TSC is supported for reliable timing. + /// + /// # Safety + /// This function uses unsafe assembly instructions but is safe to call. + /// However, the resulting timestamp is only meaningful if invariant TSC is supported. + pub fn read_tsc() -> u64 { + unsafe { _rdtsc() } + } +} + +/// Create a trace record from the message and push it to the trace buffer. +/// +/// **NOTE**: If the message is too long it will be truncated to fit within `MAX_TRACE_MSG_LEN`. +/// This is useful for ensuring that the trace buffer does not overflow. +pub fn create_trace_record(msg: &str) { + let entry = TraceRecord::from(msg); + let mut buffer = TRACE_BUFFER.lock(); + + buffer.push(entry); +} + +/// Flush the trace buffer to send any remaining trace records to the host. +pub fn flush_trace_buffer() { + let mut buffer = TRACE_BUFFER.lock(); + buffer.flush(); +} + +#[cfg(test)] +mod tests { + use alloc::format; + + use super::*; + + /// This is a mock function for testing purposes. + /// In a real scenario, this would send the trace records to the host. + fn mock_send_to_host(_len: u64, _records: &[TraceRecord]) {} + + fn create_test_entry(msg: &str) -> TraceRecord { + let cycles = invariant_tsc::read_tsc(); + + TraceRecord { + cycles, + msg: { + let mut arr = [0u8; MAX_TRACE_MSG_LEN]; + arr[..msg.len()].copy_from_slice(msg.as_bytes()); + arr + }, + msg_len: msg.len(), + } + } + + #[test] + fn test_push_trace_record() { + let mut buffer = TraceBuffer::new(mock_send_to_host); + + let msg = "Test message"; + let entry = create_test_entry(msg); + + buffer.push(entry); + assert_eq!(buffer.write_index, 1); + assert_eq!(buffer.entries[0].msg_len, msg.len()); + assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); + assert!(buffer.entries[0].cycles > 0); // Ensure cycles is set + } + + #[test] + fn test_flush_trace_buffer() { + let mut buffer = TraceBuffer::new(mock_send_to_host); + + let msg = "Test message"; + let entry = create_test_entry(msg); + + buffer.push(entry); + assert_eq!(buffer.write_index, 1); + assert_eq!(buffer.entries[0].msg_len, msg.len()); + assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); + assert!(buffer.entries[0].cycles > 0); + + // Flush the buffer + buffer.flush(); + + // After flushing, the entryes should still be intact, we don't clear them + assert_eq!(buffer.write_index, 0); + assert_eq!(buffer.entries[0].msg_len, msg.len()); + assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); + assert!(buffer.entries[0].cycles > 0); + } + + #[test] + fn test_auto_flush_on_full() { + let mut buffer = TraceBuffer::new(mock_send_to_host); + + // Fill the buffer to trigger auto-flush + for i in 0..MAX_NO_OF_ENTRIES { + let msg = format!("Message {}", i); + let entry = create_test_entry(&msg); + buffer.push(entry); + } + + // After filling, the write index should be 0 (buffer is full) + assert_eq!(buffer.write_index, 0); + + // The first entry should still be intact + assert_eq!(buffer.entries[0].msg_len, "Message 0".len()); + } + + /// Test TraceRecord creation with a valid message + #[test] + fn test_trace_record_creation_valid() { + let msg = "Valid message"; + let entry = TraceRecord::try_from(msg).expect("Failed to create TraceRecord"); + assert_eq!(entry.msg_len, msg.len()); + assert_eq!(&entry.msg[..msg.len()], msg.as_bytes()); + assert!(entry.cycles > 0); // Ensure cycles is set + } + + /// Test TraceRecord creation with a message that exceeds the maximum length + #[test] + fn test_trace_record_creation_too_long() { + let long_msg = "A".repeat(MAX_TRACE_MSG_LEN + 1); + let result = TraceRecord::from(long_msg.as_str()); + assert_eq!(result.msg_len, MAX_TRACE_MSG_LEN); + assert_eq!( + &result.msg[..MAX_TRACE_MSG_LEN], + &long_msg.as_bytes()[..MAX_TRACE_MSG_LEN], + ); + } +} diff --git a/src/hyperlight_guest_tracing_macro/Cargo.toml b/src/hyperlight_guest_tracing_macro/Cargo.toml new file mode 100644 index 000000000..89522c1de --- /dev/null +++ b/src/hyperlight_guest_tracing_macro/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "hyperlight-guest-tracing-macro" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +readme.workspace = true +description = """Provides the tracing macros for the hyperlight guest, enabling structured logging and tracing capabilities.""" + +[dependencies] +hyperlight-guest-tracing = { workspace = true } +proc-macro2 = "1.0" +quote = "1.0.40" +syn = { version = "2.0.104", features = ["full"] } + +[features] +default = [] + +[lib] +proc-macro = true + +[lints] +workspace = true diff --git a/src/hyperlight_guest_tracing_macro/src/lib.rs b/src/hyperlight_guest_tracing_macro/src/lib.rs new file mode 100644 index 000000000..53f0ef817 --- /dev/null +++ b/src/hyperlight_guest_tracing_macro/src/lib.rs @@ -0,0 +1,250 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +use proc_macro::TokenStream; +use quote::quote; +use syn::{ItemFn, parse_macro_input}; + +/// A procedural macro attribute for tracing function calls. +/// Usage: +/// ```rust +/// #[hyperlight_guest_tracing_macro::trace_function] +/// fn my_function() { +/// // // Function body +/// } +/// ``` +/// +/// This macro will create a trace record when the function is called, if the `trace_guest` +/// feature is enabled. +/// +/// The trace record will contain the function name as a string. +/// Note: This macro is intended to be used with the `hyperlight_guest_tracing` crate. +#[proc_macro_attribute] +pub fn trace_function(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input_fn = parse_macro_input!(item as ItemFn); + + let fn_name = &input_fn.sig.ident; + let fn_name_str = fn_name.to_string(); + let fn_vis = &input_fn.vis; + let fn_sig = &input_fn.sig; + let fn_block = &input_fn.block; + let fn_attrs = &input_fn.attrs; + let fn_output = &input_fn.sig.output; + + // Compose entry/exit messages + let entry_msg = format!("> {}", fn_name_str); + let exit_msg = format!("< {}", fn_name_str); + + if entry_msg.len() > hyperlight_guest_tracing::MAX_TRACE_MSG_LEN + || exit_msg.len() > hyperlight_guest_tracing::MAX_TRACE_MSG_LEN + { + panic!( + "Trace messages must not exceed {} bytes in length.", + hyperlight_guest_tracing::MAX_TRACE_MSG_LEN + ); + } + + let expanded = match fn_output { + syn::ReturnType::Default => { + // No return value (unit) + quote! { + #(#fn_attrs)* + #fn_vis #fn_sig { + #[cfg(feature = "trace_guest")] + hyperlight_guest_tracing::create_trace_record(#entry_msg); + // Call the original function body + #fn_block + #[cfg(feature = "trace_guest")] + hyperlight_guest_tracing::create_trace_record(#exit_msg); + } + } + } + syn::ReturnType::Type(_, _) => { + // Has a return value + quote! { + #(#fn_attrs)* + #fn_vis #fn_sig { + #[cfg(feature = "trace_guest")] + hyperlight_guest_tracing::create_trace_record(concat!("> ", #fn_name_str)); + let __trace_result = (|| #fn_block )(); + #[cfg(feature = "trace_guest")] + hyperlight_guest_tracing::create_trace_record(concat!("< ", #fn_name_str)); + __trace_result + } + } + } + }; + + TokenStream::from(expanded) +} + +// Input structure for the trace macro +struct TraceMacroInput { + message: syn::Lit, + statement: Option, +} + +impl syn::parse::Parse for TraceMacroInput { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let message: syn::Lit = input.parse()?; + if !matches!(message, syn::Lit::Str(_)) { + return Err(input.error("first argument to trace! must be a string literal")); + } + if let syn::Lit::Str(ref lit_str) = message { + if lit_str.value().is_empty() { + return Err(input.error("trace message must not be empty")); + } + if lit_str.value().len() > hyperlight_guest_tracing::MAX_TRACE_MSG_LEN { + return Err(input.error(format!( + "trace message must not exceed {} bytes", + hyperlight_guest_tracing::MAX_TRACE_MSG_LEN + ))); + } + } + + let statement = if input.peek(syn::Token![,]) { + let _: syn::Token![,] = input.parse()?; + Some(input.parse()?) + } else { + None + }; + Ok(TraceMacroInput { message, statement }) + } +} + +/// This macro creates a trace record with a message, or traces a block with entry/exit records. +/// +/// Usage: +/// ```rust +/// use hyperlight_guest_tracing_macro::trace; +/// trace!("message"); +/// trace!("message", { /* block of code */ }); +/// ``` +/// +/// When called with an expression or statement as the second argument, it is wrapped in a block, +/// entry and exit trace records are created at the start and end of block, and the result of the block is returned. +/// +/// # Examples +/// +/// ## Basic usage: trace with message only +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// trace!("hello"); +/// ``` +/// +/// ## Trace with a block, returning a value +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// let x = trace!("block", { 42 }); +/// assert_eq!(x, 42); +/// ``` +/// +/// ## Trace with a block using local variables +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// let y = 10; +/// let z = trace!("sum", { y + 5 }); +/// assert_eq!(z, 15); +/// ``` +/// +/// ## Trace with a block that returns a reference +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// let s = String::from("abc"); +/// let r: &str = trace!("ref", { &s }); +/// assert_eq!(r, "abc"); +/// ``` +/// +/// ## Control flow: `return` inside the block returns from the function +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// fn foo() -> i32 { +/// let _ = trace!("fail", { +/// // This return only exits the closure, not the function `foo`. +/// return 42; +/// }); +/// assert!(false, "This should not be reached"); +/// } +/// ``` +/// +/// ## Control flow: `break` inside the block exits the outer loop +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// let mut x = 0; +/// for i in 1..3 { +/// x = i; +/// let _ = trace!("msg", { +/// // This break should exit the loop. +/// break; +/// }); +/// } +/// assert_eq!(x, 1, "Loop should break after the first iteration"); +/// ``` +#[proc_macro] +pub fn trace(input: TokenStream) -> TokenStream { + let parsed = syn::parse_macro_input!(input as TraceMacroInput); + let trace_message = match parsed.message { + syn::Lit::Str(ref lit_str) => lit_str.value(), + _ => unreachable!(), + }; + if let Some(statement) = parsed.statement { + let entry = format!("+ {}", trace_message); + let exit = format!("- {}", trace_message); + let expanded = quote! { + { + #[cfg(feature = "trace_guest")] + hyperlight_guest_tracing::create_trace_record(#entry); + let __trace_result = #statement; + #[cfg(feature = "trace_guest")] + hyperlight_guest_tracing::create_trace_record(#exit); + __trace_result + } + }; + TokenStream::from(expanded) + } else { + let expanded = quote! { + { + #[cfg(feature = "trace_guest")] + hyperlight_guest_tracing::create_trace_record(#trace_message); + } + }; + TokenStream::from(expanded) + } +} + +/// This macro flushes the trace buffer, sending any remaining trace records to the host. +/// +/// Usage: +/// ```rust +/// hyperlight_guest_tracing_macro::flush!(); +/// ``` +#[proc_macro] +pub fn flush(_input: TokenStream) -> TokenStream { + let expanded = quote! { + { + #[cfg(feature = "trace_guest")] + hyperlight_guest_tracing::flush_trace_buffer(); + } + }; + + TokenStream::from(expanded) +} From cb8c1fc7bd4986e25d5fbd752b68b38e08de8bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Tue, 8 Jul 2025 15:19:54 +0300 Subject: [PATCH 046/271] [hyperlight_host/trace] Handle the trace records sent by a guest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - When an `Out` instruction is intercepted, the Hypervisor checks for the port to verifies what type of exit was encoded. Based on this, when a trace record type is received, we copy the array of trace records from the guest's memory, calculate the timestamp based on the cycles returned by the guest's RDTSC and write the record to the trace file. Signed-off-by: Doru Blânzeanu --- Cargo.lock | 1 + src/hyperlight_host/Cargo.toml | 3 +- .../src/hypervisor/hyperv_linux.rs | 18 +++- .../src/hypervisor/hyperv_windows.rs | 14 ++- src/hyperlight_host/src/hypervisor/kvm.rs | 15 ++- src/hyperlight_host/src/hypervisor/mod.rs | 5 +- src/hyperlight_host/src/sandbox/mod.rs | 34 ++++++ src/hyperlight_host/src/sandbox/outb.rs | 100 +++++++++++++++++- 8 files changed, 178 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a39331791..7dd63e99b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,6 +1427,7 @@ dependencies = [ "goblin", "hyperlight-common", "hyperlight-component-macro", + "hyperlight-guest-tracing", "hyperlight-testing", "kvm-bindings", "kvm-ioctls", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 76a152b38..23753330c 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -39,6 +39,7 @@ tracing = { version = "0.1.41", features = ["log"] } tracing-log = "0.2.0" tracing-core = "0.1.34" hyperlight-common = { workspace = true, default-features = true, features = [ "std" ] } +hyperlight-guest-tracing = { workspace = true, default-features = true, optional = true } vmm-sys-util = "0.14.0" crossbeam-channel = "0.5.15" thiserror = "2.0.12" @@ -131,7 +132,7 @@ executable_heap = [] print_debug = [] # Dumps the VM state to a file on unexpected errors or crashes. The path of the file will be printed on stdout and logged. crashdump = ["dep:chrono"] -trace_guest = [] +trace_guest = ["hyperlight-common/trace_guest", "dep:hyperlight-guest-tracing"] # This feature enables unwinding the guest stack from the host, in # order to produce stack traces for debugging or profiling. unwind_guest = [ "trace_guest", "dep:framehop", "dep:fallible-iterator", "hyperlight-common/unwind_guest" ] diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index ef56a7044..2c7eb7a8e 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -48,7 +48,7 @@ use mshv_bindings::{ hv_partition_property_code_HV_PARTITION_PROPERTY_SYNTHETIC_PROC_FEATURES, hv_partition_synthetic_processor_features, }; -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "trace_guest")] use mshv_bindings::{ hv_register_name, hv_register_name_HV_X64_REGISTER_RAX, hv_register_name_HV_X64_REGISTER_RBP, hv_register_name_HV_X64_REGISTER_RCX, hv_register_name_HV_X64_REGISTER_RSP, @@ -58,7 +58,7 @@ use tracing::{Span, instrument}; #[cfg(crashdump)] use {super::crashdump, std::path::Path}; -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "trace_guest")] use super::TraceRegister; use super::fpu::{FP_CONTROL_WORD_DEFAULT, FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT}; #[cfg(gdb)] @@ -554,7 +554,7 @@ impl Debug for HypervLinuxDriver { } } -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "trace_guest")] impl From for hv_register_name { fn from(r: TraceRegister) -> Self { match r { @@ -761,6 +761,12 @@ impl Hypervisor for HypervLinuxDriver { libc::EINTR, ))) } else { + #[cfg(feature = "trace_guest")] + if self.trace_info.guest_start_epoch.is_none() { + // Set the guest start epoch to the current time, before running the vcpu + crate::debug!("HyperV - Guest Start Epoch set"); + self.trace_info.guest_start_epoch = Some(std::time::Instant::now()); + } // Note: if a `InterruptHandle::kill()` called while this thread is **here** // Then the vcpu will run, but we will keep sending signals to this thread // to interrupt it until `running` is set to false. The `vcpu_fd::run()` call will @@ -1114,7 +1120,7 @@ impl Hypervisor for HypervLinuxDriver { Ok(()) } - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "trace_guest")] fn read_trace_reg(&self, reg: TraceRegister) -> Result { let mut assoc = [hv_register_assoc { name: reg.into(), @@ -1129,6 +1135,10 @@ impl Hypervisor for HypervLinuxDriver { fn trace_info_as_ref(&self) -> &TraceInfo { &self.trace_info } + #[cfg(feature = "trace_guest")] + fn trace_info_as_mut(&mut self) -> &mut TraceInfo { + &mut self.trace_info + } } impl Drop for HypervLinuxDriver { diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index 55b01e8bb..08350d40c 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -44,7 +44,7 @@ use { std::sync::Mutex, }; -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "trace_guest")] use super::TraceRegister; use super::fpu::{FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT}; use super::handlers::{MemAccessHandlerWrapper, OutBHandlerWrapper}; @@ -732,6 +732,12 @@ impl Hypervisor for HypervWindowsDriver { Reserved: Default::default(), } } else { + #[cfg(feature = "trace_guest")] + if self.trace_info.guest_start_epoch.is_none() { + // Set the guest start epoch to the current time, before running the vcpu + crate::debug!("MSHV - Guest Start Epoch set"); + self.trace_info.guest_start_epoch = Some(std::time::Instant::now()); + } self.processor.run()? }; self.interrupt_handle @@ -1046,7 +1052,7 @@ impl Hypervisor for HypervWindowsDriver { Ok(()) } - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "trace_guest")] fn read_trace_reg(&self, reg: TraceRegister) -> Result { let regs = self.processor.get_regs()?; match reg { @@ -1062,6 +1068,10 @@ impl Hypervisor for HypervWindowsDriver { fn trace_info_as_ref(&self) -> &TraceInfo { &self.trace_info } + #[cfg(feature = "trace_guest")] + fn trace_info_as_mut(&mut self) -> &mut TraceInfo { + &mut self.trace_info + } } impl Drop for HypervWindowsDriver { diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index b63c44eb4..0b668c305 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -29,7 +29,7 @@ use tracing::{Span, instrument}; #[cfg(crashdump)] use {super::crashdump, std::path::Path}; -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "trace_guest")] use super::TraceRegister; use super::fpu::{FP_CONTROL_WORD_DEFAULT, FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT}; #[cfg(gdb)] @@ -643,6 +643,13 @@ impl Hypervisor for KVMDriver { { Err(kvm_ioctls::Error::new(libc::EINTR)) } else { + #[cfg(feature = "trace_guest")] + if self.trace_info.guest_start_epoch.is_none() { + // Set the guest start epoch to the current time, before running the vcpu + crate::debug!("KVM - Guest Start Epoch set"); + self.trace_info.guest_start_epoch = Some(std::time::Instant::now()); + } + // Note: if a `InterruptHandle::kill()` called while this thread is **here** // Then the vcpu will run, but we will keep sending signals to this thread // to interrupt it until `running` is set to false. The `vcpu_fd::run()` call will @@ -965,7 +972,7 @@ impl Hypervisor for KVMDriver { Ok(()) } - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "trace_guest")] fn read_trace_reg(&self, reg: TraceRegister) -> Result { let regs = self.vcpu_fd.get_regs()?; Ok(match reg { @@ -981,6 +988,10 @@ impl Hypervisor for KVMDriver { fn trace_info_as_ref(&self) -> &TraceInfo { &self.trace_info } + #[cfg(feature = "trace_guest")] + fn trace_info_as_mut(&mut self) -> &mut TraceInfo { + &mut self.trace_info + } } impl Drop for KVMDriver { diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index 2be3fdf28..a5332d9be 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -270,12 +270,15 @@ pub(crate) trait Hypervisor: Debug + Sync + Send { } /// Read a register for trace/unwind purposes - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "trace_guest")] fn read_trace_reg(&self, reg: TraceRegister) -> Result; /// Get a reference of the trace info for the guest #[cfg(feature = "trace_guest")] fn trace_info_as_ref(&self) -> &TraceInfo; + /// Get a mutable reference of the trace info for the guest + #[cfg(feature = "trace_guest")] + fn trace_info_as_mut(&mut self) -> &mut TraceInfo; } /// A virtual CPU that can be run until an exit occurs diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index 5a2f7be71..7c3c5b156 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -105,6 +105,17 @@ pub(crate) struct TraceInfo { /// early as the creation of the sandbox being traced. #[allow(dead_code)] pub epoch: std::time::Instant, + /// The frequency of the timestamp counter. + #[allow(dead_code)] + pub tsc_freq: u64, + /// The epoch at which the guest started, if it has started. + /// This is used to calculate the time spent in the guest relative to the + /// time of the host. + #[allow(dead_code)] + pub guest_start_epoch: Option, + /// The start guest time, in TSC cycles, for the current guest. + #[allow(dead_code)] + pub guest_start_tsc: Option, /// The file to which the trace is being written #[allow(dead_code)] pub file: Arc>, @@ -139,8 +150,13 @@ impl TraceInfo { let cache = framehop::x86_64::CacheX86_64::new(); (unwinder, Arc::new(Mutex::new(cache))) }; + let tsc_freq = Self::calculate_tsc_freq()?; + let ret = Self { epoch: std::time::Instant::now(), + tsc_freq, + guest_start_epoch: None, + guest_start_tsc: None, file: Arc::new(Mutex::new(std::fs::File::create_new(path)?)), #[cfg(feature = "unwind_guest")] unwind_module, @@ -156,6 +172,24 @@ impl TraceInfo { })?; Ok(ret) } + + /// Calculate the TSC frequency based on the RDTSC instruction. + fn calculate_tsc_freq() -> crate::Result { + if !hyperlight_guest_tracing::invariant_tsc::has_invariant_tsc() { + return Err(crate::new_error!( + "Invariant TSC is not supported on this platform" + )); + } + let start = hyperlight_guest_tracing::invariant_tsc::read_tsc(); + let start_time = std::time::Instant::now(); + // Sleep for 1 second to get a good sample + std::thread::sleep(std::time::Duration::from_secs(1)); + let end = hyperlight_guest_tracing::invariant_tsc::read_tsc(); + let end_time = std::time::Instant::now(); + let elapsed = end_time.duration_since(start_time).as_secs_f64(); + + Ok(((end - start) as f64 / elapsed) as u64) + } } pub(crate) trait WrapperGetter { diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index 5a559321a..0a028b94e 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "trace_guest")] use std::io::Write; use std::sync::{Arc, Mutex}; @@ -26,6 +26,8 @@ use hyperlight_common::flatbuffer_wrappers::function_types::ParameterValue; use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_common::flatbuffer_wrappers::guest_log_data::GuestLogData; use hyperlight_common::outb::{Exception, OutBAction}; +#[cfg(feature = "trace_guest")] +use hyperlight_guest_tracing::TraceRecord; use log::{Level, Record}; use tracing::{Span, instrument}; use tracing_log::format_trace; @@ -33,7 +35,7 @@ use tracing_log::format_trace; use super::host_funcs::FunctionRegistry; use super::mem_mgr::MemMgrWrapper; use crate::hypervisor::handlers::{OutBHandler, OutBHandlerFunction, OutBHandlerWrapper}; -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "trace_guest")] use crate::mem::layout::SandboxMemoryLayout; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; @@ -211,6 +213,53 @@ pub(super) fn record_trace_frame( Ok(()) } +#[cfg(feature = "trace_guest")] +pub(super) fn record_guest_trace_frame( + trace_info: &TraceInfo, + frame_id: u64, + cycles: u64, + write_frame: F, +) -> Result<()> { + let Ok(mut out) = trace_info.file.lock() else { + return Ok(()); + }; + // frame structure: + // 16 bytes timestamp + + // The number of cycles spent in the guest relative to the first received trace record + let cycles_spent = cycles + - trace_info + .guest_start_tsc + .as_ref() + .map_or_else(|| 0, |c| *c); + // Convert cycles to microseconds based on the TSC frequency + let micros = cycles_spent as f64 / trace_info.tsc_freq as f64 * 1_000_000f64; + + // Convert to a Duration + let guest_duration = std::time::Duration::from_micros(micros as u64); + + // Calculate the time when the guest started execution relative to the host epoch + // Note: This is relative to the time saved when the `TraceInfo` was created (before the + // Hypervisor is created). + let guest_start_time = trace_info + .guest_start_epoch + .as_ref() + .unwrap_or(&trace_info.epoch) + .saturating_duration_since(trace_info.epoch); + + // Calculate the timestamp when the actual frame was recorded relative to the host epoch + let timestamp = guest_start_time + .checked_add(guest_duration) + .unwrap_or(guest_duration); + + let _ = out.write_all(×tamp.as_micros().to_ne_bytes()); + // 8 bytes frame type id + let _ = out.write_all(&frame_id.to_ne_bytes()); + // frame data + write_frame(&mut out); + Ok(()) +} + /// Handles OutB operations from the guest. #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] fn handle_outb_impl( @@ -287,6 +336,53 @@ fn handle_outb_impl( write_stack(f, &stack); }) } + #[cfg(feature = "trace_guest")] + OutBAction::TraceRecord => { + let Ok(len) = _hv.read_trace_reg(crate::hypervisor::TraceRegister::RAX) else { + return Ok(()); + }; + let Ok(ptr) = _hv.read_trace_reg(crate::hypervisor::TraceRegister::RCX) else { + return Ok(()); + }; + let mut buffer = vec![0u8; len as usize * std::mem::size_of::()]; + let buffer = &mut buffer[..]; + + // Read the trace records from the guest memory + mem_mgr + .as_ref() + .shared_mem + .copy_to_slice(buffer, ptr as usize - SandboxMemoryLayout::BASE_ADDRESS) + // .read::((addr - SandboxMemoryLayout::BASE_ADDRESS as u64) as usize) + .map_err(|e| { + new_error!( + "Failed to copy trace records from guest memory to host: {:?}", + e + ) + })?; + + let traces = unsafe { + std::slice::from_raw_parts(buffer.as_ptr() as *const TraceRecord, len as usize) + }; + + { + let trace_info = _hv.trace_info_as_mut(); + // Store the start guest cycles if not already set + // This is the `entrypoint` of the guest execution + // This should be set only once, at the start of the guest execution + if trace_info.guest_start_tsc.is_none() && !traces.is_empty() { + trace_info.guest_start_tsc = Some(traces[0].cycles); + } + } + + for record in traces { + record_guest_trace_frame(_hv.trace_info_as_ref(), 4u64, record.cycles, |f| { + let _ = f.write_all(&record.msg_len.to_ne_bytes()); + let _ = f.write_all(&record.msg[..record.msg_len]); + })? + } + + Ok(()) + } } } From 1dea1fdf62e134a194fc878ab039da6ddcfc1a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Tue, 8 Jul 2025 15:24:58 +0300 Subject: [PATCH 047/271] [hyperlight_guest] Add traces in the guest to track the execution timing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add traces wherever we think it might be of use to help us better profile the codebase. - Add flush instructions before halting or running an `OutB` instruction to ensure the records are sent before the guest exits due to an error or a normal exit Signed-off-by: Doru Blânzeanu --- Cargo.lock | 4 + src/hyperlight_guest/Cargo.toml | 6 ++ src/hyperlight_guest/src/exit.rs | 10 +++ .../src/guest_handle/host_comm.rs | 7 ++ src/hyperlight_guest/src/guest_handle/io.rs | 25 ++++-- src/hyperlight_guest_bin/Cargo.toml | 3 + .../src/exceptions/gdt.rs | 1 + .../src/exceptions/handler.rs | 7 ++ .../src/exceptions/idt.rs | 1 + .../src/exceptions/idtr.rs | 1 + .../src/guest_function/call.rs | 9 +- src/hyperlight_guest_bin/src/lib.rs | 6 +- .../src/hypervisor/hyperv_linux.rs | 6 +- .../src/hypervisor/hyperv_windows.rs | 6 +- src/hyperlight_host/src/hypervisor/kvm.rs | 4 +- src/hyperlight_host/src/sandbox/mod.rs | 84 ++++++++++++++----- src/hyperlight_host/src/sandbox/outb.rs | 31 +++++-- .../rust_guests/callbackguest/Cargo.lock | 24 +++++- src/tests/rust_guests/simpleguest/Cargo.lock | 24 +++++- 19 files changed, 208 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7dd63e99b..0abb3a481 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1367,6 +1367,8 @@ version = "0.7.0" dependencies = [ "anyhow", "hyperlight-common", + "hyperlight-guest-tracing", + "hyperlight-guest-tracing-macro", "serde_json", ] @@ -1380,6 +1382,8 @@ dependencies = [ "glob", "hyperlight-common", "hyperlight-guest", + "hyperlight-guest-tracing", + "hyperlight-guest-tracing-macro", "log", "spin 0.10.0", ] diff --git a/src/hyperlight_guest/Cargo.toml b/src/hyperlight_guest/Cargo.toml index 8fce35293..d55aa4f92 100644 --- a/src/hyperlight_guest/Cargo.toml +++ b/src/hyperlight_guest/Cargo.toml @@ -15,3 +15,9 @@ Provides only the essential building blocks for interacting with the host enviro anyhow = { version = "1.0.98", default-features = false } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } hyperlight-common = { workspace = true } +hyperlight-guest-tracing = { workspace = true, optional = true } +hyperlight-guest-tracing-macro = { workspace = true} + +[features] +default = [] +trace_guest = ["dep:hyperlight-guest-tracing"] diff --git a/src/hyperlight_guest/src/exit.rs b/src/hyperlight_guest/src/exit.rs index 82d8a9545..42a9cc0fd 100644 --- a/src/hyperlight_guest/src/exit.rs +++ b/src/hyperlight_guest/src/exit.rs @@ -21,17 +21,22 @@ use hyperlight_common::outb::OutBAction; /// Halt the execution of the guest and returns control to the host. #[inline(never)] +#[hyperlight_guest_tracing_macro::trace_function] pub fn halt() { + // Ensure all tracing data is flushed before halting + hyperlight_guest_tracing_macro::flush!(); unsafe { asm!("hlt", options(nostack)) } } /// Exits the VM with an Abort OUT action and code 0. #[unsafe(no_mangle)] +#[hyperlight_guest_tracing_macro::trace_function] pub extern "C" fn abort() -> ! { abort_with_code(&[0, 0xFF]) } /// Exits the VM with an Abort OUT action and a specific code. +#[hyperlight_guest_tracing_macro::trace_function] pub fn abort_with_code(code: &[u8]) -> ! { outb(OutBAction::Abort as u16, code); outb(OutBAction::Abort as u16, &[0xFF]); // send abort terminator (if not included in code) @@ -42,6 +47,7 @@ pub fn abort_with_code(code: &[u8]) -> ! { /// /// # Safety /// This function is unsafe because it dereferences a raw pointer. +#[hyperlight_guest_tracing_macro::trace_function] pub unsafe fn abort_with_code_and_message(code: &[u8], message_ptr: *const c_char) -> ! { unsafe { // Step 1: Send abort code (typically 1 byte, but `code` allows flexibility) @@ -62,7 +68,10 @@ pub unsafe fn abort_with_code_and_message(code: &[u8], message_ptr: *const c_cha } /// OUT bytes to the host through multiple exits. +#[hyperlight_guest_tracing_macro::trace_function] pub(crate) fn outb(port: u16, data: &[u8]) { + // Ensure all tracing data is flushed before sending OUT bytes + hyperlight_guest_tracing_macro::flush!(); unsafe { let mut i = 0; while i < data.len() { @@ -79,6 +88,7 @@ pub(crate) fn outb(port: u16, data: &[u8]) { } /// OUT function for sending a 32-bit value to the host. +#[hyperlight_guest_tracing_macro::trace_function] pub(crate) unsafe fn out32(port: u16, val: u32) { unsafe { asm!("out dx, eax", in("dx") port, in("eax") val, options(preserves_flags, nomem, nostack)); diff --git a/src/hyperlight_guest/src/guest_handle/host_comm.rs b/src/hyperlight_guest/src/guest_handle/host_comm.rs index 972685ae1..d5cf57ffa 100644 --- a/src/hyperlight_guest/src/guest_handle/host_comm.rs +++ b/src/hyperlight_guest/src/guest_handle/host_comm.rs @@ -35,6 +35,7 @@ use crate::exit::out32; impl GuestHandle { /// Get user memory region as bytes. + #[hyperlight_guest_tracing_macro::trace_function] pub fn read_n_bytes_from_user_memory(&self, num: u64) -> Result> { let peb_ptr = self.peb().unwrap(); let user_memory_region_ptr = unsafe { (*peb_ptr).init_data.ptr as *mut u8 }; @@ -63,6 +64,7 @@ impl GuestHandle { /// /// When calling `call_host_function`, this function is called /// internally to get the return value. + #[hyperlight_guest_tracing_macro::trace_function] pub fn get_host_return_value>(&self) -> Result { let return_value = self .try_pop_shared_input_data_into::() @@ -83,6 +85,7 @@ impl GuestHandle { /// /// Note: The function return value must be obtained by calling /// `get_host_return_value`. + #[hyperlight_guest_tracing_macro::trace_function] pub fn call_host_function_without_returning_result( &self, function_name: &str, @@ -114,6 +117,7 @@ impl GuestHandle { /// sends it to the host, and then retrieves the return value. /// /// The return value is deserialized into the specified type `T`. + #[hyperlight_guest_tracing_macro::trace_function] pub fn call_host_function>( &self, function_name: &str, @@ -124,6 +128,7 @@ impl GuestHandle { self.get_host_return_value::() } + #[hyperlight_guest_tracing_macro::trace_function] pub fn get_host_function_details(&self) -> HostFunctionDetails { let peb_ptr = self.peb().unwrap(); let host_function_details_buffer = @@ -140,6 +145,7 @@ impl GuestHandle { } /// Write an error to the shared output data buffer. + #[hyperlight_guest_tracing_macro::trace_function] pub fn write_error(&self, error_code: ErrorCode, message: Option<&str>) { let guest_error: GuestError = GuestError::new( error_code, @@ -155,6 +161,7 @@ impl GuestHandle { } /// Log a message with the specified log level, source, caller, source file, and line number. + #[hyperlight_guest_tracing_macro::trace_function] pub fn log_message( &self, log_level: LogLevel, diff --git a/src/hyperlight_guest/src/guest_handle/io.rs b/src/hyperlight_guest/src/guest_handle/io.rs index ce8c82b0c..4654f0001 100644 --- a/src/hyperlight_guest/src/guest_handle/io.rs +++ b/src/hyperlight_guest/src/guest_handle/io.rs @@ -27,6 +27,7 @@ use crate::error::{HyperlightGuestError, Result}; impl GuestHandle { /// Pops the top element from the shared input data buffer and returns it as a T + #[hyperlight_guest_tracing_macro::trace_function] pub fn try_pop_shared_input_data_into(&self) -> Result where T: for<'a> TryFrom<&'a [u8]>, @@ -68,15 +69,18 @@ impl GuestHandle { let buffer = &idb[last_element_offset_rel as usize..]; // convert the buffer to T - let type_t = match T::try_from(buffer) { - Ok(t) => Ok(t), - Err(_e) => { - return Err(HyperlightGuestError::new( - ErrorCode::GuestError, - format!("Unable to convert buffer to {}", type_name::()), - )); + let type_t = hyperlight_guest_tracing_macro::trace!( + "convert buffer", + match T::try_from(buffer) { + Ok(t) => Ok(t), + Err(_e) => { + return Err(HyperlightGuestError::new( + ErrorCode::GuestError, + format!("Unable to convert buffer to {}", type_name::()), + )); + } } - }; + ); // update the stack pointer to point to the element we just popped of since that is now free idb[..8].copy_from_slice(&last_element_offset_rel.to_le_bytes()); @@ -88,6 +92,7 @@ impl GuestHandle { } /// Pushes the given data onto the shared output data buffer. + #[hyperlight_guest_tracing_macro::trace_function] pub fn push_shared_output_data(&self, data: Vec) -> Result<()> { let peb_ptr = self.peb().unwrap(); let output_stack_size = unsafe { (*peb_ptr).output_stack.size as usize }; @@ -133,7 +138,9 @@ impl GuestHandle { } // write the actual data - odb[stack_ptr_rel as usize..stack_ptr_rel as usize + data.len()].copy_from_slice(&data); + hyperlight_guest_tracing_macro::trace!("copy data", { + odb[stack_ptr_rel as usize..stack_ptr_rel as usize + data.len()].copy_from_slice(&data); + }); // write the offset to the newly written data, to the top of the stack let bytes: [u8; 8] = stack_ptr_rel.to_le_bytes(); diff --git a/src/hyperlight_guest_bin/Cargo.toml b/src/hyperlight_guest_bin/Cargo.toml index a0347f866..ff30980b4 100644 --- a/src/hyperlight_guest_bin/Cargo.toml +++ b/src/hyperlight_guest_bin/Cargo.toml @@ -17,11 +17,14 @@ and third-party code used by our C-API needed to build a native hyperlight-guest default = ["libc", "printf"] libc = [] # compile musl libc printf = [] # compile printf +trace_guest = ["hyperlight-common/trace_guest", "dep:hyperlight-guest-tracing", "hyperlight-guest/trace_guest"] mem_profile = ["hyperlight-common/unwind_guest","hyperlight-common/mem_profile"] [dependencies] hyperlight-guest = { workspace = true, default-features = false } hyperlight-common = { workspace = true, default-features = false } +hyperlight-guest-tracing = { workspace = true, optional = true } +hyperlight-guest-tracing-macro = { workspace = true } buddy_system_allocator = "0.11.0" log = { version = "0.4", default-features = false } spin = "0.10.0" diff --git a/src/hyperlight_guest_bin/src/exceptions/gdt.rs b/src/hyperlight_guest_bin/src/exceptions/gdt.rs index 0a3b2cfb6..0da032321 100644 --- a/src/hyperlight_guest_bin/src/exceptions/gdt.rs +++ b/src/hyperlight_guest_bin/src/exceptions/gdt.rs @@ -72,6 +72,7 @@ struct GdtPointer { } /// Load the GDT +#[hyperlight_guest_tracing_macro::trace_function] pub unsafe fn load_gdt() { unsafe { let gdt_ptr = GdtPointer { diff --git a/src/hyperlight_guest_bin/src/exceptions/handler.rs b/src/hyperlight_guest_bin/src/exceptions/handler.rs index ab0da4cfe..b2cae2c4f 100644 --- a/src/hyperlight_guest_bin/src/exceptions/handler.rs +++ b/src/hyperlight_guest_bin/src/exceptions/handler.rs @@ -65,6 +65,12 @@ pub extern "C" fn hl_exception_handler( exception_number: u64, page_fault_address: u64, ) { + // When using the `trace_function` macro, it wraps the function body with create_trace_record + // call, which generates a warning because of the `abort_with_code_and_message` call which does + // not return. + // This is manually added to avoid the warning. + hyperlight_guest_tracing_macro::trace!("> hl_exception_handler"); + let ctx = stack_pointer as *mut Context; let exn_info = (stack_pointer + size_of::() as u64) as *mut ExceptionInfo; @@ -95,6 +101,7 @@ pub extern "C" fn hl_exception_handler( )(exception_number, exn_info, ctx, page_fault_address) } { + hyperlight_guest_tracing_macro::trace!("< hl_exception_handler"); return; } } diff --git a/src/hyperlight_guest_bin/src/exceptions/idt.rs b/src/hyperlight_guest_bin/src/exceptions/idt.rs index 3107c4df4..820e96861 100644 --- a/src/hyperlight_guest_bin/src/exceptions/idt.rs +++ b/src/hyperlight_guest_bin/src/exceptions/idt.rs @@ -71,6 +71,7 @@ impl IdtEntry { // Architectures Software Developer's Manual). pub(crate) static mut IDT: [IdtEntry; 256] = unsafe { core::mem::zeroed() }; +#[hyperlight_guest_tracing_macro::trace_function] pub(crate) fn init_idt() { set_idt_entry(Exception::DivideByZero as usize, _do_excp0); // Divide by zero set_idt_entry(Exception::Debug as usize, _do_excp1); // Debug diff --git a/src/hyperlight_guest_bin/src/exceptions/idtr.rs b/src/hyperlight_guest_bin/src/exceptions/idtr.rs index d1d54830b..0d020f1e8 100644 --- a/src/hyperlight_guest_bin/src/exceptions/idtr.rs +++ b/src/hyperlight_guest_bin/src/exceptions/idtr.rs @@ -40,6 +40,7 @@ impl Idtr { } } +#[hyperlight_guest_tracing_macro::trace_function] pub(crate) unsafe fn load_idt() { unsafe { init_idt(); diff --git a/src/hyperlight_guest_bin/src/guest_function/call.rs b/src/hyperlight_guest_bin/src/guest_function/call.rs index 0c7c99a0e..376b0cf35 100644 --- a/src/hyperlight_guest_bin/src/guest_function/call.rs +++ b/src/hyperlight_guest_bin/src/guest_function/call.rs @@ -27,6 +27,7 @@ use crate::{GUEST_HANDLE, REGISTERED_GUEST_FUNCTIONS}; type GuestFunc = fn(&FunctionCall) -> Result>; +#[hyperlight_guest_tracing_macro::trace_function] pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result> { // Validate this is a Guest Function Call if function_call.function_call_type() != FunctionCallType::Guest { @@ -61,7 +62,7 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result core::mem::transmute::(function_pointer) }; - p_function(&function_call) + hyperlight_guest_tracing_macro::trace!("guest_function", p_function(&function_call)) } else { // The given function is not registered. The guest should implement a function called guest_dispatch_function to handle this. @@ -72,7 +73,9 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result fn guest_dispatch_function(function_call: FunctionCall) -> Result>; } - unsafe { guest_dispatch_function(function_call) } + hyperlight_guest_tracing_macro::trace!("default guest function", unsafe { + guest_dispatch_function(function_call) + }) } } @@ -80,6 +83,7 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result // and we will leak memory as the epilogue will not be called as halt() is not going to return. #[unsafe(no_mangle)] #[inline(never)] +#[hyperlight_guest_tracing_macro::trace_function] fn internal_dispatch_function() -> Result<()> { let handle = unsafe { GUEST_HANDLE }; @@ -100,6 +104,7 @@ fn internal_dispatch_function() -> Result<()> { // This is implemented as a separate function to make sure that epilogue in the internal_dispatch_function is called before the halt() // which if it were included in the internal_dispatch_function cause the epilogue to not be called because the halt() would not return // when running in the hypervisor. +#[hyperlight_guest_tracing_macro::trace_function] pub(crate) extern "C" fn dispatch_function() { // The hyperlight host likes to use one partition and reset it in // various ways; if that has happened, there might stale TLB diff --git a/src/hyperlight_guest_bin/src/lib.rs b/src/hyperlight_guest_bin/src/lib.rs index 133e282e7..9d8a2c35e 100644 --- a/src/hyperlight_guest_bin/src/lib.rs +++ b/src/hyperlight_guest_bin/src/lib.rs @@ -32,6 +32,7 @@ use hyperlight_common::mem::HyperlightPEB; use hyperlight_common::outb::OutBAction; use hyperlight_guest::exit::{abort_with_code_and_message, halt}; use hyperlight_guest::guest_handle::handle::GuestHandle; +use hyperlight_guest_tracing_macro::{trace, trace_function}; use log::LevelFilter; use spin::Once; @@ -155,6 +156,7 @@ unsafe extern "C" { static INIT: Once = Once::new(); #[unsafe(no_mangle)] +#[trace_function] pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_level: u64) { if peb_address == 0 { panic!("PEB address is null"); @@ -204,7 +206,9 @@ pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_leve (*peb_ptr).guest_function_dispatch_ptr = dispatch_function as usize as u64; - hyperlight_main(); + trace!("hyperlight_main", + hyperlight_main(); + ); } }); diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 2c7eb7a8e..65f8910be 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -763,8 +763,10 @@ impl Hypervisor for HypervLinuxDriver { } else { #[cfg(feature = "trace_guest")] if self.trace_info.guest_start_epoch.is_none() { - // Set the guest start epoch to the current time, before running the vcpu - crate::debug!("HyperV - Guest Start Epoch set"); + // Store the guest start epoch and cycles to trace the guest execution time + crate::debug!("MSHV - Guest Start Epoch set"); + self.trace_info.guest_start_tsc = + Some(hyperlight_guest_tracing::invariant_tsc::read_tsc()); self.trace_info.guest_start_epoch = Some(std::time::Instant::now()); } // Note: if a `InterruptHandle::kill()` called while this thread is **here** diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index 08350d40c..01c2b0560 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -734,8 +734,10 @@ impl Hypervisor for HypervWindowsDriver { } else { #[cfg(feature = "trace_guest")] if self.trace_info.guest_start_epoch.is_none() { - // Set the guest start epoch to the current time, before running the vcpu - crate::debug!("MSHV - Guest Start Epoch set"); + // Store the guest start epoch and cycles to trace the guest execution time + crate::debug!("HyperV - Guest Start Epoch set"); + self.trace_info.guest_start_tsc = + Some(hyperlight_guest_tracing::invariant_tsc::read_tsc()); self.trace_info.guest_start_epoch = Some(std::time::Instant::now()); } self.processor.run()? diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index 0b668c305..188c27ed7 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -645,9 +645,11 @@ impl Hypervisor for KVMDriver { } else { #[cfg(feature = "trace_guest")] if self.trace_info.guest_start_epoch.is_none() { - // Set the guest start epoch to the current time, before running the vcpu + // Store the guest start epoch and cycles to trace the guest execution time crate::debug!("KVM - Guest Start Epoch set"); self.trace_info.guest_start_epoch = Some(std::time::Instant::now()); + self.trace_info.guest_start_tsc = + Some(hyperlight_guest_tracing::invariant_tsc::read_tsc()); } // Note: if a `InterruptHandle::kill()` called while this thread is **here** diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index 7c3c5b156..5b367cb6f 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -90,7 +90,7 @@ pub type ExtraAllowedSyscall = i64; /// Determine whether a suitable hypervisor is available to run /// this sandbox. /// -// Returns a boolean indicating whether a suitable hypervisor is present. +/// Returns a boolean indicating whether a suitable hypervisor is present. #[instrument(skip_all, parent = Span::current())] pub fn is_hypervisor_present() -> bool { hypervisor::get_available_hypervisor().is_some() @@ -103,18 +103,23 @@ pub fn is_hypervisor_present() -> bool { pub(crate) struct TraceInfo { /// The epoch against which trace events are timed; at least as /// early as the creation of the sandbox being traced. - #[allow(dead_code)] pub epoch: std::time::Instant, /// The frequency of the timestamp counter. - #[allow(dead_code)] - pub tsc_freq: u64, + pub tsc_freq: Option, /// The epoch at which the guest started, if it has started. /// This is used to calculate the time spent in the guest relative to the - /// time of the host. - #[allow(dead_code)] + /// time when the host started. pub guest_start_epoch: Option, - /// The start guest time, in TSC cycles, for the current guest. - #[allow(dead_code)] + /// The start guest time, in TSC cycles, for the current guest has a double purpose. + /// This field is used in two ways: + /// 1. It contains the TSC value recorded on the host when the guest started. + /// This is used to calculate the TSC frequency which is the same on the host and guest. + /// The TSC frequency is used to convert TSC values to timestamps in the trace. + /// **NOTE**: This is only used until the TSC frequency is calculated, when the first + /// records are received. + /// 2. To store the TSC value at recorded on the guest when the guest started (first record + /// received) + /// This is used to calculate the records timestamps relative to when guest started. pub guest_start_tsc: Option, /// The file to which the trace is being written #[allow(dead_code)] @@ -139,8 +144,17 @@ impl TraceInfo { ) -> crate::Result { let mut path = std::env::current_dir()?; path.push("trace"); + + // create directory if it does not exist + if !path.exists() { + std::fs::create_dir(&path)?; + } path.push(uuid::Uuid::new_v4().to_string()); path.set_extension("trace"); + + log::info!("Creating trace file at: {}", path.display()); + println!("Creating trace file at: {}", path.display()); + #[cfg(feature = "unwind_guest")] let hash = unwind_module.hash(); #[cfg(feature = "unwind_guest")] @@ -150,11 +164,17 @@ impl TraceInfo { let cache = framehop::x86_64::CacheX86_64::new(); (unwinder, Arc::new(Mutex::new(cache))) }; - let tsc_freq = Self::calculate_tsc_freq()?; + if !hyperlight_guest_tracing::invariant_tsc::has_invariant_tsc() { + // If the platform does not support invariant TSC, warn the user. + // On Azure nested virtualization, the TSC invariant bit is not correctly reported, this is a known issue. + log::warn!( + "Invariant TSC is not supported on this platform, trace timestamps may be inaccurate" + ); + } let ret = Self { epoch: std::time::Instant::now(), - tsc_freq, + tsc_freq: None, guest_start_epoch: None, guest_start_tsc: None, file: Arc::new(Mutex::new(std::fs::File::create_new(path)?)), @@ -173,22 +193,40 @@ impl TraceInfo { Ok(ret) } - /// Calculate the TSC frequency based on the RDTSC instruction. - fn calculate_tsc_freq() -> crate::Result { - if !hyperlight_guest_tracing::invariant_tsc::has_invariant_tsc() { - return Err(crate::new_error!( - "Invariant TSC is not supported on this platform" - )); - } - let start = hyperlight_guest_tracing::invariant_tsc::read_tsc(); - let start_time = std::time::Instant::now(); - // Sleep for 1 second to get a good sample - std::thread::sleep(std::time::Duration::from_secs(1)); - let end = hyperlight_guest_tracing::invariant_tsc::read_tsc(); + /// Calculate the TSC frequency based on the RDTSC instruction on the host. + fn calculate_tsc_freq(&mut self) -> crate::Result<()> { + let (start, start_time) = match ( + self.guest_start_tsc.as_ref(), + self.guest_start_epoch.as_ref(), + ) { + (Some(start), Some(start_time)) => (*start, *start_time), + _ => { + // If the guest start TSC and time are not set, we use the current time and TSC. + // This is not ideal, but it allows us to calculate the TSC frequency without + // failing. + // This is a fallback mechanism to ensure that we can still calculate, however it + // should be noted that this may lead to inaccuracies in the TSC frequency. + // The start time should be already set before running the guest for each sandbox. + log::error!( + "Guest start TSC and time are not set. Calculating TSC frequency will use current time and TSC." + ); + ( + hyperlight_guest_tracing::invariant_tsc::read_tsc(), + std::time::Instant::now(), + ) + } + }; + let end_time = std::time::Instant::now(); + let end = hyperlight_guest_tracing::invariant_tsc::read_tsc(); + let elapsed = end_time.duration_since(start_time).as_secs_f64(); + let tsc_freq = ((end - start) as f64 / elapsed) as u64; + + log::info!("Calculated TSC frequency: {} Hz", tsc_freq); + self.tsc_freq = Some(tsc_freq); - Ok(((end - start) as f64 / elapsed) as u64) + Ok(()) } } diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index 0a028b94e..62b3bf0c1 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -232,8 +232,13 @@ pub(super) fn record_guest_trace_frame( .guest_start_tsc .as_ref() .map_or_else(|| 0, |c| *c); + // Convert cycles to microseconds based on the TSC frequency - let micros = cycles_spent as f64 / trace_info.tsc_freq as f64 * 1_000_000f64; + let tsc_freq = trace_info + .tsc_freq + .as_ref() + .ok_or_else(|| new_error!("TSC frequency not set in TraceInfo"))?; + let micros = cycles_spent as f64 / *tsc_freq as f64 * 1_000_000f64; // Convert to a Duration let guest_duration = std::time::Duration::from_micros(micros as u64); @@ -352,7 +357,6 @@ fn handle_outb_impl( .as_ref() .shared_mem .copy_to_slice(buffer, ptr as usize - SandboxMemoryLayout::BASE_ADDRESS) - // .read::((addr - SandboxMemoryLayout::BASE_ADDRESS as u64) as usize) .map_err(|e| { new_error!( "Failed to copy trace records from guest memory to host: {:?}", @@ -366,11 +370,24 @@ fn handle_outb_impl( { let trace_info = _hv.trace_info_as_mut(); - // Store the start guest cycles if not already set - // This is the `entrypoint` of the guest execution - // This should be set only once, at the start of the guest execution - if trace_info.guest_start_tsc.is_none() && !traces.is_empty() { - trace_info.guest_start_tsc = Some(traces[0].cycles); + + // Calculate the TSC frequency based on the current TSC reading + // This is done only once, when the first trace record is received + // Ideally, we should use a timer or a clock to measure the time elapsed, + // but that adds delays. + // To avoid that we store the TSC value and a timestamp right + // before starting the guest execution and then calculate the TSC frequency when + // the first trace record is received, based on the current TSC value and clock. + if trace_info.tsc_freq.is_none() { + trace_info.calculate_tsc_freq()?; + + // After the TSC frequency is calculated, we no longer need the value of TSC + // recorded on the host when the guest started, so we can set the guest_start_tsc field + // to store the TSC value recorded on the guest when the guest started executing. + // This is used to calculate the records timestamps relative to the first trace record. + if !traces.is_empty() { + trace_info.guest_start_tsc = Some(traces[0].cycles); + } } } diff --git a/src/tests/rust_guests/callbackguest/Cargo.lock b/src/tests/rust_guests/callbackguest/Cargo.lock index 82979afeb..ddaec1d0b 100644 --- a/src/tests/rust_guests/callbackguest/Cargo.lock +++ b/src/tests/rust_guests/callbackguest/Cargo.lock @@ -85,6 +85,7 @@ version = "0.7.0" dependencies = [ "anyhow", "hyperlight-common", + "hyperlight-guest-tracing-macro", "serde_json", ] @@ -98,10 +99,29 @@ dependencies = [ "glob", "hyperlight-common", "hyperlight-guest", + "hyperlight-guest-tracing-macro", "log", "spin 0.10.0", ] +[[package]] +name = "hyperlight-guest-tracing" +version = "0.7.0" +dependencies = [ + "hyperlight-common", + "spin 0.10.0", +] + +[[package]] +name = "hyperlight-guest-tracing-macro" +version = "0.7.0" +dependencies = [ + "hyperlight-guest-tracing", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "itoa" version = "1.0.15" @@ -233,9 +253,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index b30d4ef5e..62170dcbb 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -76,6 +76,7 @@ version = "0.7.0" dependencies = [ "anyhow", "hyperlight-common", + "hyperlight-guest-tracing-macro", "serde_json", ] @@ -89,10 +90,29 @@ dependencies = [ "glob", "hyperlight-common", "hyperlight-guest", + "hyperlight-guest-tracing-macro", "log", "spin 0.10.0", ] +[[package]] +name = "hyperlight-guest-tracing" +version = "0.7.0" +dependencies = [ + "hyperlight-common", + "spin 0.10.0", +] + +[[package]] +name = "hyperlight-guest-tracing-macro" +version = "0.7.0" +dependencies = [ + "hyperlight-guest-tracing", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "itoa" version = "1.0.15" @@ -234,9 +254,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", From 4ac82dae298ae5b243a44b9d08a91564c78dc824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Tue, 8 Jul 2025 15:28:10 +0300 Subject: [PATCH 048/271] Update sample guests to accept features that enable tracing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update CI to test the tracing functionality - Add features for the Justfile to be able to build guests with features Signed-off-by: Doru Blânzeanu --- .github/workflows/dep_rust.yml | 8 + Justfile | 33 ++- .../rust_guests/callbackguest/Cargo.lock | 34 +-- .../rust_guests/callbackguest/Cargo.toml | 8 +- src/tests/rust_guests/dummyguest/Cargo.lock | 265 +++++++++++++++++- src/tests/rust_guests/dummyguest/Cargo.toml | 13 +- src/tests/rust_guests/simpleguest/Cargo.lock | 34 +-- src/tests/rust_guests/simpleguest/Cargo.toml | 7 + src/tests/rust_guests/witguest/Cargo.lock | 22 ++ src/tests/rust_guests/witguest/Cargo.toml | 8 +- 10 files changed, 391 insertions(+), 41 deletions(-) diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index f08958515..e625eb88a 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -137,6 +137,7 @@ jobs: cargo check -p hyperlight-host --features crashdump cargo check -p hyperlight-host --features print_debug cargo check -p hyperlight-host --features gdb + cargo check -p hyperlight-host --features trace_guest,unwind_guest,mem_profile # without any features just test-compilation-no-default-features ${{ matrix.config }} @@ -169,6 +170,13 @@ jobs: RUST_LOG: debug run: just test-rust-crashdump ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} + - name: Run Rust Tracing tests - linux + if: runner.os == 'Linux' + env: + CARGO_TERM_COLOR: always + RUST_LOG: debug + run: just test-rust-tracing ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv2' && 'mshv2' || ''}} + - name: Download benchmarks from "latest" run: just bench-download ${{ runner.os }} ${{ matrix.hypervisor }} ${{ matrix.cpu}} dev-latest # compare to prerelease env: diff --git a/Justfile b/Justfile index 276c7985d..4f42efd2e 100644 --- a/Justfile +++ b/Justfile @@ -38,11 +38,11 @@ witguest-wit: cargo install --locked wasm-tools cd src/tests/rust_guests/witguest && wasm-tools component wit guest.wit -w -o interface.wasm -build-rust-guests target=default-target: (witguest-wit) - cd src/tests/rust_guests/callbackguest && cargo build --profile={{ if target == "debug" { "dev" } else { target } }} - cd src/tests/rust_guests/simpleguest && cargo build --profile={{ if target == "debug" { "dev" } else { target } }} - cd src/tests/rust_guests/dummyguest && cargo build --profile={{ if target == "debug" { "dev" } else { target } }} - cd src/tests/rust_guests/witguest && cargo build --profile={{ if target == "debug" { "dev" } else { target } }} +build-rust-guests target=default-target features="": (witguest-wit) + cd src/tests/rust_guests/callbackguest && cargo build {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} + cd src/tests/rust_guests/simpleguest && cargo build {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} + cd src/tests/rust_guests/dummyguest && cargo build {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} + cd src/tests/rust_guests/witguest && cargo build {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} @move-rust-guests target=default-target: cp {{ callbackguest_source }}/{{ target }}/callbackguest* {{ rust_guests_bin_dir }}/{{ target }}/ @@ -82,6 +82,7 @@ test-like-ci config=default-target hypervisor="kvm": cargo check -p hyperlight-host --features crashdump cargo check -p hyperlight-host --features print_debug cargo check -p hyperlight-host --features gdb + cargo check -p hyperlight-host --features trace_guest,unwind_guest,mem_profile @# without any driver (should fail to compile) just test-compilation-no-default-features {{config}} @@ -89,6 +90,9 @@ test-like-ci config=default-target hypervisor="kvm": @# test the crashdump feature just test-rust-crashdump {{config}} + @# test the tracing related features + just test-rust-tracing {{config}} {{ if hypervisor == "mshv3" {"mshv3"} else {""} }} + # runs all tests test target=default-target features="": (test-unit target features) (test-isolated target features) (test-integration "rust" target features) (test-integration "c" target features) (test-seccomp target features) @@ -141,6 +145,25 @@ test-rust-gdb-debugging target=default-target features="": test-rust-crashdump target=default-target features="": cargo test --profile={{ if target == "debug" { "dev" } else { target } }} {{ if features =="" {'--features crashdump'} else { "--features crashdump," + features } }} -- test_crashdump +# rust test for tracing +test-rust-tracing target=default-target features="": + # Run tests for the tracing guest and macro + cargo test -p hyperlight-guest-tracing --profile={{ if target == "debug" { "dev" } else { target } }} + cargo test -p hyperlight-guest-tracing-macro --profile={{ if target == "debug" { "dev" } else { target } }} + + # Prepare the tracing guest for testing + just build-rust-guests {{ target }} trace_guest + just move-rust-guests {{ target }} + # Run hello-world example with tracing enabled to get the trace output + # Capture the trace file path and print use it afterwards to run cargo run -p trace_dump + cargo run --profile={{ if target == "debug" { "dev" } else { target } }} --example hello-world --features {{ if features =="" {'trace_guest'} else { "trace_guest," + features } }} \ + | sed -n 's/.*Creating trace file at: \(.*\)/\1/p' \ + | xargs -I {} cargo run -p trace_dump ./{{ simpleguest_source }}/{{ target }}/simpleguest {} list_frames + + # Rebuild the tracing guests without the tracing feature + # This is to ensure that the tracing feature does not affect the other tests + just build-rust-guests {{ target }} + just move-rust-guests {{ target }} ################ ### LINTING #### diff --git a/src/tests/rust_guests/callbackguest/Cargo.lock b/src/tests/rust_guests/callbackguest/Cargo.lock index ddaec1d0b..075c49f42 100644 --- a/src/tests/rust_guests/callbackguest/Cargo.lock +++ b/src/tests/rust_guests/callbackguest/Cargo.lock @@ -10,15 +10,15 @@ checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "buddy_system_allocator" @@ -40,18 +40,18 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.25" +version = "1.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" dependencies = [ "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "flatbuffers" @@ -85,6 +85,7 @@ version = "0.7.0" dependencies = [ "anyhow", "hyperlight-common", + "hyperlight-guest-tracing", "hyperlight-guest-tracing-macro", "serde_json", ] @@ -99,6 +100,7 @@ dependencies = [ "glob", "hyperlight-common", "hyperlight-guest", + "hyperlight-guest-tracing", "hyperlight-guest-tracing-macro", "log", "spin 0.10.0", @@ -130,9 +132,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -146,15 +148,15 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -217,9 +219,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" dependencies = [ "itoa", "memchr", diff --git a/src/tests/rust_guests/callbackguest/Cargo.toml b/src/tests/rust_guests/callbackguest/Cargo.toml index ccbdf6a0a..2d63452e4 100644 --- a/src/tests/rust_guests/callbackguest/Cargo.toml +++ b/src/tests/rust_guests/callbackguest/Cargo.toml @@ -6,4 +6,10 @@ edition = "2021" [dependencies] hyperlight-guest = { path = "../../../hyperlight_guest" } hyperlight-guest-bin = { path = "../../../hyperlight_guest_bin" } -hyperlight-common = { path = "../../../hyperlight_common", default-features = false } \ No newline at end of file +hyperlight-common = { path = "../../../hyperlight_common", default-features = false } + +[features] +default = [] +trace_guest = ["hyperlight-guest-bin/trace_guest"] +unwind_guest = ["hyperlight-common/unwind_guest"] +mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] \ No newline at end of file diff --git a/src/tests/rust_guests/dummyguest/Cargo.lock b/src/tests/rust_guests/dummyguest/Cargo.lock index 3848de252..3b7a713a7 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.lock +++ b/src/tests/rust_guests/dummyguest/Cargo.lock @@ -1,7 +1,270 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "buddy_system_allocator" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0108968a3a2dab95b089c0fc3f1afa7759aa5ebe6f1d86d206d6f7ba726eb" +dependencies = [ + "spin 0.9.8", +] + +[[package]] +name = "cc" +version = "1.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "dummyguest" version = "0.4.0" +dependencies = [ + "hyperlight-common", + "hyperlight-guest-bin", +] + +[[package]] +name = "flatbuffers" +version = "25.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1045398c1bfd89168b5fd3f1fc11f6e70b34f6f66300c87d44d3de849463abf1" +dependencies = [ + "bitflags", + "rustc_version", +] + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "hyperlight-common" +version = "0.7.0" +dependencies = [ + "anyhow", + "flatbuffers", + "log", + "spin 0.10.0", +] + +[[package]] +name = "hyperlight-guest" +version = "0.7.0" +dependencies = [ + "anyhow", + "hyperlight-common", + "hyperlight-guest-tracing", + "hyperlight-guest-tracing-macro", + "serde_json", +] + +[[package]] +name = "hyperlight-guest-bin" +version = "0.7.0" +dependencies = [ + "buddy_system_allocator", + "cc", + "cfg-if", + "glob", + "hyperlight-common", + "hyperlight-guest", + "hyperlight-guest-tracing", + "hyperlight-guest-tracing-macro", + "log", + "spin 0.10.0", +] + +[[package]] +name = "hyperlight-guest-tracing" +version = "0.7.0" +dependencies = [ + "hyperlight-common", + "spin 0.10.0", +] + +[[package]] +name = "hyperlight-guest-tracing-macro" +version = "0.7.0" +dependencies = [ + "hyperlight-guest-tracing", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", +] + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" diff --git a/src/tests/rust_guests/dummyguest/Cargo.toml b/src/tests/rust_guests/dummyguest/Cargo.toml index 619031cae..3de8389e9 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.toml +++ b/src/tests/rust_guests/dummyguest/Cargo.toml @@ -1,4 +1,15 @@ [package] name = "dummyguest" version = "0.4.0" -edition = "2021" \ No newline at end of file +edition = "2021" + + +[dependencies] +hyperlight-guest-bin = { path = "../../../hyperlight_guest_bin" } +hyperlight-common = { path = "../../../hyperlight_common", default-features = false } + +[features] +default = [] +trace_guest = ["hyperlight-guest-bin/trace_guest"] +unwind_guest = ["hyperlight-common/unwind_guest"] +mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] \ No newline at end of file diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index 62170dcbb..3cd9fe849 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -10,15 +10,15 @@ checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "buddy_system_allocator" @@ -31,18 +31,18 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.25" +version = "1.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" dependencies = [ "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "flatbuffers" @@ -76,6 +76,7 @@ version = "0.7.0" dependencies = [ "anyhow", "hyperlight-common", + "hyperlight-guest-tracing", "hyperlight-guest-tracing-macro", "serde_json", ] @@ -90,6 +91,7 @@ dependencies = [ "glob", "hyperlight-common", "hyperlight-guest", + "hyperlight-guest-tracing", "hyperlight-guest-tracing-macro", "log", "spin 0.10.0", @@ -121,9 +123,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -137,15 +139,15 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -208,9 +210,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" dependencies = [ "itoa", "memchr", diff --git a/src/tests/rust_guests/simpleguest/Cargo.toml b/src/tests/rust_guests/simpleguest/Cargo.toml index f2e75ee1c..515b618d5 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.toml +++ b/src/tests/rust_guests/simpleguest/Cargo.toml @@ -8,3 +8,10 @@ hyperlight-guest = { path = "../../../hyperlight_guest" } hyperlight-guest-bin = { path = "../../../hyperlight_guest_bin" } hyperlight-common = { path = "../../../hyperlight_common", default-features = false } log = {version = "0.4", default-features = false } + +[features] +default = [] +trace_guest = ["hyperlight-guest-bin/trace_guest"] +unwind_guest = ["hyperlight-common/unwind_guest"] +mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] + diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index bcb5b4813..ddd6f659e 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -219,6 +219,8 @@ version = "0.7.0" dependencies = [ "anyhow", "hyperlight-common", + "hyperlight-guest-tracing", + "hyperlight-guest-tracing-macro", "serde_json", ] @@ -232,10 +234,30 @@ dependencies = [ "glob", "hyperlight-common", "hyperlight-guest", + "hyperlight-guest-tracing", + "hyperlight-guest-tracing-macro", "log", "spin 0.10.0", ] +[[package]] +name = "hyperlight-guest-tracing" +version = "0.7.0" +dependencies = [ + "hyperlight-common", + "spin 0.10.0", +] + +[[package]] +name = "hyperlight-guest-tracing-macro" +version = "0.7.0" +dependencies = [ + "hyperlight-guest-tracing", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "indexmap" version = "2.9.0" diff --git a/src/tests/rust_guests/witguest/Cargo.toml b/src/tests/rust_guests/witguest/Cargo.toml index 63b38fc13..0be5aec00 100644 --- a/src/tests/rust_guests/witguest/Cargo.toml +++ b/src/tests/rust_guests/witguest/Cargo.toml @@ -7,4 +7,10 @@ edition = "2021" hyperlight-guest = { path = "../../../hyperlight_guest" } hyperlight-guest-bin = { path = "../../../hyperlight_guest_bin" } hyperlight-common = { path = "../../../hyperlight_common", default-features = false } -hyperlight-component-macro = { path = "../../../hyperlight_component_macro" } \ No newline at end of file +hyperlight-component-macro = { path = "../../../hyperlight_component_macro" } + +[features] +default = [] +trace_guest = ["hyperlight-guest-bin/trace_guest"] +unwind_guest = ["hyperlight-common/unwind_guest"] +mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] \ No newline at end of file From 593beccc8e926c79833fbc924d2805698b85c369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Tue, 8 Jul 2025 15:29:05 +0300 Subject: [PATCH 049/271] Update utility for dumping logs to support the traces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- src/trace_dump/main.rs | 84 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/src/trace_dump/main.rs b/src/trace_dump/main.rs index afd3f8b81..4f8416769 100644 --- a/src/trace_dump/main.rs +++ b/src/trace_dump/main.rs @@ -23,8 +23,21 @@ use std::rc::Rc; use std::sync::Mutex; use std::time::Duration; -use piet_common::{kurbo, Color, RenderContext, Text, TextLayout, TextLayoutBuilder}; +use piet_common::{Color, RenderContext, Text, TextLayout, TextLayoutBuilder, kurbo}; +fn read_u8_vec(inf: &mut File) -> Option> { + let len = read_u64(inf)?; + let mut vec = Vec::with_capacity(len as usize); + for _ in 0..len { + vec.push(read_u8(inf)?); + } + Some(vec) +} +fn read_u8(inf: &mut File) -> Option { + let mut bytes: [u8; 1] = [0; 1]; + inf.read_exact(&mut bytes).ok()?; + Some(u8::from_ne_bytes(bytes)) +} fn read_u128(inf: &mut File) -> Result { let mut bytes: [u8; 16] = [0; 16]; inf.read_exact(&mut bytes)?; @@ -92,6 +105,53 @@ fn dump_free( Some(()) } +fn dump_trace_record( + _state: &mut State, + _rs: &mut (), + indent: &mut u64, + now: Duration, + msg: Rc<[u8]>, +) -> Option<()> { + let msg = String::from_utf8_lossy(&msg); + + // Pretty-printing of trace records to show indentation based on the trace depth. + // Indentation is increased for messages starting with `>`, and decreased for messages starting + // with `<`. + // With the exception of `> halt`, which decreases the indent (because `> entrypoint` does not + // have a corresponding `< entrypoint`) + let msg = if msg.starts_with('>') { + if msg == "> halt" { + if *indent > 0 { + *indent -= 1; + } + } + let indent_str = " ".repeat(*indent as usize); + let msg = format!("{}{}", indent_str, &msg); + if msg != "> halt" { + // If the message is not `> halt`, increment the indent. + // This is to ensure that the next message is indented correctly. + *indent += 1; + } + + msg + } else if msg.starts_with('<') { + if *indent > 0 { + *indent -= 1; + } + let indent_str = " ".repeat(*indent as usize); + let msg = format!("{}{}", indent_str, msg); + + msg + } else { + let indent_str = " ".repeat(*indent as usize); + format!("{}{}", indent_str, msg) + }; + + println!("\n[{:9?}] {}", now, msg); + + Some(()) +} + // todo: this should use something more reasonable than a hash table // for each node. let's measure the out-degree and see if a small // array is better, to start. @@ -542,20 +602,33 @@ fn render_free( Some(()) } -fn read_file( +fn render_trace_record( + _state: &mut State, + _rs: &mut RenderState, + _indent: &mut u64, + _now: Duration, + _msg: Rc<[u8]>, +) -> Option<()> { + Some(()) +} + +fn read_file( state: &mut State, mut handle_state: S, handle_ident: I, handle_unwind: U, handle_alloc: A, handle_free: F, + handle_trace_record: T, ) -> Option<()> where I: Fn(&mut State, &mut S, Duration, blake3::Hash) -> Option<()>, U: Fn(&mut State, &mut S, Duration, Rc<[u64]>) -> Option<()>, A: Fn(&mut State, &mut S, Duration, u64, u64, Rc<[u64]>) -> Option<()>, F: Fn(&mut State, &mut S, Duration, u64, u64, Rc<[u64]>) -> Option<()>, + T: Fn(&mut State, &mut S, &mut u64, Duration, Rc<[u8]>) -> Option<()>, { + let mut indent = 0; loop { let time = match read_u128(&mut state.inf) { Ok(t) => t, @@ -600,6 +673,9 @@ where let trace = amt_trace.1.clone(); state.total -= amt; handle_free(state, &mut handle_state, now, ptr, amt, trace)?; + } else if frame_id == 4 { + let msg = read_u8_vec(&mut state.inf)?.into(); + handle_trace_record(state, &mut handle_state, &mut indent, now, msg)?; } else { return None; } @@ -699,6 +775,7 @@ fn spawn_render_thread( render_unwind, render_alloc, render_free, + render_trace_record, )?; bar_ffmpeg.wait().ok()?; flame_ffmpeg.wait().ok()?; @@ -755,6 +832,7 @@ fn dump_trace(mut state: State) { dump_unwind, dump_alloc, dump_free, + dump_trace_record, ); } @@ -771,6 +849,7 @@ fn plot_mem(args: Vec, mut state: State) { |_, _, _, _| Some(()), |_, _, _, _, _, _| Some(()), |_, _, _, _, _, _| Some(()), + |_, _, _, _, _| Some(()), ) { Some(()) => (), None => { @@ -810,6 +889,7 @@ fn plot_mem(args: Vec, mut state: State) { |_, _, _, _| Some(()), count_frame, count_frame, + |_, _, _, _, _| Some(()), ); if state.num_durations > 0 { (*jobs.lock().unwrap()).push((*start_duration.lock().unwrap(), state.max_duration)); From 26a895495f3ef432d8a3ef697e286ce54c05f57a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Tue, 8 Jul 2025 15:38:08 +0300 Subject: [PATCH 050/271] Add documentation on how to use the tracing functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- docs/hyperlight-metrics-logs-and-traces.md | 74 ++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/docs/hyperlight-metrics-logs-and-traces.md b/docs/hyperlight-metrics-logs-and-traces.md index 9158b43e2..7b90be74e 100644 --- a/docs/hyperlight-metrics-logs-and-traces.md +++ b/docs/hyperlight-metrics-logs-and-traces.md @@ -91,3 +91,77 @@ NOTE: when running this on windows that this is a linux container, so you will n ``` Once the container or the exe is running, the trace output can be viewed in the jaeger UI at [http://localhost:16686/search](http://localhost:16686/search). + +## Guest Tracing, Unwinding, and Memory Profiling + +Hyperlight provides advanced observability features for guest code running inside micro virtual machines. You can enable guest-side tracing, stack unwinding, and memory profiling using the `trace_guest`, `unwind_guest`, and `mem_profile` features. This section explains how to build, run, and inspect guest traces. + +The following features are available for guest tracing: +- `trace_guest`: Enables tracing for guest code, capturing function calls and execution time. +- `unwind_guest`: Enables stack unwinding for guest code, allowing you to capture stack traces. +- `mem_profile`: Enables memory profiling for guest code, capturing memory allocations and usage. + +### Building a Guest with Tracing Support + +To build a guest with tracing enabled, use the following commands: + +```bash +just build-rust-guests debug trace_guest +just move-rust-guests debug +``` + +This will build the guest binaries with the `trace_guest` feature enabled and move them to the appropriate location for use by the host. + +### Running a Hyperlight Example with Guest Tracing + +Once the guest is built, you can run a Hyperlight example with guest tracing enabled. For example: + +```bash +cargo run --example hello-world --features trace_guest +``` + +This will execute the `hello-world` example, loading the guest with tracing enabled. During execution, trace data will be collected and written to a file in the `trace` directory. + +### Inspecting Guest Trace Files + +To inspect the trace file generated by the guest, use the `trace_dump` crate. You will need the path to the guest symbols and the trace file. Run the following command: + +```bash +cargo run -p trace_dump list_frames +``` + +Replace `` with the path to the guest binary or symbol file, and `` with the path to the trace file in the `trace` directory. + +This command will list the stack frames and tracing information captured during guest execution, allowing you to analyze guest behavior, stack traces, and memory usage. + +#### Example + +```bash +cargo run -p trace_dump ./src/tests/rust_guests/bin/debug/simpleguest ./trace/.trace list_frames +``` + +You can use additional features such as `unwind_guest` and `mem_profile` by enabling them during the build and run steps. + +> **Note:** Make sure to follow the build and run steps in order, and ensure that the guest binaries are up to date before running the host example. + +## System Prerequisites for `trace_dump` + +To build and use the `trace_dump` crate and related guest tracing features, you must have the following system libraries and development tools installed on your system: + +- **glib-2.0** development files + - Fedora/RHEL/CentOS: + ```bash + sudo dnf install glib2-devel pkgconf-pkg-config + ``` +- **cairo** and **cairo-gobject** development files + - Fedora/RHEL/CentOS: + ```bash + sudo dnf install cairo-devel cairo-gobject-devel + ``` +- **pango** development files + - Fedora/RHEL/CentOS: + ```bash + sudo dnf install pango-devel + ``` + +These libraries are required by Rust crates such as `glib-sys`, `cairo-sys-rs`, and `pango-sys`, which are dependencies of the tracing and visualization tools. If you encounter errors about missing `.pc` files (e.g., `glib-2.0.pc`, `cairo.pc`, `pango.pc`), ensure the corresponding `-devel` packages are installed. From 172fcfa69b0f9064c7a0e48e512f8a86ae1fdbe1 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Wed, 23 Jul 2025 14:42:04 -0700 Subject: [PATCH 051/271] Make MultiUseSandbox::map_file_cow public (#725) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- src/hyperlight_host/src/sandbox/initialized_multi_use.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index e1d805d41..91722457b 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -164,7 +164,7 @@ impl MultiUseSandbox { /// Returns the length of the mapping #[allow(dead_code)] #[instrument(err(Debug), skip(self, _fp, _guest_base), parent = Span::current())] - pub(crate) fn map_file_cow(&mut self, _fp: &Path, _guest_base: u64) -> Result { + pub fn map_file_cow(&mut self, _fp: &Path, _guest_base: u64) -> Result { #[cfg(windows)] log_then_return!("mmap'ing a file into the guest is not yet supported on Windows"); #[cfg(unix)] From e08538ec8b3055420c343a510abfefb6252ebcfc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 04:18:07 +0000 Subject: [PATCH 052/271] Bump framehop from 0.13.3 to 0.14.0 (#728) Bumps [framehop](https://github.com/mstange/framehop) from 0.13.3 to 0.14.0. - [Commits](https://github.com/mstange/framehop/compare/v0.13.3...v0.14.0) --- updated-dependencies: - dependency-name: framehop dependency-version: 0.14.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 18 ++++++++++++++---- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0abb3a481..792c46a02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,7 +10,7 @@ checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "cpp_demangle", "fallible-iterator", - "gimli", + "gimli 0.31.1", "memmap2", "object", "rustc-demangle", @@ -875,14 +875,14 @@ dependencies = [ [[package]] name = "framehop" -version = "0.13.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a5a3f0acb82df800ca3aa50c0d60d286c5d13d4cfc3114b3a9663f13b032fe" +checksum = "f0586ca77af938ae3d66a103d3082ac997b432e82e65d644be6ad2fa340f582d" dependencies = [ "arrayvec", "cfg-if", "fallible-iterator", - "gimli", + "gimli 0.32.0", "macho-unwind-info", "pe-unwind-info", ] @@ -1057,6 +1057,16 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93563d740bc9ef04104f9ed6f86f1e3275c2cdafb95664e26584b9ca807a8ffe" +dependencies = [ + "fallible-iterator", + "stable_deref_trait", +] + [[package]] name = "gio" version = "0.16.7" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 23753330c..e9bf26a4f 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -28,7 +28,7 @@ rand = { version = "0.9" } cfg-if = { version = "1.0.1" } libc = { version = "0.2.174" } flatbuffers = "25.2.10" -framehop = { version = "0.13.1", optional = true } +framehop = { version = "0.14.0", optional = true } fallible-iterator = { version = "0.3.0", optional = true } blake3 = "1.8.2" page_size = "0.6.0" From d8ae0d66e38fe5d5c6e03a6dd7c7ac5740903d72 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 04:18:14 +0000 Subject: [PATCH 053/271] Bump piet-common from 0.6.2 to 0.7.0 (#726) Bumps [piet-common](https://github.com/linebender/piet) from 0.6.2 to 0.7.0. - [Release notes](https://github.com/linebender/piet/releases) - [Commits](https://github.com/linebender/piet/compare/v0.6.2...v0.7.0) --- updated-dependencies: - dependency-name: piet-common dependency-version: 0.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 306 ++++++++++++++++---------------------- src/trace_dump/Cargo.toml | 2 +- 2 files changed, 129 insertions(+), 179 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 792c46a02..4475a0e99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -145,9 +145,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "associative-cache" -version = "1.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46016233fc1bb55c23b856fe556b7db6ccd05119a0a392e04f0b3b7c79058f16" +checksum = "b993cd767a2bc7307dd87622311ca22c44329cc7a21366206bfa0896827b2bad" [[package]] name = "async-trait" @@ -157,7 +157,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -204,7 +204,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.104", + "syn", ] [[package]] @@ -305,23 +305,21 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cairo-rs" -version = "0.16.7" +version = "0.20.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3125b15ec28b84c238f6f476c6034016a5f6cc0221cb514ca46c532139fc97d" +checksum = "91e3bd0f4e25afa9cabc157908d14eeef9067d6448c49414d17b3fb55f0eadd0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "cairo-sys-rs", "glib", "libc", - "once_cell", - "thiserror 1.0.69", ] [[package]] name = "cairo-sys-rs" -version = "0.16.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c48f4af05fabdcfa9658178e1326efa061853f040ce7d72e33af6885196f421" +checksum = "059cc746549898cbfd9a47754288e5a958756650ef4652bbb6c5f71a6bda4f8b" dependencies = [ "glib-sys", "libc", @@ -341,14 +339,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "975982cdb7ad6a142be15bdf84aea7ec6a9e5d4d797c004d43185b24cfe4e684" dependencies = [ "clap", - "heck 0.5.0", + "heck", "indexmap", "log", "proc-macro2", "quote", "serde", "serde_json", - "syn 2.0.104", + "syn", "tempfile", "toml", ] @@ -375,9 +373,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.8" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +checksum = "0d0390889d58f934f01cd49736275b4c2da15bcfc328c78ff2349907e6cabf22" dependencies = [ "smallvec", "target-lexicon", @@ -488,9 +486,9 @@ checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "core-foundation" -version = "0.9.4" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -504,11 +502,11 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core-graphics" -version = "0.22.3" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "core-foundation", "core-graphics-types", "foreign-types", @@ -517,20 +515,20 @@ dependencies = [ [[package]] name = "core-graphics-types" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "core-foundation", "libc", ] [[package]] name = "core-text" -version = "19.2.0" +version = "21.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" +checksum = "a593227b66cbd4007b2a050dfdd9e1d1318311409c8d600dc82ba1b15ca9c130" dependencies = [ "core-foundation", "core-graphics", @@ -665,7 +663,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -707,7 +705,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -796,6 +794,15 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "euclid" +version = "0.22.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48" +dependencies = [ + "num-traits", +] + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -851,18 +858,30 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "foreign-types" -version = "0.3.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ + "foreign-types-macros", "foreign-types-shared", ] +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "foreign-types-shared" -version = "0.1.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] name = "form_urlencoded" @@ -943,7 +962,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -1069,11 +1088,10 @@ dependencies = [ [[package]] name = "gio" -version = "0.16.7" +version = "0.20.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1c84b4534a290a29160ef5c6eff2a9c95833111472e824fc5cb78b513dd092" +checksum = "8e27e276e7b6b8d50f6376ee7769a71133e80d093bdc363bd0af71664228b831" dependencies = [ - "bitflags 1.3.2", "futures-channel", "futures-core", "futures-io", @@ -1081,23 +1099,21 @@ dependencies = [ "gio-sys", "glib", "libc", - "once_cell", "pin-project-lite", "smallvec", - "thiserror 1.0.69", ] [[package]] name = "gio-sys" -version = "0.16.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9b693b8e39d042a95547fc258a7b07349b1f0b48f4b2fa3108ba3c51c0b5229" +checksum = "521e93a7e56fc89e84aea9a52cfc9436816a4b363b030260b699950ff1336c83" dependencies = [ "glib-sys", "gobject-sys", "libc", "system-deps", - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -1115,11 +1131,11 @@ dependencies = [ [[package]] name = "glib" -version = "0.16.9" +version = "0.20.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16aa2475c9debed5a32832cb5ff2af5a3f9e1ab9e69df58eaadc1ab2004d6eba" +checksum = "ffc4b6e352d4716d84d7dde562dd9aee2a7d48beb872dd9ece7f2d1515b2d683" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "futures-channel", "futures-core", "futures-executor", @@ -1130,31 +1146,28 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "once_cell", + "memchr", "smallvec", - "thiserror 1.0.69", ] [[package]] name = "glib-macros" -version = "0.16.8" +version = "0.20.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb1a9325847aa46f1e96ffea37611b9d51fc4827e67f79e7de502a297560a67b" +checksum = "e8084af62f09475a3f529b1629c10c429d7600ee1398ae12dd3bf175d74e7145" dependencies = [ - "anyhow", - "heck 0.4.1", + "heck", "proc-macro-crate", - "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "glib-sys" -version = "0.16.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61a4f46316d06bfa33a7ac22df6f0524c8be58e3db2d9ca99ccb1f357b62a65" +checksum = "8ab79e1ed126803a8fb827e3de0e2ff95191912b8db65cee467edb56fc4cc215" dependencies = [ "libc", "system-deps", @@ -1181,9 +1194,9 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.16.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3520bb9c07ae2a12c7f2fbb24d4efc11231c8146a86956413fb1a79bb760a0f1" +checksum = "ec9aca94bb73989e3cfdbf8f2e0f1f6da04db4d291c431f444838925c4c63eda" dependencies = [ "glib-sys", "libc", @@ -1221,12 +1234,6 @@ dependencies = [ "serde", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -1345,7 +1352,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.104", + "syn", "wasmparser", ] @@ -1358,7 +1365,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.104", + "syn", "wasmparser", ] @@ -1413,7 +1420,7 @@ dependencies = [ "hyperlight-guest-tracing", "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -1746,7 +1753,7 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -1771,11 +1778,13 @@ dependencies = [ [[package]] name = "kurbo" -version = "0.9.5" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd85a5776cd9500c2e2059c8c76c3b01528566b7fcbaf8098b55a33fc298849b" +checksum = "c62026ae44756f8a599ba21140f350303d4f08dcdcc71b5ad9c9bb8128c13c62" dependencies = [ "arrayvec", + "euclid", + "smallvec", ] [[package]] @@ -2159,7 +2168,7 @@ checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -2303,23 +2312,21 @@ dependencies = [ [[package]] name = "pango" -version = "0.16.5" +version = "0.20.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdff66b271861037b89d028656184059e03b0b6ccb36003820be19f7200b1e94" +checksum = "6576b311f6df659397043a5fa8a021da8f72e34af180b44f7d57348de691ab5c" dependencies = [ - "bitflags 1.3.2", "gio", "glib", "libc", - "once_cell", "pango-sys", ] [[package]] name = "pango-sys" -version = "0.16.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e134909a9a293e04d2cc31928aa95679c5e4df954d0b85483159bd20d8f047f" +checksum = "186909673fc09be354555c302c0b3dcf753cd9fa08dcb8077fa663c80fb243fa" dependencies = [ "glib-sys", "gobject-sys", @@ -2329,11 +2336,10 @@ dependencies = [ [[package]] name = "pangocairo" -version = "0.16.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ad2ec87789371b551fd2367c10aa37060412ffd3e60abd99491b21b93a3f9b" +checksum = "58890dc451db9964ac2d8874f903a4370a4b3932aa5281ff0c8d9810937ad84f" dependencies = [ - "bitflags 1.3.2", "cairo-rs", "glib", "libc", @@ -2343,9 +2349,9 @@ dependencies = [ [[package]] name = "pangocairo-sys" -version = "0.16.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848d2df9b7f1a8c7a19d994de443bcbe5d4382610ccb8e64247f932be74fcf76" +checksum = "b9952903f88aa93e2927e7bca2d1ebae64fc26545a9280b4ce6bddeda26b5c42" dependencies = [ "cairo-sys-rs", "glib-sys", @@ -2404,9 +2410,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "piet" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e381186490a3e2017a506d62b759ea8eaf4be14666b13ed53973e8ae193451b1" +checksum = "5139c7ec7de4cc21d108484af288b9c335b731194218023acf8b02874ed2b25e" dependencies = [ "kurbo", "unic-bidi", @@ -2414,9 +2420,9 @@ dependencies = [ [[package]] name = "piet-cairo" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc0b38ac300c79deb9bfc8c7f91a08f2b080338648f7202981094b22321bb9" +checksum = "9612bb8fdcd109ba7ce490777c79ef1bcbdb7f046b4a0e7fe449a42e51cda3e1" dependencies = [ "cairo-rs", "pango", @@ -2428,9 +2434,9 @@ dependencies = [ [[package]] name = "piet-common" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd8497cc0bcfecb1e14e027428c5e3eaf9af6e14761176e1212006d8bdba387" +checksum = "6ecd35fec05d4496878a0d9830a39b7031bb20dddd1a67dd36e8dda9b3111fd7" dependencies = [ "cairo-rs", "cairo-sys-rs", @@ -2448,9 +2454,9 @@ dependencies = [ [[package]] name = "piet-coregraphics" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a819b41d2ddb1d8abf3e45e49422f866cba281b4abb5e2fb948bba06e2c3d3f7" +checksum = "a71f2f06ad9048d617955763bb40856bee3dbb157c568d7d234280443cd6b5ae" dependencies = [ "associative-cache", "core-foundation", @@ -2463,9 +2469,9 @@ dependencies = [ [[package]] name = "piet-direct2d" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd00e91df4f987be40eb13042afe6ee9e54468466bdb7486390b40d4fef0993e" +checksum = "f0cd070348a4b8fddc486071c9fee2d98254ce7a4b9fdbf360c5dfee950d5866" dependencies = [ "associative-cache", "dwrote", @@ -2477,9 +2483,9 @@ dependencies = [ [[package]] name = "piet-web" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a560232a94e535979923d49062d1c6d5407b3804bcd0d0b4cb9e25a9b41db1e" +checksum = "471a2fe8003e860d6603fe32b47f77f0c3854f23a0068b47fe2d701b380b4d46" dependencies = [ "js-sys", "piet", @@ -2506,7 +2512,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -2614,41 +2620,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" dependencies = [ "proc-macro2", - "syn 2.0.104", + "syn", ] [[package]] name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", + "toml_edit", ] [[package]] @@ -2714,7 +2695,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -2958,7 +2939,7 @@ dependencies = [ "quote", "rust-embed-utils", "shellexpand", - "syn 2.0.104", + "syn", "walkdir", ] @@ -3087,7 +3068,7 @@ checksum = "22fc4f90c27b57691bbaf11d8ecc7cfbfe98a4da6dbe60226115d322aa80c06e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -3128,7 +3109,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -3186,7 +3167,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -3316,17 +3297,6 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.104" @@ -3355,17 +3325,17 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] name = "system-deps" -version = "6.2.2" +version = "7.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +checksum = "e4be53aa0cba896d2dc615bd42bbc130acdcffa239e0a2d965ea5b3b2a86ffdb" dependencies = [ "cfg-expr", - "heck 0.5.0", + "heck", "pkg-config", "toml", "version-compare", @@ -3373,9 +3343,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.16" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" [[package]] name = "tempfile" @@ -3425,7 +3395,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -3436,7 +3406,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -3496,7 +3466,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -3519,7 +3489,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.27", + "toml_edit", ] [[package]] @@ -3531,17 +3501,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow 0.5.40", -] - [[package]] name = "toml_edit" version = "0.22.27" @@ -3553,7 +3512,7 @@ dependencies = [ "serde_spanned", "toml_datetime", "toml_write", - "winnow 0.7.11", + "winnow", ] [[package]] @@ -3657,7 +3616,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -4022,7 +3981,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.104", + "syn", "wasm-bindgen-shared", ] @@ -4057,7 +4016,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4189,7 +4148,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -4200,7 +4159,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -4410,15 +4369,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - [[package]] name = "winnow" version = "0.7.11" @@ -4478,7 +4428,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", "synstructure", ] @@ -4509,7 +4459,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -4520,7 +4470,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -4540,7 +4490,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", "synstructure", ] @@ -4574,5 +4524,5 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] diff --git a/src/trace_dump/Cargo.toml b/src/trace_dump/Cargo.toml index 0149980e8..f53a46930 100644 --- a/src/trace_dump/Cargo.toml +++ b/src/trace_dump/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] addr2line = "0.24.2" -piet-common = { version = "0.6.2", features = [ "png" ] } +piet-common = { version = "0.7.0", features = [ "png" ] } blake3 = { version = "1.5.5" } [[bin]] From 4a8910c44bd34a815b2c3deb8ee6a52627352b96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 14:13:41 +0100 Subject: [PATCH 054/271] Bump addr2line from 0.24.2 to 0.25.0 (#727) Bumps [addr2line](https://github.com/gimli-rs/addr2line) from 0.24.2 to 0.25.0. - [Changelog](https://github.com/gimli-rs/addr2line/blob/master/CHANGELOG.md) - [Commits](https://github.com/gimli-rs/addr2line/compare/0.24.2...0.25.0) --- updated-dependencies: - dependency-name: addr2line dependency-version: 0.25.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 50 +++++++++++++++++++++------------------ src/trace_dump/Cargo.toml | 2 +- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4475a0e99..3f24c812a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,12 +7,21 @@ name = "addr2line" version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli 0.31.1", +] + +[[package]] +name = "addr2line" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9acbfca36652500c911ddb767ed433e3ed99b032b5d935be73c6923662db1d43" dependencies = [ "cpp_demangle", "fallible-iterator", - "gimli 0.31.1", + "gimli 0.32.0", "memmap2", - "object", + "object 0.37.1", "rustc-demangle", "smallvec", "typed-arena", @@ -172,11 +181,11 @@ version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ - "addr2line", + "addr2line 0.24.2", "cfg-if", "libc", "miniz_oxide", - "object", + "object 0.36.7", "rustc-demangle", "windows-targets 0.52.6", ] @@ -1071,10 +1080,6 @@ name = "gimli" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -dependencies = [ - "fallible-iterator", - "stable_deref_trait", -] [[package]] name = "gimli" @@ -2176,6 +2181,15 @@ name = "object" version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "object" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a" dependencies = [ "flate2", "memchr", @@ -3008,9 +3022,9 @@ dependencies = [ [[package]] name = "ruzstd" -version = "0.7.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad02996bfc73da3e301efe90b1837be9ed8f4a462b6ed410aa35d00381de89f" +checksum = "3640bec8aad418d7d03c72ea2de10d5c646a598f9883c7babc160d91e3c1b26c" dependencies = [ "twox-hash", ] @@ -3285,12 +3299,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "strsim" version = "0.11.1" @@ -3591,7 +3599,7 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" name = "trace_dump" version = "0.0.0" dependencies = [ - "addr2line", + "addr2line 0.25.0", "blake3", "piet-common", ] @@ -3752,13 +3760,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "twox-hash" -version = "1.6.3" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" -dependencies = [ - "cfg-if", - "static_assertions", -] +checksum = "8b907da542cbced5261bd3256de1b3a1bf340a3d37f93425a07362a1d687de56" [[package]] name = "typed-arena" diff --git a/src/trace_dump/Cargo.toml b/src/trace_dump/Cargo.toml index f53a46930..9f3b0cbe6 100644 --- a/src/trace_dump/Cargo.toml +++ b/src/trace_dump/Cargo.toml @@ -5,7 +5,7 @@ publish = false edition = "2021" [dependencies] -addr2line = "0.24.2" +addr2line = "0.25.0" piet-common = { version = "0.7.0", features = [ "png" ] } blake3 = { version = "1.5.5" } From 1a155a7afb9743f14c5e1c622af03afcc82f7a75 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 24 Jul 2025 14:36:52 -0700 Subject: [PATCH 055/271] Fix just clean command for Windows compatibility and missing directory handling (#730) Signed-off-by: Simon Davies Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: simongdavies <1397489+simongdavies@users.noreply.github.com> --- Justfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Justfile b/Justfile index 4f42efd2e..8a0d2bc2d 100644 --- a/Justfile +++ b/Justfile @@ -60,8 +60,8 @@ clean-rust: cd src/tests/rust_guests/simpleguest && cargo clean cd src/tests/rust_guests/dummyguest && cargo clean cd src/tests/rust_guests/callbackguest && cargo clean - cd src/tests/rust_guests/witguest && cargo clean - cd src/tests/rust_guests/witguest && rm -f interface.wasm + {{ if os() == "windows" { "cd src/tests/rust_guests/witguest -ErrorAction SilentlyContinue; cargo clean" } else { "[ -d src/tests/rust_guests/witguest ] && cd src/tests/rust_guests/witguest && cargo clean || true" } }} + {{ if os() == "windows" { "Remove-Item src/tests/rust_guests/witguest/interface.wasm -Force -ErrorAction SilentlyContinue" } else { "rm -f src/tests/rust_guests/witguest/interface.wasm" } }} git clean -fdx src/tests/c_guests/bin src/tests/rust_guests/bin ################ From 3d846f9691c69059c26683074525fb66d67759ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 04:17:57 +0000 Subject: [PATCH 056/271] Bump prettyplease from 0.2.35 to 0.2.36 (#733) Bumps [prettyplease](https://github.com/dtolnay/prettyplease) from 0.2.35 to 0.2.36. - [Release notes](https://github.com/dtolnay/prettyplease/releases) - [Commits](https://github.com/dtolnay/prettyplease/compare/0.2.35...0.2.36) --- updated-dependencies: - dependency-name: prettyplease dependency-version: 0.2.36 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3f24c812a..5d85796be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2629,9 +2629,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.35" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" +checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" dependencies = [ "proc-macro2", "syn", diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index 8c90c88b3..63761fab3 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -21,6 +21,6 @@ quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.95" } syn = { version = "2.0.104" } itertools = { version = "0.14.0" } -prettyplease = { version = "0.2.35" } +prettyplease = { version = "0.2.36" } hyperlight-component-util = { workspace = true } env_logger = { version = "0.11.8" } \ No newline at end of file diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index 57451dbcd..d028ec4ed 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -20,5 +20,5 @@ quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.95" } syn = { version = "2.0.104" } itertools = { version = "0.14.0" } -prettyplease = { version = "0.2.35" } +prettyplease = { version = "0.2.36" } log = { version = "0.4" } \ No newline at end of file From c3d13ca4b7e97b4c5d1f4463964bd92af064a6bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 04:24:27 +0000 Subject: [PATCH 057/271] Bump criterion from 0.6.0 to 0.7.0 (#737) Bumps [criterion](https://github.com/bheisler/criterion.rs) from 0.6.0 to 0.7.0. - [Changelog](https://github.com/bheisler/criterion.rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/bheisler/criterion.rs/compare/0.6.0...0.7.0) --- updated-dependencies: - dependency-name: criterion dependency-version: 0.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 19 +++++-------------- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d85796be..93bc18b3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -574,9 +574,9 @@ dependencies = [ [[package]] name = "criterion" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf7af66b0989381bd0be551bd7cc91912a655a58c6918420c9527b1fd8b4679" +checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" dependencies = [ "anes", "cast", @@ -597,12 +597,12 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" dependencies = [ "cast", - "itertools 0.10.5", + "itertools 0.13.0", ] [[package]] @@ -1704,15 +1704,6 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index e9bf26a4f..21c2c2cfe 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -102,7 +102,7 @@ opentelemetry-otlp = { version = "0.30.0", default-features = false, features = opentelemetry-semantic-conventions = "0.30" opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio"] } tokio = { version = "1.46.1", features = ["full"] } -criterion = "0.6.0" +criterion = "0.7.0" tracing-chrome = "0.7.2" metrics-util = "0.20.0" metrics-exporter-prometheus = { version = "0.17.2", default-features = false } From 636596232aad3f343257e123f951ce3566ccec8c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 08:56:58 +0000 Subject: [PATCH 058/271] Bump tokio from 1.46.1 to 1.47.0 (#736) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.46.1 to 1.47.0. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.46.1...tokio-1.47.0) --- updated-dependencies: - dependency-name: tokio dependency-version: 1.47.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 20 +++++++++++++++----- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 93bc18b3e..ced25e780 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1328,7 +1328,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -3266,6 +3266,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "spin" version = "0.9.8" @@ -3439,9 +3449,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.46.1" +version = "1.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" +checksum = "43864ed400b6043a4757a25c7a64a8efde741aed79a056a2fb348a406701bb35" dependencies = [ "backtrace", "bytes", @@ -3452,9 +3462,9 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "slab", - "socket2", + "socket2 0.6.0", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 21c2c2cfe..eeba95e97 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -101,7 +101,7 @@ opentelemetry = "0.30.0" opentelemetry-otlp = { version = "0.30.0", default-features = false, features = ["http-proto", "reqwest-blocking-client"] } opentelemetry-semantic-conventions = "0.30" opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio"] } -tokio = { version = "1.46.1", features = ["full"] } +tokio = { version = "1.47.0", features = ["full"] } criterion = "0.7.0" tracing-chrome = "0.7.2" metrics-util = "0.20.0" From 6264bb0c5bdd3425fd00278b945930f6fb21c265 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Jul 2025 11:41:20 +0000 Subject: [PATCH 059/271] Bump wasmparser from 0.235.0 to 0.236.0 (#738) Bumps [wasmparser](https://github.com/bytecodealliance/wasm-tools) from 0.235.0 to 0.236.0. - [Release notes](https://github.com/bytecodealliance/wasm-tools/releases) - [Commits](https://github.com/bytecodealliance/wasm-tools/commits) --- updated-dependencies: - dependency-name: wasmparser dependency-version: 0.236.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ced25e780..15c2068da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4037,9 +4037,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.235.0" +version = "0.236.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917" +checksum = "16d1eee846a705f6f3cb9d7b9f79b54583810f1fb57a1e3aea76d1742db2e3d2" dependencies = [ "bitflags 2.9.1", "hashbrown", diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index 63761fab3..204127cf6 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -16,7 +16,7 @@ name = "hyperlight_component_macro" proc-macro = true [dependencies] -wasmparser = { version = "0.235.0" } +wasmparser = { version = "0.236.0" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.95" } syn = { version = "2.0.104" } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index d028ec4ed..1c270a18a 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -15,7 +15,7 @@ Shared implementation for the procedural macros that generate Hyperlight host an name = "hyperlight_component_util" [dependencies] -wasmparser = { version = "0.235.0" } +wasmparser = { version = "0.236.0" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.95" } syn = { version = "2.0.104" } From e9d9e18e9201b4b9eda931465d02f113071b6f6f Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Wed, 30 Jul 2025 08:46:23 +0000 Subject: [PATCH 060/271] Removed the OutBHandler and MemAccessHandler abstractions and related implementations. (#732) * Update hypervisor trait and handler to remove outb and mem access wrappers and to remove sync requirement Signed-off-by: Simon Davies * Remove the outbhandler and memaccesshandler traits and types Signed-off-by: Simon Davies * Remove mem_access_handler_wrapper function Signed-off-by: Simon Davies * Remove outb_handler_wrapper function Signed-off-by: Simon Davies * Remove outbhandler and memaccesshandler traits from MultiUseSandbox Signed-off-by: Simon Davies * Remove OutBhandler and MemAccessHandler traits from evolve and provide new values to vm.initialise Signed-off-by: Simon Davies --------- Signed-off-by: Simon Davies --- .../src/hypervisor/handlers.rs | 110 +----------------- .../src/hypervisor/hyperv_linux.rs | 86 ++++++++++---- .../src/hypervisor/hyperv_windows.rs | 94 ++++++++++----- src/hyperlight_host/src/hypervisor/kvm.rs | 88 ++++++++++---- src/hyperlight_host/src/hypervisor/mod.rs | 101 +++++++--------- .../src/sandbox/initialized_multi_use.rs | 10 +- src/hyperlight_host/src/sandbox/mem_access.rs | 16 +-- src/hyperlight_host/src/sandbox/outb.rs | 34 +----- .../src/sandbox/uninitialized_evolve.rs | 17 +-- 9 files changed, 244 insertions(+), 312 deletions(-) diff --git a/src/hyperlight_host/src/hypervisor/handlers.rs b/src/hyperlight_host/src/hypervisor/handlers.rs index 186c030e2..842b44a37 100644 --- a/src/hyperlight_host/src/hypervisor/handlers.rs +++ b/src/hyperlight_host/src/hypervisor/handlers.rs @@ -16,118 +16,11 @@ limitations under the License. use std::sync::{Arc, Mutex}; -use tracing::{Span, instrument}; - -#[cfg(feature = "trace_guest")] -use super::Hypervisor; -use crate::{Result, new_error}; - -/// The trait representing custom logic to handle the case when -/// a Hypervisor's virtual CPU (vCPU) informs Hyperlight the guest -/// has initiated an outb operation. -pub(crate) trait OutBHandlerCaller: Sync + Send { - /// Function that gets called when an outb operation has occurred. - fn call( - &mut self, - #[cfg(feature = "trace_guest")] hv: &mut dyn Hypervisor, - port: u16, - payload: u32, - ) -> Result<()>; -} - -/// A convenient type representing a common way `OutBHandler` implementations -/// are passed as parameters to functions -/// -/// Note: This needs to be wrapped in a Mutex to be able to grab a mutable -/// reference to the underlying data (i.e., handle_outb in `Sandbox` takes -/// a &mut self). -pub(crate) type OutBHandlerWrapper = Arc>; - -#[cfg(feature = "trace_guest")] -pub(crate) type OutBHandlerFunction = - Box Result<()> + Send>; -#[cfg(not(feature = "trace_guest"))] -pub(crate) type OutBHandlerFunction = Box Result<()> + Send>; - -/// A `OutBHandler` implementation using a `OutBHandlerFunction` -/// -/// Note: This handler must live no longer than the `Sandbox` to which it belongs -pub(crate) struct OutBHandler(Arc>); - -impl From for OutBHandler { - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - fn from(func: OutBHandlerFunction) -> Self { - Self(Arc::new(Mutex::new(func))) - } -} - -impl OutBHandlerCaller for OutBHandler { - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - fn call( - &mut self, - #[cfg(feature = "trace_guest")] hv: &mut dyn Hypervisor, - port: u16, - payload: u32, - ) -> Result<()> { - let mut func = self - .0 - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?; - func( - #[cfg(feature = "trace_guest")] - hv, - port, - payload, - ) - } -} - -/// The trait representing custom logic to handle the case when -/// a Hypervisor's virtual CPU (vCPU) informs Hyperlight a memory access -/// outside the designated address space has occurred. -pub trait MemAccessHandlerCaller: Send { - /// Function that gets called when unexpected memory access has occurred. - fn call(&mut self) -> Result<()>; -} - -/// A convenient type representing a common way `MemAccessHandler` implementations -/// are passed as parameters to functions -/// -/// Note: This needs to be wrapped in a Mutex to be able to grab a mutable -/// reference to the underlying data (i.e., handle_mmio_exit in `Sandbox` takes -/// a &mut self). -pub type MemAccessHandlerWrapper = Arc>; - -pub(crate) type MemAccessHandlerFunction = Box Result<()> + Send>; - -/// A `MemAccessHandler` implementation using `MemAccessHandlerFunction`. -/// -/// Note: This handler must live for as long as its Sandbox or for -/// static in the case of its C API usage. -pub(crate) struct MemAccessHandler(Arc>); - -impl From for MemAccessHandler { - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - fn from(func: MemAccessHandlerFunction) -> Self { - Self(Arc::new(Mutex::new(func))) - } -} - -impl MemAccessHandlerCaller for MemAccessHandler { - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - fn call(&mut self) -> Result<()> { - let mut func = self - .0 - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?; - func() - } -} +use crate::Result; /// The trait representing custom logic to handle the case when /// a Hypervisor's virtual CPU (vCPU) informs Hyperlight a debug memory access /// has been requested. -#[cfg(gdb)] pub trait DbgMemAccessHandlerCaller: Send { /// Function that gets called when a read is requested. fn read(&mut self, addr: usize, data: &mut [u8]) -> Result<()>; @@ -143,5 +36,4 @@ pub trait DbgMemAccessHandlerCaller: Send { /// /// Note: This needs to be wrapped in a Mutex to be able to grab a mutable /// reference to the underlying data -#[cfg(gdb)] pub type DbgMemAccessHandlerWrapper = Arc>; diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 65f8910be..df3073a09 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -25,8 +25,8 @@ extern crate mshv_bindings3 as mshv_bindings; extern crate mshv_ioctls3 as mshv_ioctls; use std::fmt::{Debug, Formatter}; -use std::sync::Arc; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::{Arc, Mutex}; use log::{LevelFilter, error}; #[cfg(mshv2)] @@ -67,7 +67,6 @@ use super::gdb::{ }; #[cfg(gdb)] use super::handlers::DbgMemAccessHandlerWrapper; -use super::handlers::{MemAccessHandlerWrapper, OutBHandlerWrapper}; #[cfg(feature = "init-paging")] use super::{ CR0_AM, CR0_ET, CR0_MP, CR0_NE, CR0_PE, CR0_PG, CR0_WP, CR4_OSFXSR, CR4_OSXMMEXCPT, CR4_PAE, @@ -78,9 +77,13 @@ use super::{HyperlightExit, Hypervisor, InterruptHandle, LinuxInterruptHandle, V use crate::HyperlightError; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::{GuestPtr, RawPtr}; +use crate::mem::shared_mem::HostSharedMemory; use crate::sandbox::SandboxConfiguration; #[cfg(feature = "trace_guest")] use crate::sandbox::TraceInfo; +use crate::sandbox::host_funcs::FunctionRegistry; +use crate::sandbox::mem_mgr::MemMgrWrapper; +use crate::sandbox::outb::handle_outb; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; use crate::{Result, log_then_return, new_error}; @@ -313,7 +316,8 @@ pub(crate) struct HypervLinuxDriver { mem_regions: Vec, orig_rsp: GuestPtr, interrupt_handle: Arc, - + mem_mgr: Option>, + host_funcs: Option>>, #[cfg(gdb)] debug: Option, #[cfg(gdb)] @@ -447,6 +451,8 @@ impl HypervLinuxDriver { entrypoint: entrypoint_ptr.absolute()?, orig_rsp: rsp_ptr, interrupt_handle: interrupt_handle.clone(), + mem_mgr: None, + host_funcs: None, #[cfg(gdb)] debug, #[cfg(gdb)] @@ -574,11 +580,13 @@ impl Hypervisor for HypervLinuxDriver { peb_addr: RawPtr, seed: u64, page_size: u32, - outb_hdl: OutBHandlerWrapper, - mem_access_hdl: MemAccessHandlerWrapper, + mem_mgr: MemMgrWrapper, + host_funcs: Arc>, max_guest_log_level: Option, #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, ) -> Result<()> { + self.mem_mgr = Some(mem_mgr); + self.host_funcs = Some(host_funcs); self.page_size = page_size as usize; let max_guest_log_level: u64 = match max_guest_log_level { @@ -601,13 +609,22 @@ impl Hypervisor for HypervLinuxDriver { }; self.vcpu_fd.set_regs(®s)?; - VirtualCPU::run( + // Extract mem_mgr to avoid borrowing conflicts + let mem_mgr = self + .mem_mgr + .take() + .ok_or_else(|| new_error!("mem_mgr should be initialized"))?; + + let result = VirtualCPU::run( self.as_mut_hypervisor(), - outb_hdl, - mem_access_hdl, + &mem_mgr, #[cfg(gdb)] dbg_mem_access_fn, - )?; + ); + + // Put mem_mgr back + self.mem_mgr = Some(mem_mgr); + result?; Ok(()) } @@ -647,8 +664,7 @@ impl Hypervisor for HypervLinuxDriver { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - outb_handle_fn: OutBHandlerWrapper, - mem_access_fn: MemAccessHandlerWrapper, + mem_mgr: &MemMgrWrapper, #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, ) -> Result<()> { // Reset general purpose registers, then set RIP and RSP @@ -672,8 +688,7 @@ impl Hypervisor for HypervLinuxDriver { // run VirtualCPU::run( self.as_mut_hypervisor(), - outb_handle_fn, - mem_access_fn, + mem_mgr, #[cfg(gdb)] dbg_mem_access_fn, )?; @@ -688,22 +703,47 @@ impl Hypervisor for HypervLinuxDriver { data: Vec, rip: u64, instruction_length: u64, - outb_handle_fn: OutBHandlerWrapper, ) -> Result<()> { let mut padded = [0u8; 4]; let copy_len = data.len().min(4); padded[..copy_len].copy_from_slice(&data[..copy_len]); let val = u32::from_le_bytes(padded); - outb_handle_fn - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .call( - #[cfg(feature = "trace_guest")] - self, - port, - val, - )?; + #[cfg(feature = "trace_guest")] + { + // We need to handle the borrow checker issue where we need both: + // - &mut MemMgrWrapper (from self.mem_mgr.as_mut()) + // - &mut dyn Hypervisor (from self) + // We'll use a temporary approach to extract the mem_mgr temporarily + let mem_mgr_option = self.mem_mgr.take(); + let mut mem_mgr = mem_mgr_option + .ok_or_else(|| new_error!("mem_mgr should be initialized before handling IO"))?; + let host_funcs = self + .host_funcs + .as_ref() + .ok_or_else(|| new_error!("host_funcs should be initialized before handling IO"))? + .clone(); + + handle_outb(&mut mem_mgr, host_funcs, self, port, val)?; + + // Put the mem_mgr back + self.mem_mgr = Some(mem_mgr); + } + + #[cfg(not(feature = "trace_guest"))] + { + let mem_mgr = self + .mem_mgr + .as_mut() + .ok_or_else(|| new_error!("mem_mgr should be initialized before handling IO"))?; + let host_funcs = self + .host_funcs + .as_ref() + .ok_or_else(|| new_error!("host_funcs should be initialized before handling IO"))? + .clone(); + + handle_outb(mem_mgr, host_funcs, port, val)?; + } // update rip self.vcpu_fd.set_reg(&[hv_register_assoc { diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index 01c2b0560..595372306 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -17,8 +17,8 @@ limitations under the License. use std::fmt; use std::fmt::{Debug, Formatter}; use std::string::String; -use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex}; use log::LevelFilter; use tracing::{Span, instrument}; @@ -41,13 +41,11 @@ use { super::handlers::DbgMemAccessHandlerWrapper, crate::HyperlightError, crate::hypervisor::handlers::DbgMemAccessHandlerCaller, - std::sync::Mutex, }; #[cfg(feature = "trace_guest")] use super::TraceRegister; use super::fpu::{FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT}; -use super::handlers::{MemAccessHandlerWrapper, OutBHandlerWrapper}; use super::surrogate_process::SurrogateProcess; use super::surrogate_process_manager::*; use super::windows_hypervisor_platform::{VMPartition, VMProcessor}; @@ -62,8 +60,12 @@ use crate::hypervisor::fpu::FP_CONTROL_WORD_DEFAULT; use crate::hypervisor::wrappers::WHvGeneralRegisters; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::{GuestPtr, RawPtr}; +use crate::mem::shared_mem::HostSharedMemory; #[cfg(feature = "trace_guest")] use crate::sandbox::TraceInfo; +use crate::sandbox::host_funcs::FunctionRegistry; +use crate::sandbox::mem_mgr::MemMgrWrapper; +use crate::sandbox::outb::handle_outb; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; use crate::{Result, debug, log_then_return, new_error}; @@ -75,9 +77,9 @@ mod debug { use windows::Win32::System::Hypervisor::WHV_VP_EXCEPTION_CONTEXT; use super::{HypervWindowsDriver, *}; + use crate::Result; use crate::hypervisor::gdb::{DebugMsg, DebugResponse, VcpuStopReason, X86_64Regs}; use crate::hypervisor::handlers::DbgMemAccessHandlerCaller; - use crate::{Result, new_error}; impl HypervWindowsDriver { /// Resets the debug information to disable debugging @@ -281,6 +283,8 @@ pub(crate) struct HypervWindowsDriver { orig_rsp: GuestPtr, mem_regions: Vec, interrupt_handle: Arc, + mem_mgr: Option>, + host_funcs: Option>>, #[cfg(gdb)] debug: Option, #[cfg(gdb)] @@ -291,13 +295,12 @@ pub(crate) struct HypervWindowsDriver { #[allow(dead_code)] trace_info: TraceInfo, } -/* This does not automatically impl Send/Sync because the host +/* This does not automatically impl Send because the host * address of the shared memory region is a raw pointer, which are - * marked as !Send and !Sync. However, the access patterns used + * marked as !Send (and !Sync). However, the access patterns used * here are safe. */ unsafe impl Send for HypervWindowsDriver {} -unsafe impl Sync for HypervWindowsDriver {} impl HypervWindowsDriver { #[allow(clippy::too_many_arguments)] @@ -357,6 +360,8 @@ impl HypervWindowsDriver { orig_rsp: GuestPtr::try_from(RawPtr::from(rsp))?, mem_regions, interrupt_handle: interrupt_handle.clone(), + mem_mgr: None, + host_funcs: None, #[cfg(gdb)] debug, #[cfg(gdb)] @@ -590,11 +595,14 @@ impl Hypervisor for HypervWindowsDriver { peb_address: RawPtr, seed: u64, page_size: u32, - outb_hdl: OutBHandlerWrapper, - mem_access_hdl: MemAccessHandlerWrapper, + mem_mgr: MemMgrWrapper, + host_funcs: Arc>, max_guest_log_level: Option, #[cfg(gdb)] dbg_mem_access_hdl: DbgMemAccessHandlerWrapper, ) -> Result<()> { + self.mem_mgr = Some(mem_mgr); + self.host_funcs = Some(host_funcs); + let max_guest_log_level: u64 = match max_guest_log_level { Some(level) => level as u64, None => self.get_max_log_level().into(), @@ -615,13 +623,22 @@ impl Hypervisor for HypervWindowsDriver { }; self.processor.set_general_purpose_registers(®s)?; - VirtualCPU::run( + // Extract mem_mgr to avoid borrowing conflicts + let mem_mgr = self + .mem_mgr + .take() + .ok_or_else(|| new_error!("mem_mgr should be initialized"))?; + + let result = VirtualCPU::run( self.as_mut_hypervisor(), - outb_hdl, - mem_access_hdl, + &mem_mgr, #[cfg(gdb)] dbg_mem_access_hdl, - )?; + ); + + // Put mem_mgr back + self.mem_mgr = Some(mem_mgr); + result?; Ok(()) } @@ -645,8 +662,7 @@ impl Hypervisor for HypervWindowsDriver { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - outb_hdl: OutBHandlerWrapper, - mem_access_hdl: MemAccessHandlerWrapper, + mem_mgr: &MemMgrWrapper, #[cfg(gdb)] dbg_mem_access_hdl: DbgMemAccessHandlerWrapper, ) -> Result<()> { // Reset general purpose registers, then set RIP and RSP @@ -668,8 +684,7 @@ impl Hypervisor for HypervWindowsDriver { VirtualCPU::run( self.as_mut_hypervisor(), - outb_hdl, - mem_access_hdl, + mem_mgr, #[cfg(gdb)] dbg_mem_access_hdl, )?; @@ -684,22 +699,47 @@ impl Hypervisor for HypervWindowsDriver { data: Vec, rip: u64, instruction_length: u64, - outb_handle_fn: OutBHandlerWrapper, ) -> Result<()> { let mut padded = [0u8; 4]; let copy_len = data.len().min(4); padded[..copy_len].copy_from_slice(&data[..copy_len]); let val = u32::from_le_bytes(padded); - outb_handle_fn - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .call( - #[cfg(feature = "trace_guest")] - self, - port, - val, - )?; + #[cfg(feature = "trace_guest")] + { + // We need to handle the borrow checker issue where we need both: + // - &mut MemMgrWrapper (from self.mem_mgr.as_mut()) + // - &mut dyn Hypervisor (from self) + // We'll use a temporary approach to extract the mem_mgr temporarily + let mem_mgr_option = self.mem_mgr.take(); + let mut mem_mgr = mem_mgr_option + .ok_or_else(|| new_error!("mem_mgr should be initialized before handling IO"))?; + let host_funcs = self + .host_funcs + .as_ref() + .ok_or_else(|| new_error!("host_funcs should be initialized before handling IO"))? + .clone(); + + handle_outb(&mut mem_mgr, host_funcs, self, port, val)?; + + // Put the mem_mgr back + self.mem_mgr = Some(mem_mgr); + } + + #[cfg(not(feature = "trace_guest"))] + { + let mem_mgr = self + .mem_mgr + .as_mut() + .ok_or_else(|| new_error!("mem_mgr should be initialized before handling IO"))?; + let host_funcs = self + .host_funcs + .as_ref() + .ok_or_else(|| new_error!("host_funcs should be initialized before handling IO"))? + .clone(); + + handle_outb(mem_mgr, host_funcs, port, val)?; + } let mut regs = self.processor.get_regs()?; regs.rip = rip + instruction_length; diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index 188c27ed7..761020c50 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -16,10 +16,8 @@ limitations under the License. use std::convert::TryFrom; use std::fmt::Debug; -use std::sync::Arc; -#[cfg(gdb)] -use std::sync::Mutex; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::{Arc, Mutex}; use kvm_bindings::{kvm_fpu, kvm_regs, kvm_userspace_memory_region}; use kvm_ioctls::Cap::UserMemory; @@ -36,7 +34,6 @@ use super::fpu::{FP_CONTROL_WORD_DEFAULT, FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT}; use super::gdb::{DebugCommChannel, DebugMsg, DebugResponse, GuestDebug, KvmDebug, VcpuStopReason}; #[cfg(gdb)] use super::handlers::DbgMemAccessHandlerWrapper; -use super::handlers::{MemAccessHandlerWrapper, OutBHandlerWrapper}; #[cfg(feature = "init-paging")] use super::{ CR0_AM, CR0_ET, CR0_MP, CR0_NE, CR0_PE, CR0_PG, CR0_WP, CR4_OSFXSR, CR4_OSXMMEXCPT, CR4_PAE, @@ -47,9 +44,13 @@ use super::{HyperlightExit, Hypervisor, InterruptHandle, LinuxInterruptHandle, V use crate::HyperlightError; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::{GuestPtr, RawPtr}; +use crate::mem::shared_mem::HostSharedMemory; use crate::sandbox::SandboxConfiguration; #[cfg(feature = "trace_guest")] use crate::sandbox::TraceInfo; +use crate::sandbox::host_funcs::FunctionRegistry; +use crate::sandbox::mem_mgr::MemMgrWrapper; +use crate::sandbox::outb::handle_outb; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; use crate::{Result, log_then_return, new_error}; @@ -295,7 +296,8 @@ pub(crate) struct KVMDriver { orig_rsp: GuestPtr, mem_regions: Vec, interrupt_handle: Arc, - + mem_mgr: Option>, + host_funcs: Option>>, #[cfg(gdb)] debug: Option, #[cfg(gdb)] @@ -384,6 +386,8 @@ impl KVMDriver { orig_rsp: rsp_gp, mem_regions, interrupt_handle: interrupt_handle.clone(), + mem_mgr: None, + host_funcs: None, #[cfg(gdb)] debug, #[cfg(gdb)] @@ -460,11 +464,13 @@ impl Hypervisor for KVMDriver { peb_addr: RawPtr, seed: u64, page_size: u32, - outb_hdl: OutBHandlerWrapper, - mem_access_hdl: MemAccessHandlerWrapper, + mem_mgr: MemMgrWrapper, + host_funcs: Arc>, max_guest_log_level: Option, #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, ) -> Result<()> { + self.mem_mgr = Some(mem_mgr); + self.host_funcs = Some(host_funcs); self.page_size = page_size as usize; let max_guest_log_level: u64 = match max_guest_log_level { @@ -486,13 +492,22 @@ impl Hypervisor for KVMDriver { }; self.vcpu_fd.set_regs(®s)?; - VirtualCPU::run( + // Extract mem_mgr to avoid borrowing conflicts + let mem_mgr = self + .mem_mgr + .take() + .ok_or_else(|| new_error!("mem_mgr should be initialized"))?; + + let result = VirtualCPU::run( self.as_mut_hypervisor(), - outb_hdl, - mem_access_hdl, + &mem_mgr, #[cfg(gdb)] dbg_mem_access_fn, - )?; + ); + + // Put mem_mgr back + self.mem_mgr = Some(mem_mgr); + result?; Ok(()) } @@ -540,8 +555,7 @@ impl Hypervisor for KVMDriver { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - outb_handle_fn: OutBHandlerWrapper, - mem_access_fn: MemAccessHandlerWrapper, + mem_mgr: &MemMgrWrapper, #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, ) -> Result<()> { // Reset general purpose registers, then set RIP and RSP @@ -564,8 +578,7 @@ impl Hypervisor for KVMDriver { // run VirtualCPU::run( self.as_mut_hypervisor(), - outb_handle_fn, - mem_access_fn, + mem_mgr, #[cfg(gdb)] dbg_mem_access_fn, )?; @@ -580,7 +593,6 @@ impl Hypervisor for KVMDriver { data: Vec, _rip: u64, _instruction_length: u64, - outb_handle_fn: OutBHandlerWrapper, ) -> Result<()> { // KVM does not need RIP or instruction length, as it automatically sets the RIP @@ -595,15 +607,41 @@ impl Hypervisor for KVMDriver { padded[..copy_len].copy_from_slice(&data[..copy_len]); let value = u32::from_le_bytes(padded); - outb_handle_fn - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .call( - #[cfg(feature = "trace_guest")] - self, - port, - value, - )?; + #[cfg(feature = "trace_guest")] + { + // We need to handle the borrow checker issue where we need both: + // - &mut MemMgrWrapper (from self.mem_mgr.as_mut()) + // - &mut dyn Hypervisor (from self) + // We'll use a temporary approach to extract the mem_mgr temporarily + let mem_mgr_option = self.mem_mgr.take(); + let mut mem_mgr = + mem_mgr_option.ok_or_else(|| new_error!("mem_mgr not initialized"))?; + let host_funcs = self + .host_funcs + .as_ref() + .ok_or_else(|| new_error!("host_funcs not initialized"))? + .clone(); + + handle_outb(&mut mem_mgr, host_funcs, self, port, value)?; + + // Put the mem_mgr back + self.mem_mgr = Some(mem_mgr); + } + + #[cfg(not(feature = "trace_guest"))] + { + let mem_mgr = self + .mem_mgr + .as_mut() + .ok_or_else(|| new_error!("mem_mgr not initialized"))?; + let host_funcs = self + .host_funcs + .as_ref() + .ok_or_else(|| new_error!("host_funcs not initialized"))? + .clone(); + + handle_outb(mem_mgr, host_funcs, port, value)?; + } } Ok(()) diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index a5332d9be..e34175ba0 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -22,12 +22,13 @@ use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::metrics::METRIC_GUEST_CANCELLATION; #[cfg(feature = "trace_guest")] use crate::sandbox::TraceInfo; -use crate::{HyperlightError, Result, log_then_return, new_error}; +use crate::{HyperlightError, Result, log_then_return}; /// Util for handling x87 fpu state #[cfg(any(kvm, mshv, target_os = "windows"))] pub mod fpu; /// Handlers for Hypervisor custom logic +#[cfg(gdb)] pub mod handlers; /// HyperV-on-linux functionality #[cfg(mshv)] @@ -72,10 +73,11 @@ use gdb::VcpuStopReason; #[cfg(gdb)] use self::handlers::{DbgMemAccessHandlerCaller, DbgMemAccessHandlerWrapper}; -use self::handlers::{ - MemAccessHandlerCaller, MemAccessHandlerWrapper, OutBHandlerCaller, OutBHandlerWrapper, -}; use crate::mem::ptr::RawPtr; +use crate::mem::shared_mem::HostSharedMemory; +use crate::sandbox::host_funcs::FunctionRegistry; +use crate::sandbox::mem_access::handle_mem_access; +use crate::sandbox::mem_mgr::MemMgrWrapper; cfg_if::cfg_if! { if #[cfg(feature = "init-paging")] { @@ -134,7 +136,7 @@ pub enum TraceRegister { } /// A common set of hypervisor functionality -pub(crate) trait Hypervisor: Debug + Sync + Send { +pub(crate) trait Hypervisor: Debug + Send { /// Initialise the internally stored vCPU with the given PEB address and /// random number seed, then run it until a HLT instruction. #[allow(clippy::too_many_arguments)] @@ -143,8 +145,8 @@ pub(crate) trait Hypervisor: Debug + Sync + Send { peb_addr: RawPtr, seed: u64, page_size: u32, - outb_handle_fn: OutBHandlerWrapper, - mem_access_fn: MemAccessHandlerWrapper, + mem_mgr: MemMgrWrapper, + host_funcs: Arc>, guest_max_log_level: Option, #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, ) -> Result<()>; @@ -168,8 +170,7 @@ pub(crate) trait Hypervisor: Debug + Sync + Send { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - outb_handle_fn: OutBHandlerWrapper, - mem_access_fn: MemAccessHandlerWrapper, + mem_mgr: &MemMgrWrapper, #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, ) -> Result<()>; @@ -180,7 +181,6 @@ pub(crate) trait Hypervisor: Debug + Sync + Send { data: Vec, rip: u64, instruction_length: u64, - outb_handle_fn: OutBHandlerWrapper, ) -> Result<()>; /// Run the vCPU @@ -289,8 +289,7 @@ impl VirtualCPU { #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] pub(crate) fn run( hv: &mut dyn Hypervisor, - outb_handle_fn: Arc>, - mem_access_fn: Arc>, + mem_mgr: &MemMgrWrapper, #[cfg(gdb)] dbg_mem_access_fn: Arc>, ) -> Result<()> { loop { @@ -306,17 +305,13 @@ impl VirtualCPU { break; } Ok(HyperlightExit::IoOut(port, data, rip, instruction_length)) => { - hv.handle_io(port, data, rip, instruction_length, outb_handle_fn.clone())? + hv.handle_io(port, data, rip, instruction_length)? } Ok(HyperlightExit::Mmio(addr)) => { #[cfg(crashdump)] crashdump::generate_crashdump(hv)?; - mem_access_fn - .clone() - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .call()?; + handle_mem_access(mem_mgr)?; log_then_return!("MMIO access address {:#x}", addr); } @@ -531,10 +526,6 @@ pub(crate) mod tests { use hyperlight_testing::dummy_guest_as_string; - use super::handlers::{MemAccessHandler, OutBHandler, OutBHandlerFunction}; - #[cfg(gdb)] - use crate::hypervisor::DbgMemAccessHandlerCaller; - use crate::mem::ptr::RawPtr; use crate::sandbox::uninitialized::GuestBinary; #[cfg(any(crashdump, gdb))] use crate::sandbox::uninitialized::SandboxRuntimeConfig; @@ -542,36 +533,16 @@ pub(crate) mod tests { use crate::sandbox::{SandboxConfiguration, UninitializedSandbox}; use crate::{Result, is_hypervisor_present, new_error}; - #[cfg(gdb)] - struct DbgMemAccessHandler {} - - #[cfg(gdb)] - impl DbgMemAccessHandlerCaller for DbgMemAccessHandler { - fn read(&mut self, _offset: usize, _data: &mut [u8]) -> Result<()> { - Ok(()) - } - - fn write(&mut self, _offset: usize, _data: &[u8]) -> Result<()> { - Ok(()) - } - - fn get_code_offset(&mut self) -> Result { - Ok(0) - } - } - #[test] fn test_initialise() -> Result<()> { if !is_hypervisor_present() { return Ok(()); } - let mem_access_handler = { - let func: Box Result<()> + Send> = Box::new(|| -> Result<()> { Ok(()) }); - Arc::new(Mutex::new(MemAccessHandler::from(func))) - }; + use crate::mem::ptr::RawPtr; + use crate::sandbox::host_funcs::FunctionRegistry; #[cfg(gdb)] - let dbg_mem_access_handler = Arc::new(Mutex::new(DbgMemAccessHandler {})); + use crate::sandbox::mem_access::dbg_mem_access_handler_wrapper; let filename = dummy_guest_as_string().map_err(|e| new_error!("{}", e))?; @@ -580,7 +551,7 @@ pub(crate) mod tests { let rt_cfg: SandboxRuntimeConfig = Default::default(); let sandbox = UninitializedSandbox::new(GuestBinary::FilePath(filename.clone()), Some(config))?; - let (_hshm, mut gshm) = sandbox.mgr.build(); + let (mem_mgr, mut gshm) = sandbox.mgr.build(); let mut vm = set_up_hypervisor_partition( &mut gshm, &config, @@ -588,23 +559,29 @@ pub(crate) mod tests { &rt_cfg, sandbox.load_info, )?; - let outb_handler: Arc> = { - #[cfg(feature = "trace_guest")] - #[allow(clippy::type_complexity)] - let func: OutBHandlerFunction = Box::new(|_, _, _| -> Result<()> { Ok(()) }); - #[cfg(not(feature = "trace_guest"))] - let func: OutBHandlerFunction = Box::new(|_, _| -> Result<()> { Ok(()) }); - Arc::new(Mutex::new(OutBHandler::from(func))) - }; + + // Set up required parameters for initialise + let peb_addr = RawPtr::from(0x1000u64); // Dummy PEB address + let seed = 12345u64; // Random seed + let page_size = 4096u32; // Standard page size + let host_funcs = Arc::new(Mutex::new(FunctionRegistry::default())); + let guest_max_log_level = Some(log::LevelFilter::Error); + + #[cfg(gdb)] + let dbg_mem_access_fn = dbg_mem_access_handler_wrapper(mem_mgr.clone()); + + // Test the initialise method vm.initialise( - RawPtr::from(0x230000), - 1234567890, - 4096, - outb_handler, - mem_access_handler, - None, + peb_addr, + seed, + page_size, + mem_mgr, + host_funcs, + guest_max_log_level, #[cfg(gdb)] - dbg_mem_access_handler, - ) + dbg_mem_access_fn, + )?; + + Ok(()) } } diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 91722457b..ada0ea174 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -34,7 +34,6 @@ use crate::func::guest_err::check_for_guest_error; use crate::func::{ParameterTuple, SupportedReturnType}; #[cfg(gdb)] use crate::hypervisor::handlers::DbgMemAccessHandlerWrapper; -use crate::hypervisor::handlers::{MemAccessHandlerCaller, OutBHandlerCaller}; use crate::hypervisor::{Hypervisor, InterruptHandle}; #[cfg(unix)] use crate::mem::memory_region::MemoryRegionType; @@ -57,8 +56,6 @@ pub struct MultiUseSandbox { pub(super) _host_funcs: Arc>, pub(crate) mem_mgr: MemMgrWrapper, vm: Box, - out_hdl: Arc>, - mem_hdl: Arc>, dispatch_ptr: RawPtr, #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, @@ -75,8 +72,6 @@ impl MultiUseSandbox { host_funcs: Arc>, mgr: MemMgrWrapper, vm: Box, - out_hdl: Arc>, - mem_hdl: Arc>, dispatch_ptr: RawPtr, #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, ) -> MultiUseSandbox { @@ -84,8 +79,6 @@ impl MultiUseSandbox { _host_funcs: host_funcs, mem_mgr: mgr, vm, - out_hdl, - mem_hdl, dispatch_ptr, #[cfg(gdb)] dbg_mem_access_fn, @@ -237,8 +230,7 @@ impl MultiUseSandbox { self.vm.dispatch_call_from_host( self.dispatch_ptr.clone(), - self.out_hdl.clone(), - self.mem_hdl.clone(), + &self.mem_mgr, #[cfg(gdb)] self.dbg_mem_access_fn.clone(), )?; diff --git a/src/hyperlight_host/src/sandbox/mem_access.rs b/src/hyperlight_host/src/sandbox/mem_access.rs index 6a6078b2c..ea0d3a3fe 100644 --- a/src/hyperlight_host/src/sandbox/mem_access.rs +++ b/src/hyperlight_host/src/sandbox/mem_access.rs @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +#[cfg(gdb)] use std::sync::{Arc, Mutex}; use tracing::{Span, instrument}; @@ -22,14 +23,11 @@ use super::mem_mgr::MemMgrWrapper; use crate::error::HyperlightError::StackOverflow; #[cfg(gdb)] use crate::hypervisor::handlers::{DbgMemAccessHandlerCaller, DbgMemAccessHandlerWrapper}; -use crate::hypervisor::handlers::{ - MemAccessHandler, MemAccessHandlerFunction, MemAccessHandlerWrapper, -}; use crate::mem::shared_mem::HostSharedMemory; use crate::{Result, log_then_return}; #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] -pub(super) fn handle_mem_access_impl(wrapper: &MemMgrWrapper) -> Result<()> { +pub(crate) fn handle_mem_access(wrapper: &MemMgrWrapper) -> Result<()> { if !wrapper.check_stack_guard()? { log_then_return!(StackOverflow()); } @@ -37,16 +35,6 @@ pub(super) fn handle_mem_access_impl(wrapper: &MemMgrWrapper) Ok(()) } -#[instrument(skip_all, parent = Span::current(), level= "Trace")] -pub(crate) fn mem_access_handler_wrapper( - wrapper: MemMgrWrapper, -) -> MemAccessHandlerWrapper { - let mem_access_func: MemAccessHandlerFunction = - Box::new(move || handle_mem_access_impl(&wrapper)); - let mem_access_hdl = MemAccessHandler::from(mem_access_func); - Arc::new(Mutex::new(mem_access_hdl)) -} - #[cfg(gdb)] struct DbgMemAccessContainer { wrapper: MemMgrWrapper, diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index 62b3bf0c1..20a5d8f94 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -34,14 +34,15 @@ use tracing_log::format_trace; use super::host_funcs::FunctionRegistry; use super::mem_mgr::MemMgrWrapper; -use crate::hypervisor::handlers::{OutBHandler, OutBHandlerFunction, OutBHandlerWrapper}; +#[cfg(feature = "trace_guest")] +use crate::hypervisor::Hypervisor; #[cfg(feature = "trace_guest")] use crate::mem::layout::SandboxMemoryLayout; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; -use crate::{HyperlightError, Result, new_error}; #[cfg(feature = "trace_guest")] -use crate::{hypervisor::Hypervisor, sandbox::TraceInfo}; +use crate::sandbox::TraceInfo; +use crate::{HyperlightError, Result, new_error}; #[instrument(err(Debug), skip_all, parent = Span::current(), level="Trace")] pub(super) fn outb_log(mgr: &mut SandboxMemoryManager) -> Result<()> { @@ -267,7 +268,7 @@ pub(super) fn record_guest_trace_frame( /// Handles OutB operations from the guest. #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] -fn handle_outb_impl( +pub(crate) fn handle_outb( mem_mgr: &mut MemMgrWrapper, host_funcs: Arc>, #[cfg(feature = "trace_guest")] _hv: &mut dyn Hypervisor, @@ -402,31 +403,6 @@ fn handle_outb_impl( } } } - -/// Given a `MemMgrWrapper` and ` HostFuncsWrapper` -- both passed by _value_ -/// -- return an `OutBHandlerWrapper` wrapping the core OUTB handler logic. -/// -/// TODO: pass at least the `host_funcs_wrapper` param by reference. -#[instrument(skip_all, parent = Span::current(), level= "Trace")] -pub(crate) fn outb_handler_wrapper( - mut mem_mgr_wrapper: MemMgrWrapper, - host_funcs_wrapper: Arc>, -) -> OutBHandlerWrapper { - let outb_func: OutBHandlerFunction = - Box::new(move |#[cfg(feature = "trace_guest")] hv, port, payload| { - handle_outb_impl( - &mut mem_mgr_wrapper, - host_funcs_wrapper.clone(), - #[cfg(feature = "trace_guest")] - hv, - port, - payload, - ) - }); - let outb_hdl = OutBHandler::from(outb_func); - Arc::new(Mutex::new(outb_hdl)) -} - #[cfg(test)] mod tests { use hyperlight_common::flatbuffer_wrappers::guest_log_level::LogLevel; diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index ca6eb9e35..5db2722ef 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -27,7 +27,6 @@ use super::mem_access::dbg_mem_access_handler_wrapper; use super::uninitialized::SandboxRuntimeConfig; use crate::HyperlightError::NoHypervisorFound; use crate::hypervisor::Hypervisor; -use crate::hypervisor::handlers::{MemAccessHandlerCaller, OutBHandlerCaller}; use crate::mem::exe::LoadInfo; use crate::mem::layout::SandboxMemoryLayout; use crate::mem::mgr::SandboxMemoryManager; @@ -41,8 +40,6 @@ use crate::sandbox::TraceInfo; #[cfg(gdb)] use crate::sandbox::config::DebugInfo; use crate::sandbox::host_funcs::FunctionRegistry; -use crate::sandbox::mem_access::mem_access_handler_wrapper; -use crate::sandbox::outb::outb_handler_wrapper; use crate::sandbox::{HostSharedMemory, MemMgrWrapper}; #[cfg(target_os = "linux")] use crate::signal_handlers::setup_signal_handlers; @@ -69,8 +66,6 @@ where Arc>, MemMgrWrapper, Box, - Arc>, - Arc>, RawPtr, ) -> Result, { @@ -82,7 +77,6 @@ where &u_sbox.rt_cfg, u_sbox.load_info, )?; - let outb_hdl = outb_handler_wrapper(hshm.clone(), u_sbox.host_funcs.clone()); let seed = { let mut rng = rand::rng(); @@ -94,7 +88,6 @@ where }; let page_size = u32::try_from(page_size::get())?; - let mem_access_hdl = mem_access_handler_wrapper(hshm.clone()); #[cfg(gdb)] let dbg_mem_access_hdl = dbg_mem_access_handler_wrapper(hshm.clone()); @@ -106,8 +99,8 @@ where peb_addr, seed, page_size, - outb_hdl.clone(), - mem_access_hdl.clone(), + hshm.clone(), + u_sbox.host_funcs.clone(), u_sbox.max_guest_log_level, #[cfg(gdb)] dbg_mem_access_hdl, @@ -122,23 +115,19 @@ where u_sbox.host_funcs, hshm, vm, - outb_hdl, - mem_access_hdl, RawPtr::from(dispatch_function_addr), ) } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] pub(super) fn evolve_impl_multi_use(u_sbox: UninitializedSandbox) -> Result { - evolve_impl(u_sbox, |hf, hshm, vm, out_hdl, mem_hdl, dispatch_ptr| { + evolve_impl(u_sbox, |hf, hshm, vm, dispatch_ptr| { #[cfg(gdb)] let dbg_mem_wrapper = dbg_mem_access_handler_wrapper(hshm.clone()); Ok(MultiUseSandbox::from_uninit( hf, hshm, vm, - out_hdl, - mem_hdl, dispatch_ptr, #[cfg(gdb)] dbg_mem_wrapper, From 5e8eecfc1af421e8a80667a89b200e06d09c5bb0 Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Wed, 16 Jul 2025 22:11:42 +0100 Subject: [PATCH 061/271] Add Nix flake with development shell This also includes a couple of minor touches to other things in order to make them work more nicely in a nix devshell Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- dev/verify-msrv.sh | 2 +- flake.lock | 44 +++++++++ flake.nix | 145 ++++++++++++++++++++++++++++ src/hyperlight_guest_bin/Cargo.toml | 2 +- src/hyperlight_guest_bin/build.rs | 11 ++- 5 files changed, 200 insertions(+), 4 deletions(-) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/dev/verify-msrv.sh b/dev/verify-msrv.sh index 1b697fd13..acaf67cce 100755 --- a/dev/verify-msrv.sh +++ b/dev/verify-msrv.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -Eeuo pipefail cargo install -q jaq for CRATE in "$@"; do diff --git a/flake.lock b/flake.lock new file mode 100644 index 000000000..4efc77506 --- /dev/null +++ b/flake.lock @@ -0,0 +1,44 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1752950548, + "narHash": "sha256-NS6BLD0lxOrnCiEOcvQCDVPXafX1/ek1dfJHX1nUIzc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c87b95e25065c028d31a94f06a62927d18763fdf", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-mozilla": { + "locked": { + "lastModified": 1744624473, + "narHash": "sha256-S6zT/w5SyAkJ//dYdjbrXgm+6Vkd/k7qqUl4WgZ6jjk=", + "owner": "mozilla", + "repo": "nixpkgs-mozilla", + "rev": "2292d4b35aa854e312ad2e95c4bb5c293656f21a", + "type": "github" + }, + "original": { + "owner": "mozilla", + "ref": "master", + "repo": "nixpkgs-mozilla", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "nixpkgs-mozilla": "nixpkgs-mozilla" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 000000000..47cd32fcb --- /dev/null +++ b/flake.nix @@ -0,0 +1,145 @@ +{ + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + inputs.nixpkgs-mozilla.url = "github:mozilla/nixpkgs-mozilla/master"; + outputs = { self, nixpkgs, nixpkgs-mozilla, ... } @ inputs: + { + devShells.x86_64-linux.default = + let pkgs = import nixpkgs { + system = "x86_64-linux"; + overlays = [ (import (nixpkgs-mozilla + "/rust-overlay.nix")) ]; + }; + in with pkgs; let + # Work around the nixpkgs-mozilla equivalent of + # https://github.com/NixOS/nixpkgs/issues/278508 and an + # incompatibility between nixpkgs-mozilla and makeRustPlatform + rustChannelOf = args: let + orig = pkgs.rustChannelOf args; + patchRustPkg = pkg: (pkg.overrideAttrs (oA: { + buildCommand = builtins.replaceStrings + [ "rustc,rustdoc" ] + [ "rustc,rustdoc,clippy-driver,cargo-clippy" ] + oA.buildCommand; + })) // { + targetPlatforms = [ "x86_64-linux" ]; + badTargetPlatforms = [ ]; + }; + overrideRustPkg = pkg: lib.makeOverridable (origArgs: + patchRustPkg (pkg.override origArgs) + ) {}; + in builtins.mapAttrs (_: overrideRustPkg) orig; + + customisedRustChannelOf = args: + lib.flip builtins.mapAttrs (rustChannelOf args) (_: pkg: pkg.override { + targets = [ + "x86_64-unknown-linux-gnu" + "x86_64-pc-windows-msvc" "x86_64-unknown-none" + "wasm32-wasip1" "wasm32-wasip2" "wasm32-unknown-unknown" + ]; + extensions = [ "rust-src" ]; + }); + + # Hyperlight needs a variety of toolchains, since we use Nightly + # for rustfmt and old toolchains to verify MSRV + toolchains = lib.mapAttrs (_: customisedRustChannelOf) { + stable = { + # Stay on 1.87 for development due to the + # quickly-reversed default enablement of + # #[warn(clippy::uninlined_format_args)] + date = "2025-05-15"; + channel = "stable"; + sha256 = "sha256-KUm16pHj+cRedf8vxs/Hd2YWxpOrWZ7UOrwhILdSJBU="; + }; + nightly = { + date = "2025-07-29"; + channel = "nightly"; + sha256 = "sha256-6D2b7glWC3jpbIGCq6Ta59lGCKN9sTexhgixH4Y7Nng="; + }; + "1.85" = { + date = "2025-02-20"; + channel = "stable"; + sha256 = "sha256-AJ6LX/Q/Er9kS15bn9iflkUwcgYqRQxiOIL2ToVAXaU="; + }; + }; + + rust-platform = makeRustPlatform { + cargo = toolchains.stable.rust; + rustc = toolchains.stable.rust; + }; + + # Hyperlight scripts use cargo in a bunch of ways that don't + # make sense for Nix cargo, including the `rustup +toolchain` + # syntax to use a specific toolchain and `cargo install`, so we + # build wrappers for rustc and cargo that enable this. The + # scripts also use `rustup toolchain install` in some cases, in + # order to work in CI, so we provide a fake rustup that does + # nothing as well. + rustup-like-wrapper = name: pkgs.writeShellScriptBin name + (let + clause = name: toolchain: + "+${name}) base=\"${toolchain.rust}\"; shift 1; ;;"; + clauses = lib.strings.concatStringsSep "\n" + (lib.mapAttrsToList clause toolchains); + in '' + base="${toolchains.stable.rust}" + case "$1" in + ${clauses} + install) exit 0; ;; + esac + export PATH="$base/bin:$PATH" + exec "$base/bin/${name}" "$@" + ''); + fake-rustup = pkgs.symlinkJoin { + name = "fake-rustup"; + paths = [ + (pkgs.writeShellScriptBin "rustup" "") + (rustup-like-wrapper "rustc") + (rustup-like-wrapper "cargo") + ]; + }; + + buildRustPackageClang = rust-platform.buildRustPackage.override { stdenv = clangStdenv; }; + in (buildRustPackageClang rec { + pname = "hyperlight"; + version = "0.0.0"; + src = lib.cleanSource ./.; + cargoHash = "sha256-mNKnsaSKVz4khzWO7VhmN0cR+Ed5ML7fD1PJJCeQQ6E="; + + nativeBuildInputs = [ + azure-cli + just + dotnet-sdk_9 + llvmPackages_18.llvm + gh + lld + valgrind + pkg-config + ffmpeg + mkvtoolnix + wasm-tools + jq + jaq + gdb + ]; + buildInputs = [ + pango + cairo + openssl + ]; + + auditable = false; + + LIBCLANG_PATH = "${pkgs.llvmPackages_18.libclang.lib}/lib"; + # Use unwrapped clang for compiling guests + HYPERLIGHT_GUEST_clang = "${clang.cc}/bin/clang"; + + RUST_NIGHTLY = "${toolchains.nightly.rust}"; + # Set this through shellHook rather than nativeBuildInputs to be + # really sure that it overrides the real cargo. + shellHook = '' + export PATH="${fake-rustup}/bin:$PATH" + ''; + }).overrideAttrs(oA: { + hardeningDisable = [ "all" ]; + }); + }; +} diff --git a/src/hyperlight_guest_bin/Cargo.toml b/src/hyperlight_guest_bin/Cargo.toml index ff30980b4..90e80bff9 100644 --- a/src/hyperlight_guest_bin/Cargo.toml +++ b/src/hyperlight_guest_bin/Cargo.toml @@ -16,7 +16,7 @@ and third-party code used by our C-API needed to build a native hyperlight-guest [features] default = ["libc", "printf"] libc = [] # compile musl libc -printf = [] # compile printf +printf = [ "libc" ] # compile printf trace_guest = ["hyperlight-common/trace_guest", "dep:hyperlight-guest-tracing", "hyperlight-guest/trace_guest"] mem_profile = ["hyperlight-common/unwind_guest","hyperlight-common/mem_profile"] diff --git a/src/hyperlight_guest_bin/build.rs b/src/hyperlight_guest_bin/build.rs index dd8d76079..493f97291 100644 --- a/src/hyperlight_guest_bin/build.rs +++ b/src/hyperlight_guest_bin/build.rs @@ -97,7 +97,11 @@ fn cargo_main() { cfg.flag("-fno-stack-protector"); cfg.flag("-fstack-clash-protection"); cfg.flag("-mstack-probe-size=4096"); - cfg.compiler("clang"); + cfg.compiler( + env::var("HYPERLIGHT_GUEST_clang") + .as_deref() + .unwrap_or("clang"), + ); if cfg!(windows) { unsafe { env::set_var("AR_x86_64_unknown_none", "llvm-ar") }; @@ -197,7 +201,10 @@ impl From<&std::ffi::OsStr> for Tool { } fn find_next(root_dir: &Path, tool_name: &str) -> PathBuf { - let path = env::var_os("PATH").expect("$PATH should exist"); + if let Some(path) = env::var_os(format!("HYPERLIGHT_GUEST_{tool_name}")) { + return path.into(); + } + let path = env::var_os("PATH)").expect("$PATH should exist"); let paths: Vec<_> = env::split_paths(&path).collect(); for path in &paths { let abs_path = fs::canonicalize(path); From cf6f842b30c17467717bea883047bc3926d162e6 Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Thu, 24 Jul 2025 16:22:48 +0100 Subject: [PATCH 062/271] [justfile] Add `like-ci`, which runs more-or-less all the CI checks Unlike `test-like-ci`, this includes fmt, clippy, a guest rebuild, examples, etc. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- Justfile | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/Justfile b/Justfile index 8a0d2bc2d..d478e6a2a 100644 --- a/Justfile +++ b/Justfile @@ -91,7 +91,56 @@ test-like-ci config=default-target hypervisor="kvm": just test-rust-crashdump {{config}} @# test the tracing related features - just test-rust-tracing {{config}} {{ if hypervisor == "mshv3" {"mshv3"} else {""} }} + {{ if os() == "linux" { "just test-rust-tracing " + config + " " + if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } } else { "" } }} + +like-ci config=default-target hypervisor="kvm": + @# Ensure up-to-date Cargo.lock + cargo fetch --locked + + @# fmt + just fmt-check + + @# clippy + {{ if os() == "windows" { "just clippy " + config } else { "" } }} + {{ if os() == "windows" { "just clippy-guests " + config } else { "" } }} + + @# clippy exhaustive check + {{ if os() == "linux" { "just clippy-exhaustive " + config } else { "" } }} + + @# Verify MSRV + ./dev/verify-msrv.sh hyperlight-host hyperlight-guest hyperlight-guest-bin hyperlight-common + + @# Build and move Rust guests + just build-rust-guests {{config}} + just move-rust-guests {{config}} + + @# Build c guests + just build-c-guests {{config}} + just move-c-guests {{config}} + + @# Build + just build {{config}} + + @# Run Rust tests + just test-like-ci {{config}} {{hypervisor}} + + @# Run Rust examples - Windows + {{ if os() == "windows" { "just run-rust-examples " + config } else { "" } }} + + @# Run Rust examples - linux + {{ if os() == "linux" { "just run-rust-examples-linux " + config + " " + if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } } else { "" } }} + + @# Run Rust Gdb tests - linux + {{ if os() == "linux" { "just test-rust-gdb-debugging " + config + " " + if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } } else { "" } }} + + @# Run Rust Crashdump tests + just test-rust-crashdump {{config}} {{ if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } }} + + @# Run Rust Tracing tests - linux + {{ if os() == "linux" { "just test-rust-tracing " + config + " " + if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } } else { "" } }} + + @# Run benchmarks + just bench-ci main {{config}} {{ if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } }} # runs all tests test target=default-target features="": (test-unit target features) (test-isolated target features) (test-integration "rust" target features) (test-integration "c" target features) (test-seccomp target features) From 9a2860ac20233765044f5ac7d3d4889b1fab1d56 Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Tue, 29 Jul 2025 16:57:17 +0100 Subject: [PATCH 063/271] Fix clippy warnings that are enabled in newer toolchains Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- src/hyperlight_component_util/src/subtype.rs | 7 +++++-- src/hyperlight_host/src/hypervisor/mod.rs | 14 +++++++------- src/hyperlight_host/src/lib.rs | 2 +- src/hyperlight_host/src/mem/layout.rs | 2 +- src/hyperlight_host/src/mem/shared_mem.rs | 5 ++--- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/hyperlight_component_util/src/subtype.rs b/src/hyperlight_component_util/src/subtype.rs index cb39eea4d..f5ccaf7a5 100644 --- a/src/hyperlight_component_util/src/subtype.rs +++ b/src/hyperlight_component_util/src/subtype.rs @@ -36,7 +36,7 @@ pub enum Error<'r> { /// A value type was present, but incompatible with its expected type MismatchedValue(Value<'r>, Value<'r>), /// A defined type was present, but incompatible with its expected type - MismatchedDefined(Defined<'r>, Defined<'r>), + MismatchedDefined(Box>, Box>), /// A resource was present, but was not the same resource as was expected MismatchedResources(ResourceId, ResourceId), /// A type variable could not be resolved to be the same as the @@ -239,7 +239,10 @@ impl<'p, 'a> Ctx<'p, 'a> { self.subtype_qualified_instance(it1, it2) } (Defined::Component(ct1), Defined::Component(ct2)) => self.subtype_component(ct1, ct2), - _ => Err(Error::MismatchedDefined(dt1.clone(), dt2.clone())), + _ => Err(Error::MismatchedDefined( + Box::new(dt1.clone()), + Box::new(dt2.clone()), + )), } } pub fn subtype_handleable_is_resource<'r>(&self, ht: &'r Handleable) -> Result<(), Error<'a>> { diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index e34175ba0..801a354be 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -373,8 +373,8 @@ pub trait InterruptHandle: Debug + Send + Sync { /// /// - If this is called while the vcpu is running, then it will interrupt the vcpu and return `true`. /// - If this is called while the vcpu is not running, (for example during a host call), the - /// vcpu will not immediately be interrupted, but will prevent the vcpu from running **the next time** - /// it's scheduled, and returns `false`. + /// vcpu will not immediately be interrupted, but will prevent the vcpu from running **the next time** + /// it's scheduled, and returns `false`. /// /// # Note /// This function will block for the duration of the time it takes for the vcpu thread to be interrupted. @@ -384,8 +384,8 @@ pub trait InterruptHandle: Debug + Send + Sync { /// /// - If this is called while the vcpu is running, then it will interrupt the vcpu and return `true`. /// - If this is called while the vcpu is not running, (for example during a host call), the - /// vcpu will not immediately be interrupted, but will prevent the vcpu from running **the next time** - /// it's scheduled, and returns `false`. + /// vcpu will not immediately be interrupted, but will prevent the vcpu from running **the next time** + /// it's scheduled, and returns `false`. /// /// # Note /// This function will block for the duration of the time it takes for the vcpu thread to be interrupted. @@ -407,7 +407,7 @@ pub(super) struct LinuxInterruptHandle { /// 1. The VCPU is running (generation N), /// 2. It gets cancelled, /// 3. Then quickly restarted (generation N+1), - /// before the original thread has observed that it was cancelled. + /// before the original thread has observed that it was cancelled. /// /// Without this generation counter, the interrupt logic might assume the VCPU is still /// in the *original* run (generation N), see that it's `running`, and re-send the signal. @@ -423,9 +423,9 @@ pub(super) struct LinuxInterruptHandle { /// `kill()` is called, and cleared when the vcpu is no longer running. /// This is used to /// 1. make sure stale signals do not interrupt the - /// the wrong vcpu (a vcpu may only be interrupted iff `cancel_requested` is true), + /// the wrong vcpu (a vcpu may only be interrupted iff `cancel_requested` is true), /// 2. ensure that if a vm is killed while a host call is running, - /// the vm will not re-enter the guest after the host call returns. + /// the vm will not re-enter the guest after the host call returns. cancel_requested: AtomicBool, /// True when the debugger has requested the VM to be interrupted. Set immediately when /// `kill_from_debugger()` is called, and cleared when the vcpu is no longer running. diff --git a/src/hyperlight_host/src/lib.rs b/src/hyperlight_host/src/lib.rs index 6e5e67816..7e6a69a9c 100644 --- a/src/hyperlight_host/src/lib.rs +++ b/src/hyperlight_host/src/lib.rs @@ -50,7 +50,7 @@ pub mod hypervisor; /// present and code length will be zero; /// /// - The pointer passed to the Entrypoint in the Guest application is the size of page table + size of code, -/// at this address structs below are laid out in this order +/// at this address structs below are laid out in this order pub mod mem; /// Metric definitions and helpers pub mod metrics; diff --git a/src/hyperlight_host/src/mem/layout.rs b/src/hyperlight_host/src/mem/layout.rs index b453d90fb..de357b7ca 100644 --- a/src/hyperlight_host/src/mem/layout.rs +++ b/src/hyperlight_host/src/mem/layout.rs @@ -64,7 +64,7 @@ use crate::{Result, new_error}; // +-------------------------------------------+ 0x0_000 /// - `InitData` - some extra data that can be loaded onto the sandbox during -/// initialization. +/// initialization. /// /// - `HostDefinitions` - the length of this is the `HostFunctionDefinitionSize` /// field from `SandboxConfiguration` diff --git a/src/hyperlight_host/src/mem/shared_mem.rs b/src/hyperlight_host/src/mem/shared_mem.rs index 23d0b7fcf..e61e1b7ee 100644 --- a/src/hyperlight_host/src/mem/shared_mem.rs +++ b/src/hyperlight_host/src/mem/shared_mem.rs @@ -785,7 +785,7 @@ impl HostSharedMemory { /// patterns pub fn read(&self, offset: usize) -> Result { bounds_check!(offset, std::mem::size_of::(), self.mem_size()); - let ret = unsafe { + unsafe { let mut ret: core::mem::MaybeUninit = core::mem::MaybeUninit::uninit(); { let slice: &mut [u8] = core::slice::from_raw_parts_mut( @@ -795,8 +795,7 @@ impl HostSharedMemory { self.copy_to_slice(slice, offset)?; } Ok(ret.assume_init()) - }; - ret + } } /// Write a value of type T, whose representation is the same From 75f1e8842d3d4124cd6a547b97c5491c839068f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Wed, 30 Jul 2025 17:50:20 +0300 Subject: [PATCH 064/271] fix ci tracing tests silently failing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- .github/workflows/dep_rust.yml | 2 +- Justfile | 12 ++++++++---- src/tests/rust_guests/witguest/Cargo.lock | 8 ++++---- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index e625eb88a..fc68e3e4b 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -175,7 +175,7 @@ jobs: env: CARGO_TERM_COLOR: always RUST_LOG: debug - run: just test-rust-tracing ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv2' && 'mshv2' || ''}} + run: just test-rust-tracing ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} - name: Download benchmarks from "latest" run: just bench-download ${{ runner.os }} ${{ matrix.hypervisor }} ${{ matrix.cpu}} dev-latest # compare to prerelease diff --git a/Justfile b/Justfile index d478e6a2a..e6cf371bb 100644 --- a/Justfile +++ b/Justfile @@ -204,10 +204,14 @@ test-rust-tracing target=default-target features="": just build-rust-guests {{ target }} trace_guest just move-rust-guests {{ target }} # Run hello-world example with tracing enabled to get the trace output - # Capture the trace file path and print use it afterwards to run cargo run -p trace_dump - cargo run --profile={{ if target == "debug" { "dev" } else { target } }} --example hello-world --features {{ if features =="" {'trace_guest'} else { "trace_guest," + features } }} \ - | sed -n 's/.*Creating trace file at: \(.*\)/\1/p' \ - | xargs -I {} cargo run -p trace_dump ./{{ simpleguest_source }}/{{ target }}/simpleguest {} list_frames + TRACE_OUTPUT="$(cargo run --profile={{ if target == "debug" { "dev" } else { target } }} --example hello-world --features {{ if features =="" {"trace_guest"} else { "trace_guest," + features } }})" && \ + TRACE_FILE="$(echo "$TRACE_OUTPUT" | grep -oE 'Creating trace file at: [^ ]+' | awk -F': ' '{print $2}')" && \ + echo "$TRACE_OUTPUT" && \ + if [ -z "$TRACE_FILE" ]; then \ + echo "Error: Could not extract trace file path from output." >&2 ; \ + exit 1 ; \ + fi && \ + cargo run -p trace_dump ./{{ simpleguest_source }}/{{ target }}/simpleguest "$TRACE_FILE" list_frames # Rebuild the tracing guests without the tracing feature # This is to ensure that the tracing feature does not affect the other tests diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index ddd6f659e..ea2537ea3 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -359,9 +359,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.35" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" +checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" dependencies = [ "proc-macro2", "syn", @@ -522,9 +522,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "wasmparser" -version = "0.235.0" +version = "0.236.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917" +checksum = "16d1eee846a705f6f3cb9d7b9f79b54583810f1fb57a1e3aea76d1742db2e3d2" dependencies = [ "bitflags", "hashbrown", From a32e8b475868e70d4a46757f717442a439c3ad8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Wed, 30 Jul 2025 18:54:07 +0300 Subject: [PATCH 065/271] fix mem_mgr not initialized when tracing enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- .../src/hypervisor/hyperv_linux.rs | 27 +++++++------------ .../src/hypervisor/hyperv_windows.rs | 27 +++++++------------ src/hyperlight_host/src/hypervisor/kvm.rs | 27 +++++++------------ src/hyperlight_host/src/hypervisor/mod.rs | 7 ++--- .../src/sandbox/initialized_multi_use.rs | 1 - src/hyperlight_host/src/sandbox/mem_access.rs | 7 +++-- 6 files changed, 39 insertions(+), 57 deletions(-) diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index df3073a09..62bce6425 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -609,24 +609,11 @@ impl Hypervisor for HypervLinuxDriver { }; self.vcpu_fd.set_regs(®s)?; - // Extract mem_mgr to avoid borrowing conflicts - let mem_mgr = self - .mem_mgr - .take() - .ok_or_else(|| new_error!("mem_mgr should be initialized"))?; - - let result = VirtualCPU::run( + VirtualCPU::run( self.as_mut_hypervisor(), - &mem_mgr, #[cfg(gdb)] dbg_mem_access_fn, - ); - - // Put mem_mgr back - self.mem_mgr = Some(mem_mgr); - result?; - - Ok(()) + ) } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] @@ -664,7 +651,6 @@ impl Hypervisor for HypervLinuxDriver { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - mem_mgr: &MemMgrWrapper, #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, ) -> Result<()> { // Reset general purpose registers, then set RIP and RSP @@ -688,7 +674,6 @@ impl Hypervisor for HypervLinuxDriver { // run VirtualCPU::run( self.as_mut_hypervisor(), - mem_mgr, #[cfg(gdb)] dbg_mem_access_fn, )?; @@ -1162,6 +1147,14 @@ impl Hypervisor for HypervLinuxDriver { Ok(()) } + fn check_stack_guard(&self) -> Result { + if let Some(mgr) = self.mem_mgr.as_ref() { + mgr.check_stack_guard() + } else { + Err(new_error!("Memory manager is not initialized")) + } + } + #[cfg(feature = "trace_guest")] fn read_trace_reg(&self, reg: TraceRegister) -> Result { let mut assoc = [hv_register_assoc { diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index 595372306..d4a0c06cd 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -623,24 +623,11 @@ impl Hypervisor for HypervWindowsDriver { }; self.processor.set_general_purpose_registers(®s)?; - // Extract mem_mgr to avoid borrowing conflicts - let mem_mgr = self - .mem_mgr - .take() - .ok_or_else(|| new_error!("mem_mgr should be initialized"))?; - - let result = VirtualCPU::run( + VirtualCPU::run( self.as_mut_hypervisor(), - &mem_mgr, #[cfg(gdb)] dbg_mem_access_hdl, - ); - - // Put mem_mgr back - self.mem_mgr = Some(mem_mgr); - result?; - - Ok(()) + ) } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] @@ -662,7 +649,6 @@ impl Hypervisor for HypervWindowsDriver { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - mem_mgr: &MemMgrWrapper, #[cfg(gdb)] dbg_mem_access_hdl: DbgMemAccessHandlerWrapper, ) -> Result<()> { // Reset general purpose registers, then set RIP and RSP @@ -684,7 +670,6 @@ impl Hypervisor for HypervWindowsDriver { VirtualCPU::run( self.as_mut_hypervisor(), - mem_mgr, #[cfg(gdb)] dbg_mem_access_hdl, )?; @@ -1094,6 +1079,14 @@ impl Hypervisor for HypervWindowsDriver { Ok(()) } + fn check_stack_guard(&self) -> Result { + if let Some(mgr) = self.mem_mgr.as_ref() { + mgr.check_stack_guard() + } else { + Err(new_error!("Memory manager is not initialized")) + } + } + #[cfg(feature = "trace_guest")] fn read_trace_reg(&self, reg: TraceRegister) -> Result { let regs = self.processor.get_regs()?; diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index 761020c50..8a2de0d40 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -492,24 +492,11 @@ impl Hypervisor for KVMDriver { }; self.vcpu_fd.set_regs(®s)?; - // Extract mem_mgr to avoid borrowing conflicts - let mem_mgr = self - .mem_mgr - .take() - .ok_or_else(|| new_error!("mem_mgr should be initialized"))?; - - let result = VirtualCPU::run( + VirtualCPU::run( self.as_mut_hypervisor(), - &mem_mgr, #[cfg(gdb)] dbg_mem_access_fn, - ); - - // Put mem_mgr back - self.mem_mgr = Some(mem_mgr); - result?; - - Ok(()) + ) } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] @@ -555,7 +542,6 @@ impl Hypervisor for KVMDriver { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - mem_mgr: &MemMgrWrapper, #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, ) -> Result<()> { // Reset general purpose registers, then set RIP and RSP @@ -578,7 +564,6 @@ impl Hypervisor for KVMDriver { // run VirtualCPU::run( self.as_mut_hypervisor(), - mem_mgr, #[cfg(gdb)] dbg_mem_access_fn, )?; @@ -1012,6 +997,14 @@ impl Hypervisor for KVMDriver { Ok(()) } + fn check_stack_guard(&self) -> Result { + if let Some(mgr) = self.mem_mgr.as_ref() { + mgr.check_stack_guard() + } else { + Err(new_error!("Memory manager is not initialized")) + } + } + #[cfg(feature = "trace_guest")] fn read_trace_reg(&self, reg: TraceRegister) -> Result { let regs = self.vcpu_fd.get_regs()?; diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index 801a354be..0fe452b6e 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -170,7 +170,6 @@ pub(crate) trait Hypervisor: Debug + Send { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - mem_mgr: &MemMgrWrapper, #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, ) -> Result<()>; @@ -269,6 +268,9 @@ pub(crate) trait Hypervisor: Debug + Send { unimplemented!() } + /// Check stack guard to see if the stack is still valid + fn check_stack_guard(&self) -> Result; + /// Read a register for trace/unwind purposes #[cfg(feature = "trace_guest")] fn read_trace_reg(&self, reg: TraceRegister) -> Result; @@ -289,7 +291,6 @@ impl VirtualCPU { #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] pub(crate) fn run( hv: &mut dyn Hypervisor, - mem_mgr: &MemMgrWrapper, #[cfg(gdb)] dbg_mem_access_fn: Arc>, ) -> Result<()> { loop { @@ -311,7 +312,7 @@ impl VirtualCPU { #[cfg(crashdump)] crashdump::generate_crashdump(hv)?; - handle_mem_access(mem_mgr)?; + handle_mem_access(hv)?; log_then_return!("MMIO access address {:#x}", addr); } diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index ada0ea174..b3cee64f8 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -230,7 +230,6 @@ impl MultiUseSandbox { self.vm.dispatch_call_from_host( self.dispatch_ptr.clone(), - &self.mem_mgr, #[cfg(gdb)] self.dbg_mem_access_fn.clone(), )?; diff --git a/src/hyperlight_host/src/sandbox/mem_access.rs b/src/hyperlight_host/src/sandbox/mem_access.rs index ea0d3a3fe..e9de96e99 100644 --- a/src/hyperlight_host/src/sandbox/mem_access.rs +++ b/src/hyperlight_host/src/sandbox/mem_access.rs @@ -19,16 +19,19 @@ use std::sync::{Arc, Mutex}; use tracing::{Span, instrument}; +#[cfg(gdb)] use super::mem_mgr::MemMgrWrapper; use crate::error::HyperlightError::StackOverflow; +use crate::hypervisor::Hypervisor; #[cfg(gdb)] use crate::hypervisor::handlers::{DbgMemAccessHandlerCaller, DbgMemAccessHandlerWrapper}; +#[cfg(gdb)] use crate::mem::shared_mem::HostSharedMemory; use crate::{Result, log_then_return}; #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] -pub(crate) fn handle_mem_access(wrapper: &MemMgrWrapper) -> Result<()> { - if !wrapper.check_stack_guard()? { +pub(crate) fn handle_mem_access(hv: &dyn Hypervisor) -> Result<()> { + if !hv.check_stack_guard()? { log_then_return!(StackOverflow()); } From dfe77726b2becc426bab90cf9fa73d666edf4915 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Wed, 30 Jul 2025 12:43:38 -0700 Subject: [PATCH 066/271] [fix] Make sure memory is not mapped writeable into sandbox in kvm (#740) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- src/hyperlight_host/src/mem/memory_region.rs | 8 ++- .../src/sandbox/initialized_multi_use.rs | 66 +++++++++++++++-- src/tests/rust_guests/simpleguest/src/main.rs | 72 +++++++++++++++++++ 3 files changed, 139 insertions(+), 7 deletions(-) diff --git a/src/hyperlight_host/src/mem/memory_region.rs b/src/hyperlight_host/src/mem/memory_region.rs index b46426c3b..f4c38b168 100644 --- a/src/hyperlight_host/src/mem/memory_region.rs +++ b/src/hyperlight_host/src/mem/memory_region.rs @@ -324,9 +324,11 @@ impl From for kvm_bindings::kvm_userspace_memory_region { guest_phys_addr: region.guest_region.start as u64, memory_size: (region.guest_region.end - region.guest_region.start) as u64, userspace_addr: region.host_region.start as u64, - flags: match perm_flags { - MemoryRegionFlags::READ => KVM_MEM_READONLY, - _ => 0, // normal, RWX + flags: if perm_flags.contains(MemoryRegionFlags::WRITE) { + 0 // RWX + } else { + // Note: KVM_MEM_READONLY is executable + KVM_MEM_READONLY // RX }, } } diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index b3cee64f8..f9514dcd2 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -596,8 +596,12 @@ mod tests { let guest_base = 0x1_0000_0000; // Arbitrary guest base address unsafe { - sbox.map_region(®ion_for_memory(&map_mem, guest_base)) - .unwrap(); + sbox.map_region(®ion_for_memory( + &map_mem, + guest_base, + MemoryRegionFlags::READ, + )) + .unwrap(); } let _guard = map_mem.lock.try_read().unwrap(); @@ -611,6 +615,56 @@ mod tests { assert_eq!(actual, expected); } + // Makes sure MemoryRegionFlags::READ | MemoryRegionFlags::EXECUTE executable but not writable + #[cfg(target_os = "linux")] + #[test] + fn test_mmap_write_exec() { + let mut sbox = UninitializedSandbox::new( + GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")), + None, + ) + .unwrap() + .evolve() + .unwrap(); + + let expected = &[0x90, 0x90, 0x90, 0xC3]; // NOOP slide to RET + let map_mem = page_aligned_memory(expected); + let guest_base = 0x1_0000_0000; // Arbitrary guest base address + + unsafe { + sbox.map_region(®ion_for_memory( + &map_mem, + guest_base, + MemoryRegionFlags::READ | MemoryRegionFlags::EXECUTE, + )) + .unwrap(); + } + + let _guard = map_mem.lock.try_read().unwrap(); + + // Execute should pass since memory is executable + let succeed = sbox + .call_guest_function_by_name::( + "ExecMappedBuffer", + (guest_base as u64, expected.len() as u64), + ) + .unwrap(); + assert!(succeed, "Expected execution of mapped buffer to succeed"); + + // write should fail because the memory is mapped as read-only + let err = sbox + .call_guest_function_by_name::( + "WriteMappedBuffer", + (guest_base as u64, expected.len() as u64), + ) + .unwrap_err(); + + match err { + HyperlightError::MemoryAccessViolation(addr, ..) if addr == guest_base as u64 => {} + _ => panic!("Expected MemoryAccessViolation error"), + }; + } + #[cfg(target_os = "linux")] fn page_aligned_memory(src: &[u8]) -> GuestSharedMemory { use hyperlight_common::mem::PAGE_SIZE_USIZE; @@ -626,13 +680,17 @@ mod tests { } #[cfg(target_os = "linux")] - fn region_for_memory(mem: &GuestSharedMemory, guest_base: usize) -> MemoryRegion { + fn region_for_memory( + mem: &GuestSharedMemory, + guest_base: usize, + flags: MemoryRegionFlags, + ) -> MemoryRegion { let ptr = mem.base_addr(); let len = mem.mem_size(); MemoryRegion { host_region: ptr..(ptr + len), guest_region: guest_base..(guest_base + len), - flags: MemoryRegionFlags::READ, + flags, region_type: MemoryRegionType::Heap, } } diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index 3bf093665..405087e25 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -798,6 +798,60 @@ fn read_mapped_buffer(function_call: &FunctionCall) -> Result> { } } +fn write_mapped_buffer(function_call: &FunctionCall) -> Result> { + if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( + function_call.parameters.clone().unwrap()[0].clone(), + function_call.parameters.clone().unwrap()[1].clone(), + ) { + let base = base as usize as *mut u8; + let len = len as usize; + + unsafe { + hyperlight_guest_bin::paging::map_region(base as _, base as _, len as u64 + 4096) + }; + + let data = unsafe { core::slice::from_raw_parts_mut(base, len) }; + + // should fail + data[0] = 0x42; + + // should never reach this + Ok(get_flatbuffer_result(true)) + } else { + Err(HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + "Invalid parameters passed to read_mapped_buffer".to_string(), + )) + } +} + +fn exec_mapped_buffer(function_call: &FunctionCall) -> Result> { + if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( + function_call.parameters.clone().unwrap()[0].clone(), + function_call.parameters.clone().unwrap()[1].clone(), + ) { + let base = base as usize as *mut u8; + let len = len as usize; + + unsafe { + hyperlight_guest_bin::paging::map_region(base as _, base as _, len as u64 + 4096) + }; + + let data = unsafe { core::slice::from_raw_parts(base, len) }; + + // Should be safe as long as data is something like a NOOP followed by a RET + let func: fn() = unsafe { core::mem::transmute(data.as_ptr()) }; + func(); + + Ok(get_flatbuffer_result(true)) + } else { + Err(HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + "Invalid parameters passed to read_mapped_buffer".to_string(), + )) + } +} + #[no_mangle] pub extern "C" fn hyperlight_main() { let read_from_user_memory_def = GuestFunctionDefinition::new( @@ -818,6 +872,24 @@ pub extern "C" fn hyperlight_main() { register_function(read_mapped_buffer_def); + let write_mapped_buffer_def = GuestFunctionDefinition::new( + "WriteMappedBuffer".to_string(), + Vec::from(&[ParameterType::ULong, ParameterType::ULong]), + ReturnType::Bool, + write_mapped_buffer as usize, + ); + + register_function(write_mapped_buffer_def); + + let exec_mapped_buffer_def = GuestFunctionDefinition::new( + "ExecMappedBuffer".to_string(), + Vec::from(&[ParameterType::ULong, ParameterType::ULong]), + ReturnType::Bool, + exec_mapped_buffer as usize, + ); + + register_function(exec_mapped_buffer_def); + let set_static_def = GuestFunctionDefinition::new( "SetStatic".to_string(), Vec::new(), From 2dee742967146291f1147f712e30bde34ec58893 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Wed, 30 Jul 2025 13:51:19 -0700 Subject: [PATCH 067/271] Make snapshots region aware (#742) * refactor: move get_memory_access_violation out from trait - Accept iterator instead of slice - Move function from trait to module level. Necessary to maintain object safety of Hypervisor trait Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * implement memory region tracking in drivers - Separate Vecs for initial sandbox regions and mmap regions - Replace unmap_regions(n) with unmap_region(region) for precise control - Add Hash derive for MemoryRegion and related types - Enable use of MemoryRegino in HashSet for efficient set operations Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Make snapshot region aware - Snapshot now contains the memory region that were mapped at the time of snapshot - On restore, unmap regions that were not mapped at time of snapshot. Map regions that were - Add simple test Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --------- Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- .../src/hypervisor/hyperv_linux.rs | 46 +++++++---- .../src/hypervisor/hyperv_windows.rs | 40 +++++---- src/hyperlight_host/src/hypervisor/kvm.rs | 70 ++++++++++++---- src/hyperlight_host/src/hypervisor/mod.rs | 60 +++++++------- src/hyperlight_host/src/mem/memory_region.rs | 6 +- src/hyperlight_host/src/mem/mgr.rs | 22 ++--- .../src/mem/shared_mem_snapshot.rs | 28 ++++--- .../src/sandbox/initialized_multi_use.rs | 81 +++++++++++++++++-- 8 files changed, 245 insertions(+), 108 deletions(-) diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 62bce6425..0f8a68521 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -75,6 +75,7 @@ use super::{ use super::{HyperlightExit, Hypervisor, InterruptHandle, LinuxInterruptHandle, VirtualCPU}; #[cfg(gdb)] use crate::HyperlightError; +use crate::hypervisor::get_memory_access_violation; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::{GuestPtr, RawPtr}; use crate::mem::shared_mem::HostSharedMemory; @@ -312,12 +313,15 @@ pub(crate) struct HypervLinuxDriver { page_size: usize, vm_fd: VmFd, vcpu_fd: VcpuFd, - entrypoint: u64, - mem_regions: Vec, orig_rsp: GuestPtr, + entrypoint: u64, interrupt_handle: Arc, mem_mgr: Option>, host_funcs: Option>>, + + sandbox_regions: Vec, // Initially mapped regions when sandbox is created + mmap_regions: Vec, // Later mapped regions + #[cfg(gdb)] debug: Option, #[cfg(gdb)] @@ -447,7 +451,8 @@ impl HypervLinuxDriver { page_size: 0, vm_fd, vcpu_fd, - mem_regions, + sandbox_regions: mem_regions, + mmap_regions: Vec::new(), entrypoint: entrypoint_ptr.absolute()?, orig_rsp: rsp_ptr, interrupt_handle: interrupt_handle.clone(), @@ -540,8 +545,11 @@ impl Debug for HypervLinuxDriver { f.field("Entrypoint", &self.entrypoint) .field("Original RSP", &self.orig_rsp); - for region in &self.mem_regions { - f.field("Memory Region", ®ion); + for region in &self.sandbox_regions { + f.field("Sandbox Memory Region", ®ion); + } + for region in &self.mmap_regions { + f.field("Mapped Memory Region", ®ion); } let regs = self.vcpu_fd.get_regs(); @@ -631,20 +639,24 @@ impl Hypervisor for HypervLinuxDriver { } let mshv_region: mshv_user_mem_region = rgn.to_owned().into(); self.vm_fd.map_user_memory(mshv_region)?; - self.mem_regions.push(rgn.to_owned()); + self.mmap_regions.push(rgn.to_owned()); Ok(()) } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - unsafe fn unmap_regions(&mut self, n: u64) -> Result<()> { - for rgn in self - .mem_regions - .split_off(self.mem_regions.len() - n as usize) - { - let mshv_region: mshv_user_mem_region = rgn.to_owned().into(); + unsafe fn unmap_region(&mut self, region: &MemoryRegion) -> Result<()> { + if let Some(pos) = self.mmap_regions.iter().position(|r| r == region) { + let removed_region = self.mmap_regions.remove(pos); + let mshv_region: mshv_user_mem_region = removed_region.into(); self.vm_fd.unmap_user_memory(mshv_region)?; + Ok(()) + } else { + Err(new_error!("Tried to unmap region that is not mapped")) } - Ok(()) + } + + fn get_mapped_regions(&self) -> Box + '_> { + Box::new(self.mmap_regions.iter()) } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] @@ -867,9 +879,9 @@ impl Hypervisor for HypervLinuxDriver { gpa, &self ); - match self.get_memory_access_violation( + match get_memory_access_violation( gpa as usize, - &self.mem_regions, + self.sandbox_regions.iter().chain(self.mmap_regions.iter()), access_info, ) { Some(access_info_violation) => access_info_violation, @@ -999,7 +1011,7 @@ impl Hypervisor for HypervLinuxDriver { }); Ok(Some(crashdump::CrashDumpContext::new( - &self.mem_regions, + &self.sandbox_regions, regs, xsave.buffer.to_vec(), self.entrypoint, @@ -1180,7 +1192,7 @@ impl Drop for HypervLinuxDriver { #[instrument(skip_all, parent = Span::current(), level = "Trace")] fn drop(&mut self) { self.interrupt_handle.dropped.store(true, Ordering::Relaxed); - for region in &self.mem_regions { + for region in self.sandbox_regions.iter().chain(self.mmap_regions.iter()) { let mshv_region: mshv_user_mem_region = region.to_owned().into(); match self.vm_fd.unmap_user_memory(mshv_region) { Ok(_) => (), diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index d4a0c06cd..0fc701a13 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -57,6 +57,7 @@ use super::{ }; use super::{HyperlightExit, Hypervisor, InterruptHandle, VirtualCPU}; use crate::hypervisor::fpu::FP_CONTROL_WORD_DEFAULT; +use crate::hypervisor::get_memory_access_violation; use crate::hypervisor::wrappers::WHvGeneralRegisters; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::{GuestPtr, RawPtr}; @@ -281,10 +282,13 @@ pub(crate) struct HypervWindowsDriver { _surrogate_process: SurrogateProcess, // we need to keep a reference to the SurrogateProcess for the duration of the driver since otherwise it will dropped and the memory mapping will be unmapped and the surrogate process will be returned to the pool entrypoint: u64, orig_rsp: GuestPtr, - mem_regions: Vec, interrupt_handle: Arc, mem_mgr: Option>, host_funcs: Option>>, + + sandbox_regions: Vec, // Initially mapped regions when sandbox is created + mmap_regions: Vec, // Later mapped regions + #[cfg(gdb)] debug: Option, #[cfg(gdb)] @@ -358,7 +362,8 @@ impl HypervWindowsDriver { _surrogate_process: surrogate_process, entrypoint, orig_rsp: GuestPtr::try_from(RawPtr::from(rsp))?, - mem_regions, + sandbox_regions: mem_regions, + mmap_regions: Vec::new(), interrupt_handle: interrupt_handle.clone(), mem_mgr: None, host_funcs: None, @@ -457,8 +462,11 @@ impl Debug for HypervWindowsDriver { fs.field("Entrypoint", &self.entrypoint) .field("Original RSP", &self.orig_rsp); - for region in &self.mem_regions { - fs.field("Memory Region", ®ion); + for region in &self.sandbox_regions { + fs.field("Sandbox Memory Region", ®ion); + } + for region in &self.mmap_regions { + fs.field("Mapped Memory Region", ®ion); } // Get the registers @@ -631,18 +639,17 @@ impl Hypervisor for HypervWindowsDriver { } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - unsafe fn map_region(&mut self, _rgn: &MemoryRegion) -> Result<()> { + unsafe fn map_region(&mut self, _region: &MemoryRegion) -> Result<()> { log_then_return!("Mapping host memory into the guest not yet supported on this platform"); } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - unsafe fn unmap_regions(&mut self, n: u64) -> Result<()> { - if n > 0 { - log_then_return!( - "Mapping host memory into the guest not yet supported on this platform" - ); - } - Ok(()) + unsafe fn unmap_region(&mut self, _region: &MemoryRegion) -> Result<()> { + log_then_return!("Mapping host memory into the guest not yet supported on this platform"); + } + + fn get_mapped_regions(&self) -> Box + '_> { + Box::new(self.mmap_regions.iter()) } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] @@ -824,8 +831,11 @@ impl Hypervisor for HypervWindowsDriver { gpa, access_info, &self ); - match self.get_memory_access_violation(gpa as usize, &self.mem_regions, access_info) - { + match get_memory_access_violation( + gpa as usize, + self.sandbox_regions.iter().chain(self.mmap_regions.iter()), + access_info, + ) { Some(access_info) => access_info, None => HyperlightExit::Mmio(gpa), } @@ -934,7 +944,7 @@ impl Hypervisor for HypervWindowsDriver { }); Ok(Some(crashdump::CrashDumpContext::new( - &self.mem_regions, + &self.sandbox_regions, regs, xsave, self.entrypoint, diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index 8a2de0d40..26eae3e25 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -42,6 +42,7 @@ use super::{ use super::{HyperlightExit, Hypervisor, InterruptHandle, LinuxInterruptHandle, VirtualCPU}; #[cfg(gdb)] use crate::HyperlightError; +use crate::hypervisor::get_memory_access_violation; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::{GuestPtr, RawPtr}; use crate::mem::shared_mem::HostSharedMemory; @@ -294,10 +295,15 @@ pub(crate) struct KVMDriver { vcpu_fd: VcpuFd, entrypoint: u64, orig_rsp: GuestPtr, - mem_regions: Vec, interrupt_handle: Arc, mem_mgr: Option>, host_funcs: Option>>, + + sandbox_regions: Vec, // Initially mapped regions when sandbox is created + mmap_regions: Vec<(MemoryRegion, u32)>, // Later mapped regions (region, slot number) + next_slot: u32, // Monotonically increasing slot number + freed_slots: Vec, // Reusable slots from unmapped regions + #[cfg(gdb)] debug: Option, #[cfg(gdb)] @@ -384,7 +390,10 @@ impl KVMDriver { vcpu_fd, entrypoint, orig_rsp: rsp_gp, - mem_regions, + next_slot: mem_regions.len() as u32, + sandbox_regions: mem_regions, + mmap_regions: Vec::new(), + freed_slots: Vec::new(), interrupt_handle: interrupt_handle.clone(), mem_mgr: None, host_funcs: None, @@ -434,8 +443,11 @@ impl Debug for KVMDriver { let mut f = f.debug_struct("KVM Driver"); // Output each memory region - for region in &self.mem_regions { - f.field("Memory Region", ®ion); + for region in &self.sandbox_regions { + f.field("Sandbox Memory Region", ®ion); + } + for region in &self.mmap_regions { + f.field("Mapped Memory Region", ®ion); } let regs = self.vcpu_fd.get_regs(); // check that regs is OK and then set field in debug struct @@ -517,25 +529,45 @@ impl Hypervisor for KVMDriver { } let mut kvm_region: kvm_userspace_memory_region = region.clone().into(); - kvm_region.slot = self.mem_regions.len() as u32; + + // Try to reuse a freed slot first, otherwise use next_slot + let slot = if let Some(freed_slot) = self.freed_slots.pop() { + freed_slot + } else { + let slot = self.next_slot; + self.next_slot += 1; + slot + }; + + kvm_region.slot = slot; unsafe { self.vm_fd.set_user_memory_region(kvm_region) }?; - self.mem_regions.push(region.to_owned()); + self.mmap_regions.push((region.to_owned(), slot)); Ok(()) } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - unsafe fn unmap_regions(&mut self, n: u64) -> Result<()> { - let n_keep = self.mem_regions.len() - n as usize; - for (k, region) in self.mem_regions.split_off(n_keep).iter().enumerate() { - let mut kvm_region: kvm_userspace_memory_region = region.clone().into(); - kvm_region.slot = (n_keep + k) as u32; + unsafe fn unmap_region(&mut self, region: &MemoryRegion) -> Result<()> { + if let Some(idx) = self.mmap_regions.iter().position(|(r, _)| r == region) { + let (region, slot) = self.mmap_regions.remove(idx); + let mut kvm_region: kvm_userspace_memory_region = region.into(); + kvm_region.slot = slot; // Setting memory_size to 0 unmaps the slot's region // From https://docs.kernel.org/virt/kvm/api.html // > Deleting a slot is done by passing zero for memory_size. kvm_region.memory_size = 0; unsafe { self.vm_fd.set_user_memory_region(kvm_region) }?; + + // Add the freed slot to the reuse list + self.freed_slots.push(slot); + + Ok(()) + } else { + Err(new_error!("Tried to unmap region that is not mapped")) } - Ok(()) + } + + fn get_mapped_regions(&self) -> Box + '_> { + Box::new(self.mmap_regions.iter().map(|(region, _)| region)) } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] @@ -717,9 +749,11 @@ impl Hypervisor for KVMDriver { Ok(VcpuExit::MmioRead(addr, _)) => { crate::debug!("KVM MMIO Read -Details: Address: {} \n {:#?}", addr, &self); - match self.get_memory_access_violation( + match get_memory_access_violation( addr as usize, - &self.mem_regions, + self.sandbox_regions + .iter() + .chain(self.mmap_regions.iter().map(|(r, _)| r)), MemoryRegionFlags::READ, ) { Some(access_violation_exit) => access_violation_exit, @@ -729,9 +763,11 @@ impl Hypervisor for KVMDriver { Ok(VcpuExit::MmioWrite(addr, _)) => { crate::debug!("KVM MMIO Write -Details: Address: {} \n {:#?}", addr, &self); - match self.get_memory_access_violation( + match get_memory_access_violation( addr as usize, - &self.mem_regions, + self.sandbox_regions + .iter() + .chain(self.mmap_regions.iter().map(|(r, _)| r)), MemoryRegionFlags::WRITE, ) { Some(access_violation_exit) => access_violation_exit, @@ -847,7 +883,7 @@ impl Hypervisor for KVMDriver { // The [`CrashDumpContext`] accepts xsave as a vector of u8, so we need to convert the // xsave region to a vector of u8 Ok(Some(crashdump::CrashDumpContext::new( - &self.mem_regions, + &self.sandbox_regions, regs, xsave .region diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index 0fe452b6e..53b721c7c 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -157,8 +157,13 @@ pub(crate) trait Hypervisor: Debug + Send { /// requirements of at least one page for base and len. unsafe fn map_region(&mut self, rgn: &MemoryRegion) -> Result<()>; - /// Unmap the most recent `n` regions mapped by `map_region` - unsafe fn unmap_regions(&mut self, n: u64) -> Result<()>; + /// Unmap a memory region from the sandbox + unsafe fn unmap_region(&mut self, rgn: &MemoryRegion) -> Result<()>; + + /// Get the currently mapped dynamic memory regions (not including sandbox regions) + /// + /// Note: Box needed for trait to be object-safe :( + fn get_mapped_regions(&self) -> Box + '_>; /// Dispatch a call from the host to the guest using the given pointer /// to the dispatch function _in the guest's address space_. @@ -185,33 +190,6 @@ pub(crate) trait Hypervisor: Debug + Send { /// Run the vCPU fn run(&mut self) -> Result; - /// Returns a Some(HyperlightExit::AccessViolation(..)) if the given gpa doesn't have - /// access its corresponding region. Returns None otherwise, or if the region is not found. - fn get_memory_access_violation( - &self, - gpa: usize, - mem_regions: &[MemoryRegion], - access_info: MemoryRegionFlags, - ) -> Option { - // find the region containing the given gpa - let region = mem_regions - .iter() - .find(|region| region.guest_region.contains(&gpa)); - - if let Some(region) = region { - if !region.flags.contains(access_info) - || region.flags.contains(MemoryRegionFlags::STACK_GUARD) - { - return Some(HyperlightExit::AccessViolation( - gpa as u64, - access_info, - region.flags, - )); - } - } - None - } - /// Get InterruptHandle to underlying VM fn interrupt_handle(&self) -> Arc; @@ -283,6 +261,30 @@ pub(crate) trait Hypervisor: Debug + Send { fn trace_info_as_mut(&mut self) -> &mut TraceInfo; } +/// Returns a Some(HyperlightExit::AccessViolation(..)) if the given gpa doesn't have +/// access its corresponding region. Returns None otherwise, or if the region is not found. +pub(crate) fn get_memory_access_violation<'a>( + gpa: usize, + mut mem_regions: impl Iterator, + access_info: MemoryRegionFlags, +) -> Option { + // find the region containing the given gpa + let region = mem_regions.find(|region| region.guest_region.contains(&gpa)); + + if let Some(region) = region { + if !region.flags.contains(access_info) + || region.flags.contains(MemoryRegionFlags::STACK_GUARD) + { + return Some(HyperlightExit::AccessViolation( + gpa as u64, + access_info, + region.flags, + )); + } + } + None +} + /// A virtual CPU that can be run until an exit occurs pub struct VirtualCPU {} diff --git a/src/hyperlight_host/src/mem/memory_region.rs b/src/hyperlight_host/src/mem/memory_region.rs index f4c38b168..22f71d65b 100644 --- a/src/hyperlight_host/src/mem/memory_region.rs +++ b/src/hyperlight_host/src/mem/memory_region.rs @@ -52,7 +52,7 @@ pub(crate) const DEFAULT_GUEST_BLOB_MEM_FLAGS: MemoryRegionFlags = MemoryRegionF bitflags! { /// flags representing memory permission for a memory region - #[derive(Copy, Clone, Debug, PartialEq, Eq)] + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct MemoryRegionFlags: u32 { /// no permissions const NONE = 0; @@ -154,7 +154,7 @@ impl TryFrom for MemoryRegionFlags { } // only used for debugging -#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] /// The type of memory region pub enum MemoryRegionType { /// The region contains the guest's page tables @@ -181,7 +181,7 @@ pub enum MemoryRegionType { /// represents a single memory region inside the guest. All memory within a region has /// the same memory permissions -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct MemoryRegion { /// the range of guest memory addresses pub guest_region: Range, diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 4e4aa0112..526190d4c 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -27,8 +27,9 @@ use tracing::{Span, instrument}; use super::exe::ExeInfo; use super::layout::SandboxMemoryLayout; +use super::memory_region::MemoryRegion; #[cfg(feature = "init-paging")] -use super::memory_region::{DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegion, MemoryRegionType}; +use super::memory_region::{DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegionType}; use super::ptr::{GuestPtr, RawPtr}; use super::ptr_offset::Offset; use super::shared_mem::{ExclusiveSharedMemory, GuestSharedMemory, HostSharedMemory, SharedMemory}; @@ -259,16 +260,16 @@ where } } - pub(crate) fn snapshot(&mut self) -> Result { - SharedMemorySnapshot::new(&mut self.shared_mem, self.mapped_rgns) + /// Create a snapshot with the given mapped regions + pub(crate) fn snapshot( + &mut self, + mapped_regions: Vec, + ) -> Result { + SharedMemorySnapshot::new(&mut self.shared_mem, mapped_regions) } /// This function restores a memory snapshot from a given snapshot. - /// - /// Returns the number of memory regions mapped into the sandbox - /// that need to be unmapped in order for the restore to be - /// completed. - pub(crate) fn restore_snapshot(&mut self, snapshot: &SharedMemorySnapshot) -> Result { + pub(crate) fn restore_snapshot(&mut self, snapshot: &SharedMemorySnapshot) -> Result<()> { if self.shared_mem.mem_size() != snapshot.mem_size() { return Err(new_error!( "Snapshot size does not match current memory size: {} != {}", @@ -276,9 +277,8 @@ where snapshot.mem_size() )); } - let old_rgns = self.mapped_rgns; - self.mapped_rgns = snapshot.restore_from_snapshot(&mut self.shared_mem)?; - Ok(old_rgns - self.mapped_rgns) + snapshot.restore_from_snapshot(&mut self.shared_mem)?; + Ok(()) } /// Sets `addr` to the correct offset in the memory referenced by diff --git a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs index dfa54430c..8f55a8b25 100644 --- a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs +++ b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs @@ -16,6 +16,7 @@ limitations under the License. use tracing::{Span, instrument}; +use super::memory_region::MemoryRegion; use super::shared_mem::SharedMemory; use crate::Result; @@ -24,21 +25,21 @@ use crate::Result; #[derive(Clone)] pub(crate) struct SharedMemorySnapshot { snapshot: Vec, - /// How many non-main-RAM regions were mapped when this snapshot was taken? - mapped_rgns: u64, + /// The memory regions that were mapped when this snapshot was taken (excluding initial sandbox regions) + regions: Vec, } impl SharedMemorySnapshot { /// Take a snapshot of the memory in `shared_mem`, then create a new /// instance of `Self` with the snapshot stored therein. #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - pub(super) fn new(shared_mem: &mut S, mapped_rgns: u64) -> Result { + pub(super) fn new( + shared_mem: &mut S, + regions: Vec, + ) -> Result { // TODO: Track dirty pages instead of copying entire memory let snapshot = shared_mem.with_exclusivity(|e| e.copy_all_to_vec())??; - Ok(Self { - snapshot, - mapped_rgns, - }) + Ok(Self { snapshot, regions }) } /// Take another snapshot of the internally-stored `SharedMemory`, @@ -51,11 +52,16 @@ impl SharedMemorySnapshot { } /// Copy the memory from the internally-stored memory snapshot - /// into the internally-stored `SharedMemory` + /// into the internally-stored `SharedMemory`. #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - pub(super) fn restore_from_snapshot(&self, shared_mem: &mut S) -> Result { + pub(super) fn restore_from_snapshot(&self, shared_mem: &mut S) -> Result<()> { shared_mem.with_exclusivity(|e| e.copy_from_slice(self.snapshot.as_slice(), 0))??; - Ok(self.mapped_rgns) + Ok(()) + } + + /// Get the mapped regions from this snapshot + pub(crate) fn regions(&self) -> &[MemoryRegion] { + &self.regions } /// Return the size of the snapshot in bytes. @@ -78,7 +84,7 @@ mod tests { let data2 = data1.iter().map(|b| b + 1).collect::>(); let mut gm = ExclusiveSharedMemory::new(PAGE_SIZE_USIZE).unwrap(); gm.copy_from_slice(data1.as_slice(), 0).unwrap(); - let mut snap = super::SharedMemorySnapshot::new(&mut gm, 0).unwrap(); + let mut snap = super::SharedMemorySnapshot::new(&mut gm, Vec::new()).unwrap(); { // after the first snapshot is taken, make sure gm has the equivalent // of data1 diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index f9514dcd2..b21ab6361 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +use std::collections::HashSet; #[cfg(unix)] use std::os::fd::AsRawFd; #[cfg(unix)] @@ -88,18 +89,35 @@ impl MultiUseSandbox { /// Create a snapshot of the current state of the sandbox's memory. #[instrument(err(Debug), skip_all, parent = Span::current())] pub fn snapshot(&mut self) -> Result { - let snapshot = self.mem_mgr.unwrap_mgr_mut().snapshot()?; - Ok(Snapshot { inner: snapshot }) + let mapped_regions_iter = self.vm.get_mapped_regions(); + let mapped_regions_vec: Vec = mapped_regions_iter.cloned().collect(); + let memory_snapshot = self.mem_mgr.unwrap_mgr_mut().snapshot(mapped_regions_vec)?; + Ok(Snapshot { + inner: memory_snapshot, + }) } /// Restore the sandbox's memory to the state captured in the given snapshot. #[instrument(err(Debug), skip_all, parent = Span::current())] pub fn restore(&mut self, snapshot: &Snapshot) -> Result<()> { - let rgns_to_unmap = self - .mem_mgr + self.mem_mgr .unwrap_mgr_mut() .restore_snapshot(&snapshot.inner)?; - unsafe { self.vm.unmap_regions(rgns_to_unmap)? }; + + let current_regions: HashSet<_> = self.vm.get_mapped_regions().cloned().collect(); + let snapshot_regions: HashSet<_> = snapshot.inner.regions().iter().cloned().collect(); + + let regions_to_unmap = current_regions.difference(&snapshot_regions); + let regions_to_map = snapshot_regions.difference(¤t_regions); + + for region in regions_to_unmap { + unsafe { self.vm.unmap_region(region)? }; + } + + for region in regions_to_map { + unsafe { self.vm.map_region(region)? }; + } + Ok(()) } @@ -694,4 +712,57 @@ mod tests { region_type: MemoryRegionType::Heap, } } + + #[cfg(target_os = "linux")] + fn allocate_guest_memory() -> GuestSharedMemory { + page_aligned_memory(b"test data for snapshot") + } + + #[test] + #[cfg(target_os = "linux")] + fn snapshot_restore_handles_remapping_correctly() { + let mut sbox: MultiUseSandbox = { + let path = simple_guest_as_string().unwrap(); + let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap(); + u_sbox.evolve().unwrap() + }; + + // 1. Take snapshot 1 with no additional regions mapped + let snapshot1 = sbox.snapshot().unwrap(); + assert_eq!(sbox.vm.get_mapped_regions().len(), 0); + + // 2. Map a memory region + let map_mem = allocate_guest_memory(); + let guest_base = 0x200000000_usize; + let region = region_for_memory(&map_mem, guest_base, MemoryRegionFlags::READ); + + unsafe { sbox.map_region(®ion).unwrap() }; + assert_eq!(sbox.vm.get_mapped_regions().len(), 1); + + // 3. Take snapshot 2 with 1 region mapped + let snapshot2 = sbox.snapshot().unwrap(); + assert_eq!(sbox.vm.get_mapped_regions().len(), 1); + + // 4. Restore to snapshot 1 (should unmap the region) + sbox.restore(&snapshot1).unwrap(); + assert_eq!(sbox.vm.get_mapped_regions().len(), 0); + + // 5. Restore forward to snapshot 2 (should remap the region) + sbox.restore(&snapshot2).unwrap(); + assert_eq!(sbox.vm.get_mapped_regions().len(), 1); + + // Verify the region is the same + let mut restored_regions = sbox.vm.get_mapped_regions(); + assert_eq!(*restored_regions.next().unwrap(), region); + assert!(restored_regions.next().is_none()); + drop(restored_regions); + + // 6. Try map the region again (should fail since already mapped) + let err = unsafe { sbox.map_region(®ion) }; + assert!( + err.is_err(), + "Expected error when remapping existing region: {:?}", + err + ); + } } From f99e33fdcaf2e143b732798e7c424958d1c04351 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Wed, 30 Jul 2025 14:25:15 -0700 Subject: [PATCH 068/271] Ensure sandboxes can only restore to snapshots taken from the same sandbox (#746) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- src/hyperlight_host/src/error.rs | 4 ++ src/hyperlight_host/src/mem/mgr.rs | 3 +- .../src/mem/shared_mem_snapshot.rs | 17 ++++++- .../src/sandbox/initialized_multi_use.rs | 49 ++++++++++++++++++- 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/hyperlight_host/src/error.rs b/src/hyperlight_host/src/error.rs index df8ee8a37..951066c53 100644 --- a/src/hyperlight_host/src/error.rs +++ b/src/hyperlight_host/src/error.rs @@ -221,6 +221,10 @@ pub enum HyperlightError { #[cfg(all(feature = "seccomp", target_os = "linux"))] SeccompFilterError(#[from] seccompiler::Error), + /// Tried to restore snapshot to a sandbox that is not the same as the one the snapshot was taken from + #[error("Snapshot was taken from a different sandbox")] + SnapshotSandboxMismatch, + /// SystemTimeError #[error("SystemTimeError {0:?}")] SystemTimeError(#[from] SystemTimeError), diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 526190d4c..e33c4b08d 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -263,9 +263,10 @@ where /// Create a snapshot with the given mapped regions pub(crate) fn snapshot( &mut self, + sandbox_id: u64, mapped_regions: Vec, ) -> Result { - SharedMemorySnapshot::new(&mut self.shared_mem, mapped_regions) + SharedMemorySnapshot::new(&mut self.shared_mem, sandbox_id, mapped_regions) } /// This function restores a memory snapshot from a given snapshot. diff --git a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs index 8f55a8b25..49af2d99d 100644 --- a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs +++ b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs @@ -24,6 +24,9 @@ use crate::Result; /// of the memory therein #[derive(Clone)] pub(crate) struct SharedMemorySnapshot { + // Unique ID of the sandbox this snapshot was taken from + sandbox_id: u64, + // Memory of the sandbox at the time this snapshot was taken snapshot: Vec, /// The memory regions that were mapped when this snapshot was taken (excluding initial sandbox regions) regions: Vec, @@ -35,11 +38,16 @@ impl SharedMemorySnapshot { #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] pub(super) fn new( shared_mem: &mut S, + sandbox_id: u64, regions: Vec, ) -> Result { // TODO: Track dirty pages instead of copying entire memory let snapshot = shared_mem.with_exclusivity(|e| e.copy_all_to_vec())??; - Ok(Self { snapshot, regions }) + Ok(Self { + sandbox_id, + snapshot, + regions, + }) } /// Take another snapshot of the internally-stored `SharedMemory`, @@ -59,6 +67,11 @@ impl SharedMemorySnapshot { Ok(()) } + /// The id of the sandbox this snapshot was taken from. + pub(crate) fn sandbox_id(&self) -> u64 { + self.sandbox_id + } + /// Get the mapped regions from this snapshot pub(crate) fn regions(&self) -> &[MemoryRegion] { &self.regions @@ -84,7 +97,7 @@ mod tests { let data2 = data1.iter().map(|b| b + 1).collect::>(); let mut gm = ExclusiveSharedMemory::new(PAGE_SIZE_USIZE).unwrap(); gm.copy_from_slice(data1.as_slice(), 0).unwrap(); - let mut snap = super::SharedMemorySnapshot::new(&mut gm, Vec::new()).unwrap(); + let mut snap = super::SharedMemorySnapshot::new(&mut gm, 0, Vec::new()).unwrap(); { // after the first snapshot is taken, make sure gm has the equivalent // of data1 diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index b21ab6361..6b925f264 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -20,6 +20,7 @@ use std::os::fd::AsRawFd; #[cfg(unix)] use std::os::linux::fs::MetadataExt; use std::path::Path; +use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::{Arc, Mutex}; use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType}; @@ -31,6 +32,7 @@ use tracing::{Span, instrument}; use super::host_funcs::FunctionRegistry; use super::snapshot::Snapshot; use super::{Callable, MemMgrWrapper, WrapperGetter}; +use crate::HyperlightError::SnapshotSandboxMismatch; use crate::func::guest_err::check_for_guest_error; use crate::func::{ParameterTuple, SupportedReturnType}; #[cfg(gdb)] @@ -44,6 +46,9 @@ use crate::mem::shared_mem::HostSharedMemory; use crate::metrics::maybe_time_and_emit_guest_call; use crate::{HyperlightError, Result, log_then_return}; +/// Global counter for assigning unique IDs to sandboxes +static SANDBOX_ID_COUNTER: AtomicU64 = AtomicU64::new(0); + /// A sandbox that supports being used Multiple times. /// The implication of being used multiple times is two-fold: /// @@ -53,6 +58,8 @@ use crate::{HyperlightError, Result, log_then_return}; /// 2. A MultiUseGuestCallContext can be created from the sandbox and used to make multiple guest function calls to the Sandbox. /// in this case the state of the sandbox is not reset until the context is finished and the `MultiUseSandbox` is returned. pub struct MultiUseSandbox { + /// Unique identifier for this sandbox instance + id: u64, // We need to keep a reference to the host functions, even if the compiler marks it as unused. The compiler cannot detect our dynamic usages of the host function in `HyperlightFunction::call`. pub(super) _host_funcs: Arc>, pub(crate) mem_mgr: MemMgrWrapper, @@ -77,6 +84,7 @@ impl MultiUseSandbox { #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, ) -> MultiUseSandbox { Self { + id: SANDBOX_ID_COUNTER.fetch_add(1, Ordering::Relaxed), _host_funcs: host_funcs, mem_mgr: mgr, vm, @@ -91,7 +99,10 @@ impl MultiUseSandbox { pub fn snapshot(&mut self) -> Result { let mapped_regions_iter = self.vm.get_mapped_regions(); let mapped_regions_vec: Vec = mapped_regions_iter.cloned().collect(); - let memory_snapshot = self.mem_mgr.unwrap_mgr_mut().snapshot(mapped_regions_vec)?; + let memory_snapshot = self + .mem_mgr + .unwrap_mgr_mut() + .snapshot(self.id, mapped_regions_vec)?; Ok(Snapshot { inner: memory_snapshot, }) @@ -100,6 +111,10 @@ impl MultiUseSandbox { /// Restore the sandbox's memory to the state captured in the given snapshot. #[instrument(err(Debug), skip_all, parent = Span::current())] pub fn restore(&mut self, snapshot: &Snapshot) -> Result<()> { + if self.id != snapshot.inner.sandbox_id() { + return Err(SnapshotSandboxMismatch); + } + self.mem_mgr .unwrap_mgr_mut() .restore_snapshot(&snapshot.inner)?; @@ -765,4 +780,36 @@ mod tests { err ); } + + #[test] + fn snapshot_different_sandbox() { + let mut sandbox = { + let path = simple_guest_as_string().unwrap(); + let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap(); + u_sbox.evolve().unwrap() + }; + + let mut sandbox2 = { + let path = simple_guest_as_string().unwrap(); + let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap(); + u_sbox.evolve().unwrap() + }; + assert_ne!(sandbox.id, sandbox2.id); + + let snapshot = sandbox.snapshot().unwrap(); + let err = sandbox2.restore(&snapshot); + assert!(matches!(err, Err(HyperlightError::SnapshotSandboxMismatch))); + + let sandbox_id = sandbox.id; + drop(sandbox); + drop(sandbox2); + drop(snapshot); + + let sandbox3 = { + let path = simple_guest_as_string().unwrap(); + let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap(); + u_sbox.evolve().unwrap() + }; + assert_ne!(sandbox3.id, sandbox_id); + } } From 06267cd3d633a2173cd80789bc842e9711f40bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Thu, 31 Jul 2025 11:06:00 +0300 Subject: [PATCH 069/271] Re-export macros in hyperlight_guest_tracing (#734) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Re-export macros in hyperlight_guest_tracing for ease of use Signed-off-by: Doru Blânzeanu * update Cargo.toml to reflect latest versions Signed-off-by: Doru Blânzeanu --------- Signed-off-by: Doru Blânzeanu --- Cargo.lock | 4 +- src/hyperlight_guest/Cargo.toml | 5 +- src/hyperlight_guest/src/exit.rs | 16 ++--- .../src/guest_handle/host_comm.rs | 14 ++--- src/hyperlight_guest/src/guest_handle/io.rs | 8 +-- src/hyperlight_guest_bin/Cargo.toml | 5 +- .../src/exceptions/gdt.rs | 2 +- .../src/exceptions/handler.rs | 4 +- .../src/exceptions/idt.rs | 2 +- .../src/exceptions/idtr.rs | 2 +- .../src/guest_function/call.rs | 10 ++-- src/hyperlight_guest_bin/src/lib.rs | 2 +- src/hyperlight_guest_bin/src/paging.rs | 1 + src/hyperlight_guest_tracing/Cargo.toml | 1 + src/hyperlight_guest_tracing/src/lib.rs | 4 ++ src/hyperlight_guest_tracing_macro/Cargo.toml | 1 - src/hyperlight_guest_tracing_macro/src/lib.rs | 60 +++++++++---------- .../rust_guests/callbackguest/Cargo.lock | 4 +- src/tests/rust_guests/dummyguest/Cargo.lock | 4 +- src/tests/rust_guests/simpleguest/Cargo.lock | 4 +- src/tests/rust_guests/witguest/Cargo.lock | 4 +- 21 files changed, 75 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15c2068da..6f3b94fd4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1390,7 +1390,6 @@ dependencies = [ "anyhow", "hyperlight-common", "hyperlight-guest-tracing", - "hyperlight-guest-tracing-macro", "serde_json", ] @@ -1405,7 +1404,6 @@ dependencies = [ "hyperlight-common", "hyperlight-guest", "hyperlight-guest-tracing", - "hyperlight-guest-tracing-macro", "log", "spin 0.10.0", ] @@ -1415,6 +1413,7 @@ name = "hyperlight-guest-tracing" version = "0.7.0" dependencies = [ "hyperlight-common", + "hyperlight-guest-tracing-macro", "spin 0.10.0", ] @@ -1422,7 +1421,6 @@ dependencies = [ name = "hyperlight-guest-tracing-macro" version = "0.7.0" dependencies = [ - "hyperlight-guest-tracing", "proc-macro2", "quote", "syn", diff --git a/src/hyperlight_guest/Cargo.toml b/src/hyperlight_guest/Cargo.toml index d55aa4f92..5788bedc6 100644 --- a/src/hyperlight_guest/Cargo.toml +++ b/src/hyperlight_guest/Cargo.toml @@ -15,9 +15,8 @@ Provides only the essential building blocks for interacting with the host enviro anyhow = { version = "1.0.98", default-features = false } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } hyperlight-common = { workspace = true } -hyperlight-guest-tracing = { workspace = true, optional = true } -hyperlight-guest-tracing-macro = { workspace = true} +hyperlight-guest-tracing = { workspace = true } [features] default = [] -trace_guest = ["dep:hyperlight-guest-tracing"] +trace_guest = [] diff --git a/src/hyperlight_guest/src/exit.rs b/src/hyperlight_guest/src/exit.rs index 42a9cc0fd..715086c7b 100644 --- a/src/hyperlight_guest/src/exit.rs +++ b/src/hyperlight_guest/src/exit.rs @@ -21,22 +21,22 @@ use hyperlight_common::outb::OutBAction; /// Halt the execution of the guest and returns control to the host. #[inline(never)] -#[hyperlight_guest_tracing_macro::trace_function] +#[hyperlight_guest_tracing::trace_function] pub fn halt() { // Ensure all tracing data is flushed before halting - hyperlight_guest_tracing_macro::flush!(); + hyperlight_guest_tracing::flush!(); unsafe { asm!("hlt", options(nostack)) } } /// Exits the VM with an Abort OUT action and code 0. #[unsafe(no_mangle)] -#[hyperlight_guest_tracing_macro::trace_function] +#[hyperlight_guest_tracing::trace_function] pub extern "C" fn abort() -> ! { abort_with_code(&[0, 0xFF]) } /// Exits the VM with an Abort OUT action and a specific code. -#[hyperlight_guest_tracing_macro::trace_function] +#[hyperlight_guest_tracing::trace_function] pub fn abort_with_code(code: &[u8]) -> ! { outb(OutBAction::Abort as u16, code); outb(OutBAction::Abort as u16, &[0xFF]); // send abort terminator (if not included in code) @@ -47,7 +47,7 @@ pub fn abort_with_code(code: &[u8]) -> ! { /// /// # Safety /// This function is unsafe because it dereferences a raw pointer. -#[hyperlight_guest_tracing_macro::trace_function] +#[hyperlight_guest_tracing::trace_function] pub unsafe fn abort_with_code_and_message(code: &[u8], message_ptr: *const c_char) -> ! { unsafe { // Step 1: Send abort code (typically 1 byte, but `code` allows flexibility) @@ -68,10 +68,10 @@ pub unsafe fn abort_with_code_and_message(code: &[u8], message_ptr: *const c_cha } /// OUT bytes to the host through multiple exits. -#[hyperlight_guest_tracing_macro::trace_function] +#[hyperlight_guest_tracing::trace_function] pub(crate) fn outb(port: u16, data: &[u8]) { // Ensure all tracing data is flushed before sending OUT bytes - hyperlight_guest_tracing_macro::flush!(); + hyperlight_guest_tracing::flush!(); unsafe { let mut i = 0; while i < data.len() { @@ -88,7 +88,7 @@ pub(crate) fn outb(port: u16, data: &[u8]) { } /// OUT function for sending a 32-bit value to the host. -#[hyperlight_guest_tracing_macro::trace_function] +#[hyperlight_guest_tracing::trace_function] pub(crate) unsafe fn out32(port: u16, val: u32) { unsafe { asm!("out dx, eax", in("dx") port, in("eax") val, options(preserves_flags, nomem, nostack)); diff --git a/src/hyperlight_guest/src/guest_handle/host_comm.rs b/src/hyperlight_guest/src/guest_handle/host_comm.rs index d5cf57ffa..5719417ab 100644 --- a/src/hyperlight_guest/src/guest_handle/host_comm.rs +++ b/src/hyperlight_guest/src/guest_handle/host_comm.rs @@ -35,7 +35,7 @@ use crate::exit::out32; impl GuestHandle { /// Get user memory region as bytes. - #[hyperlight_guest_tracing_macro::trace_function] + #[hyperlight_guest_tracing::trace_function] pub fn read_n_bytes_from_user_memory(&self, num: u64) -> Result> { let peb_ptr = self.peb().unwrap(); let user_memory_region_ptr = unsafe { (*peb_ptr).init_data.ptr as *mut u8 }; @@ -64,7 +64,7 @@ impl GuestHandle { /// /// When calling `call_host_function`, this function is called /// internally to get the return value. - #[hyperlight_guest_tracing_macro::trace_function] + #[hyperlight_guest_tracing::trace_function] pub fn get_host_return_value>(&self) -> Result { let return_value = self .try_pop_shared_input_data_into::() @@ -85,7 +85,7 @@ impl GuestHandle { /// /// Note: The function return value must be obtained by calling /// `get_host_return_value`. - #[hyperlight_guest_tracing_macro::trace_function] + #[hyperlight_guest_tracing::trace_function] pub fn call_host_function_without_returning_result( &self, function_name: &str, @@ -117,7 +117,7 @@ impl GuestHandle { /// sends it to the host, and then retrieves the return value. /// /// The return value is deserialized into the specified type `T`. - #[hyperlight_guest_tracing_macro::trace_function] + #[hyperlight_guest_tracing::trace_function] pub fn call_host_function>( &self, function_name: &str, @@ -128,7 +128,7 @@ impl GuestHandle { self.get_host_return_value::() } - #[hyperlight_guest_tracing_macro::trace_function] + #[hyperlight_guest_tracing::trace_function] pub fn get_host_function_details(&self) -> HostFunctionDetails { let peb_ptr = self.peb().unwrap(); let host_function_details_buffer = @@ -145,7 +145,7 @@ impl GuestHandle { } /// Write an error to the shared output data buffer. - #[hyperlight_guest_tracing_macro::trace_function] + #[hyperlight_guest_tracing::trace_function] pub fn write_error(&self, error_code: ErrorCode, message: Option<&str>) { let guest_error: GuestError = GuestError::new( error_code, @@ -161,7 +161,7 @@ impl GuestHandle { } /// Log a message with the specified log level, source, caller, source file, and line number. - #[hyperlight_guest_tracing_macro::trace_function] + #[hyperlight_guest_tracing::trace_function] pub fn log_message( &self, log_level: LogLevel, diff --git a/src/hyperlight_guest/src/guest_handle/io.rs b/src/hyperlight_guest/src/guest_handle/io.rs index 4654f0001..759c88880 100644 --- a/src/hyperlight_guest/src/guest_handle/io.rs +++ b/src/hyperlight_guest/src/guest_handle/io.rs @@ -27,7 +27,7 @@ use crate::error::{HyperlightGuestError, Result}; impl GuestHandle { /// Pops the top element from the shared input data buffer and returns it as a T - #[hyperlight_guest_tracing_macro::trace_function] + #[hyperlight_guest_tracing::trace_function] pub fn try_pop_shared_input_data_into(&self) -> Result where T: for<'a> TryFrom<&'a [u8]>, @@ -69,7 +69,7 @@ impl GuestHandle { let buffer = &idb[last_element_offset_rel as usize..]; // convert the buffer to T - let type_t = hyperlight_guest_tracing_macro::trace!( + let type_t = hyperlight_guest_tracing::trace!( "convert buffer", match T::try_from(buffer) { Ok(t) => Ok(t), @@ -92,7 +92,7 @@ impl GuestHandle { } /// Pushes the given data onto the shared output data buffer. - #[hyperlight_guest_tracing_macro::trace_function] + #[hyperlight_guest_tracing::trace_function] pub fn push_shared_output_data(&self, data: Vec) -> Result<()> { let peb_ptr = self.peb().unwrap(); let output_stack_size = unsafe { (*peb_ptr).output_stack.size as usize }; @@ -138,7 +138,7 @@ impl GuestHandle { } // write the actual data - hyperlight_guest_tracing_macro::trace!("copy data", { + hyperlight_guest_tracing::trace!("copy data", { odb[stack_ptr_rel as usize..stack_ptr_rel as usize + data.len()].copy_from_slice(&data); }); diff --git a/src/hyperlight_guest_bin/Cargo.toml b/src/hyperlight_guest_bin/Cargo.toml index 90e80bff9..83ac2a454 100644 --- a/src/hyperlight_guest_bin/Cargo.toml +++ b/src/hyperlight_guest_bin/Cargo.toml @@ -17,14 +17,13 @@ and third-party code used by our C-API needed to build a native hyperlight-guest default = ["libc", "printf"] libc = [] # compile musl libc printf = [ "libc" ] # compile printf -trace_guest = ["hyperlight-common/trace_guest", "dep:hyperlight-guest-tracing", "hyperlight-guest/trace_guest"] +trace_guest = ["hyperlight-common/trace_guest", "hyperlight-guest/trace_guest"] mem_profile = ["hyperlight-common/unwind_guest","hyperlight-common/mem_profile"] [dependencies] hyperlight-guest = { workspace = true, default-features = false } hyperlight-common = { workspace = true, default-features = false } -hyperlight-guest-tracing = { workspace = true, optional = true } -hyperlight-guest-tracing-macro = { workspace = true } +hyperlight-guest-tracing = { workspace = true } buddy_system_allocator = "0.11.0" log = { version = "0.4", default-features = false } spin = "0.10.0" diff --git a/src/hyperlight_guest_bin/src/exceptions/gdt.rs b/src/hyperlight_guest_bin/src/exceptions/gdt.rs index 0da032321..38bdf183e 100644 --- a/src/hyperlight_guest_bin/src/exceptions/gdt.rs +++ b/src/hyperlight_guest_bin/src/exceptions/gdt.rs @@ -72,7 +72,7 @@ struct GdtPointer { } /// Load the GDT -#[hyperlight_guest_tracing_macro::trace_function] +#[hyperlight_guest_tracing::trace_function] pub unsafe fn load_gdt() { unsafe { let gdt_ptr = GdtPointer { diff --git a/src/hyperlight_guest_bin/src/exceptions/handler.rs b/src/hyperlight_guest_bin/src/exceptions/handler.rs index b2cae2c4f..838cd582b 100644 --- a/src/hyperlight_guest_bin/src/exceptions/handler.rs +++ b/src/hyperlight_guest_bin/src/exceptions/handler.rs @@ -69,7 +69,7 @@ pub extern "C" fn hl_exception_handler( // call, which generates a warning because of the `abort_with_code_and_message` call which does // not return. // This is manually added to avoid the warning. - hyperlight_guest_tracing_macro::trace!("> hl_exception_handler"); + hyperlight_guest_tracing::trace!("> hl_exception_handler"); let ctx = stack_pointer as *mut Context; let exn_info = (stack_pointer + size_of::() as u64) as *mut ExceptionInfo; @@ -101,7 +101,7 @@ pub extern "C" fn hl_exception_handler( )(exception_number, exn_info, ctx, page_fault_address) } { - hyperlight_guest_tracing_macro::trace!("< hl_exception_handler"); + hyperlight_guest_tracing::trace!("< hl_exception_handler"); return; } } diff --git a/src/hyperlight_guest_bin/src/exceptions/idt.rs b/src/hyperlight_guest_bin/src/exceptions/idt.rs index 820e96861..91364cd95 100644 --- a/src/hyperlight_guest_bin/src/exceptions/idt.rs +++ b/src/hyperlight_guest_bin/src/exceptions/idt.rs @@ -71,7 +71,7 @@ impl IdtEntry { // Architectures Software Developer's Manual). pub(crate) static mut IDT: [IdtEntry; 256] = unsafe { core::mem::zeroed() }; -#[hyperlight_guest_tracing_macro::trace_function] +#[hyperlight_guest_tracing::trace_function] pub(crate) fn init_idt() { set_idt_entry(Exception::DivideByZero as usize, _do_excp0); // Divide by zero set_idt_entry(Exception::Debug as usize, _do_excp1); // Debug diff --git a/src/hyperlight_guest_bin/src/exceptions/idtr.rs b/src/hyperlight_guest_bin/src/exceptions/idtr.rs index 0d020f1e8..e79fb5dcf 100644 --- a/src/hyperlight_guest_bin/src/exceptions/idtr.rs +++ b/src/hyperlight_guest_bin/src/exceptions/idtr.rs @@ -40,7 +40,7 @@ impl Idtr { } } -#[hyperlight_guest_tracing_macro::trace_function] +#[hyperlight_guest_tracing::trace_function] pub(crate) unsafe fn load_idt() { unsafe { init_idt(); diff --git a/src/hyperlight_guest_bin/src/guest_function/call.rs b/src/hyperlight_guest_bin/src/guest_function/call.rs index 376b0cf35..3d55a9f5e 100644 --- a/src/hyperlight_guest_bin/src/guest_function/call.rs +++ b/src/hyperlight_guest_bin/src/guest_function/call.rs @@ -27,7 +27,7 @@ use crate::{GUEST_HANDLE, REGISTERED_GUEST_FUNCTIONS}; type GuestFunc = fn(&FunctionCall) -> Result>; -#[hyperlight_guest_tracing_macro::trace_function] +#[hyperlight_guest_tracing::trace_function] pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result> { // Validate this is a Guest Function Call if function_call.function_call_type() != FunctionCallType::Guest { @@ -62,7 +62,7 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result core::mem::transmute::(function_pointer) }; - hyperlight_guest_tracing_macro::trace!("guest_function", p_function(&function_call)) + hyperlight_guest_tracing::trace!("guest_function", p_function(&function_call)) } else { // The given function is not registered. The guest should implement a function called guest_dispatch_function to handle this. @@ -73,7 +73,7 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result fn guest_dispatch_function(function_call: FunctionCall) -> Result>; } - hyperlight_guest_tracing_macro::trace!("default guest function", unsafe { + hyperlight_guest_tracing::trace!("default guest function", unsafe { guest_dispatch_function(function_call) }) } @@ -83,7 +83,7 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result // and we will leak memory as the epilogue will not be called as halt() is not going to return. #[unsafe(no_mangle)] #[inline(never)] -#[hyperlight_guest_tracing_macro::trace_function] +#[hyperlight_guest_tracing::trace_function] fn internal_dispatch_function() -> Result<()> { let handle = unsafe { GUEST_HANDLE }; @@ -104,7 +104,7 @@ fn internal_dispatch_function() -> Result<()> { // This is implemented as a separate function to make sure that epilogue in the internal_dispatch_function is called before the halt() // which if it were included in the internal_dispatch_function cause the epilogue to not be called because the halt() would not return // when running in the hypervisor. -#[hyperlight_guest_tracing_macro::trace_function] +#[hyperlight_guest_tracing::trace_function] pub(crate) extern "C" fn dispatch_function() { // The hyperlight host likes to use one partition and reset it in // various ways; if that has happened, there might stale TLB diff --git a/src/hyperlight_guest_bin/src/lib.rs b/src/hyperlight_guest_bin/src/lib.rs index 9d8a2c35e..fa5e3a6f5 100644 --- a/src/hyperlight_guest_bin/src/lib.rs +++ b/src/hyperlight_guest_bin/src/lib.rs @@ -32,7 +32,7 @@ use hyperlight_common::mem::HyperlightPEB; use hyperlight_common::outb::OutBAction; use hyperlight_guest::exit::{abort_with_code_and_message, halt}; use hyperlight_guest::guest_handle::handle::GuestHandle; -use hyperlight_guest_tracing_macro::{trace, trace_function}; +use hyperlight_guest_tracing::{trace, trace_function}; use log::LevelFilter; use spin::Once; diff --git a/src/hyperlight_guest_bin/src/paging.rs b/src/hyperlight_guest_bin/src/paging.rs index 749900349..a5a3d9f26 100644 --- a/src/hyperlight_guest_bin/src/paging.rs +++ b/src/hyperlight_guest_bin/src/paging.rs @@ -61,6 +61,7 @@ struct MapResponse { /// as such do not use concurrently with any other page table operations /// - TLB invalidation is not performed, /// if previously-unmapped ranges are not being mapped, TLB invalidation may need to be performed afterwards. +#[hyperlight_guest_tracing::trace_function] pub unsafe fn map_region(phys_base: u64, virt_base: *mut u8, len: u64) { let mut pml4_base: u64; unsafe { diff --git a/src/hyperlight_guest_tracing/Cargo.toml b/src/hyperlight_guest_tracing/Cargo.toml index e77144eaa..873f9e37d 100644 --- a/src/hyperlight_guest_tracing/Cargo.toml +++ b/src/hyperlight_guest_tracing/Cargo.toml @@ -11,6 +11,7 @@ description = """Provides the tracing functionality for the hyperlight guest.""" [dependencies] hyperlight-common = { workspace = true, default-features = false, features = ["trace_guest"] } +hyperlight-guest-tracing-macro = { workspace = true } spin = "0.10.0" [lints] diff --git a/src/hyperlight_guest_tracing/src/lib.rs b/src/hyperlight_guest_tracing/src/lib.rs index 8d7ae0e6a..bcf4ee4dd 100644 --- a/src/hyperlight_guest_tracing/src/lib.rs +++ b/src/hyperlight_guest_tracing/src/lib.rs @@ -36,6 +36,10 @@ const MAX_NO_OF_ENTRIES: usize = 32; /// Maximum length of a trace message in bytes. pub const MAX_TRACE_MSG_LEN: usize = 64; +/// Re-export the tracing macros +/// This allows users to use the macros without needing to import them explicitly. +pub use hyperlight_guest_tracing_macro::*; + #[derive(Debug, Copy, Clone)] /// Represents a trace record of a guest with a number of cycles and a message. pub struct TraceRecord { diff --git a/src/hyperlight_guest_tracing_macro/Cargo.toml b/src/hyperlight_guest_tracing_macro/Cargo.toml index 89522c1de..6e749ac20 100644 --- a/src/hyperlight_guest_tracing_macro/Cargo.toml +++ b/src/hyperlight_guest_tracing_macro/Cargo.toml @@ -10,7 +10,6 @@ readme.workspace = true description = """Provides the tracing macros for the hyperlight guest, enabling structured logging and tracing capabilities.""" [dependencies] -hyperlight-guest-tracing = { workspace = true } proc-macro2 = "1.0" quote = "1.0.40" syn = { version = "2.0.104", features = ["full"] } diff --git a/src/hyperlight_guest_tracing_macro/src/lib.rs b/src/hyperlight_guest_tracing_macro/src/lib.rs index 53f0ef817..24b790864 100644 --- a/src/hyperlight_guest_tracing_macro/src/lib.rs +++ b/src/hyperlight_guest_tracing_macro/src/lib.rs @@ -48,15 +48,6 @@ pub fn trace_function(_attr: TokenStream, item: TokenStream) -> TokenStream { let entry_msg = format!("> {}", fn_name_str); let exit_msg = format!("< {}", fn_name_str); - if entry_msg.len() > hyperlight_guest_tracing::MAX_TRACE_MSG_LEN - || exit_msg.len() > hyperlight_guest_tracing::MAX_TRACE_MSG_LEN - { - panic!( - "Trace messages must not exceed {} bytes in length.", - hyperlight_guest_tracing::MAX_TRACE_MSG_LEN - ); - } - let expanded = match fn_output { syn::ReturnType::Default => { // No return value (unit) @@ -64,11 +55,16 @@ pub fn trace_function(_attr: TokenStream, item: TokenStream) -> TokenStream { #(#fn_attrs)* #fn_vis #fn_sig { #[cfg(feature = "trace_guest")] - hyperlight_guest_tracing::create_trace_record(#entry_msg); + const _: () = assert!( + #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, + "Trace message exceeds the maximum bytes length", + ); + #[cfg(feature = "trace_guest")] + ::hyperlight_guest_tracing::create_trace_record(#entry_msg); // Call the original function body #fn_block #[cfg(feature = "trace_guest")] - hyperlight_guest_tracing::create_trace_record(#exit_msg); + ::hyperlight_guest_tracing::create_trace_record(#exit_msg); } } } @@ -78,10 +74,15 @@ pub fn trace_function(_attr: TokenStream, item: TokenStream) -> TokenStream { #(#fn_attrs)* #fn_vis #fn_sig { #[cfg(feature = "trace_guest")] - hyperlight_guest_tracing::create_trace_record(concat!("> ", #fn_name_str)); + const _: () = assert!( + #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, + "Trace message exceeds the maximum bytes length", + ); + #[cfg(feature = "trace_guest")] + ::hyperlight_guest_tracing::create_trace_record(#entry_msg); let __trace_result = (|| #fn_block )(); #[cfg(feature = "trace_guest")] - hyperlight_guest_tracing::create_trace_record(concat!("< ", #fn_name_str)); + ::hyperlight_guest_tracing::create_trace_record(#exit_msg); __trace_result } } @@ -103,17 +104,6 @@ impl syn::parse::Parse for TraceMacroInput { if !matches!(message, syn::Lit::Str(_)) { return Err(input.error("first argument to trace! must be a string literal")); } - if let syn::Lit::Str(ref lit_str) = message { - if lit_str.value().is_empty() { - return Err(input.error("trace message must not be empty")); - } - if lit_str.value().len() > hyperlight_guest_tracing::MAX_TRACE_MSG_LEN { - return Err(input.error(format!( - "trace message must not exceed {} bytes", - hyperlight_guest_tracing::MAX_TRACE_MSG_LEN - ))); - } - } let statement = if input.peek(syn::Token![,]) { let _: syn::Token![,] = input.parse()?; @@ -207,15 +197,20 @@ pub fn trace(input: TokenStream) -> TokenStream { _ => unreachable!(), }; if let Some(statement) = parsed.statement { - let entry = format!("+ {}", trace_message); - let exit = format!("- {}", trace_message); + let entry_msg = format!("+ {}", trace_message); + let exit_msg = format!("- {}", trace_message); let expanded = quote! { { #[cfg(feature = "trace_guest")] - hyperlight_guest_tracing::create_trace_record(#entry); + const _: () = assert!( + #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, + "Trace message exceeds the maximum bytes length", + ); + #[cfg(feature = "trace_guest")] + ::hyperlight_guest_tracing::create_trace_record(#entry_msg); let __trace_result = #statement; #[cfg(feature = "trace_guest")] - hyperlight_guest_tracing::create_trace_record(#exit); + ::hyperlight_guest_tracing::create_trace_record(#exit_msg); __trace_result } }; @@ -224,7 +219,12 @@ pub fn trace(input: TokenStream) -> TokenStream { let expanded = quote! { { #[cfg(feature = "trace_guest")] - hyperlight_guest_tracing::create_trace_record(#trace_message); + const _: () = assert!( + #trace_message.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, + "Trace message exceeds the maximum bytes length", + ); + #[cfg(feature = "trace_guest")] + ::hyperlight_guest_tracing::create_trace_record(#trace_message); } }; TokenStream::from(expanded) @@ -242,7 +242,7 @@ pub fn flush(_input: TokenStream) -> TokenStream { let expanded = quote! { { #[cfg(feature = "trace_guest")] - hyperlight_guest_tracing::flush_trace_buffer(); + ::hyperlight_guest_tracing::flush_trace_buffer(); } }; diff --git a/src/tests/rust_guests/callbackguest/Cargo.lock b/src/tests/rust_guests/callbackguest/Cargo.lock index 075c49f42..24c80469e 100644 --- a/src/tests/rust_guests/callbackguest/Cargo.lock +++ b/src/tests/rust_guests/callbackguest/Cargo.lock @@ -86,7 +86,6 @@ dependencies = [ "anyhow", "hyperlight-common", "hyperlight-guest-tracing", - "hyperlight-guest-tracing-macro", "serde_json", ] @@ -101,7 +100,6 @@ dependencies = [ "hyperlight-common", "hyperlight-guest", "hyperlight-guest-tracing", - "hyperlight-guest-tracing-macro", "log", "spin 0.10.0", ] @@ -111,6 +109,7 @@ name = "hyperlight-guest-tracing" version = "0.7.0" dependencies = [ "hyperlight-common", + "hyperlight-guest-tracing-macro", "spin 0.10.0", ] @@ -118,7 +117,6 @@ dependencies = [ name = "hyperlight-guest-tracing-macro" version = "0.7.0" dependencies = [ - "hyperlight-guest-tracing", "proc-macro2", "quote", "syn", diff --git a/src/tests/rust_guests/dummyguest/Cargo.lock b/src/tests/rust_guests/dummyguest/Cargo.lock index 3b7a713a7..f1c9d9e55 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.lock +++ b/src/tests/rust_guests/dummyguest/Cargo.lock @@ -85,7 +85,6 @@ dependencies = [ "anyhow", "hyperlight-common", "hyperlight-guest-tracing", - "hyperlight-guest-tracing-macro", "serde_json", ] @@ -100,7 +99,6 @@ dependencies = [ "hyperlight-common", "hyperlight-guest", "hyperlight-guest-tracing", - "hyperlight-guest-tracing-macro", "log", "spin 0.10.0", ] @@ -110,6 +108,7 @@ name = "hyperlight-guest-tracing" version = "0.7.0" dependencies = [ "hyperlight-common", + "hyperlight-guest-tracing-macro", "spin 0.10.0", ] @@ -117,7 +116,6 @@ dependencies = [ name = "hyperlight-guest-tracing-macro" version = "0.7.0" dependencies = [ - "hyperlight-guest-tracing", "proc-macro2", "quote", "syn", diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index 3cd9fe849..07672d6f1 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -77,7 +77,6 @@ dependencies = [ "anyhow", "hyperlight-common", "hyperlight-guest-tracing", - "hyperlight-guest-tracing-macro", "serde_json", ] @@ -92,7 +91,6 @@ dependencies = [ "hyperlight-common", "hyperlight-guest", "hyperlight-guest-tracing", - "hyperlight-guest-tracing-macro", "log", "spin 0.10.0", ] @@ -102,6 +100,7 @@ name = "hyperlight-guest-tracing" version = "0.7.0" dependencies = [ "hyperlight-common", + "hyperlight-guest-tracing-macro", "spin 0.10.0", ] @@ -109,7 +108,6 @@ dependencies = [ name = "hyperlight-guest-tracing-macro" version = "0.7.0" dependencies = [ - "hyperlight-guest-tracing", "proc-macro2", "quote", "syn", diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index ea2537ea3..2ecd6119f 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -220,7 +220,6 @@ dependencies = [ "anyhow", "hyperlight-common", "hyperlight-guest-tracing", - "hyperlight-guest-tracing-macro", "serde_json", ] @@ -235,7 +234,6 @@ dependencies = [ "hyperlight-common", "hyperlight-guest", "hyperlight-guest-tracing", - "hyperlight-guest-tracing-macro", "log", "spin 0.10.0", ] @@ -245,6 +243,7 @@ name = "hyperlight-guest-tracing" version = "0.7.0" dependencies = [ "hyperlight-common", + "hyperlight-guest-tracing-macro", "spin 0.10.0", ] @@ -252,7 +251,6 @@ dependencies = [ name = "hyperlight-guest-tracing-macro" version = "0.7.0" dependencies = [ - "hyperlight-guest-tracing", "proc-macro2", "quote", "syn", From 5c719a81a79dd72f7d313568859a8854fc4bcaea Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 31 Jul 2025 09:45:14 +0100 Subject: [PATCH 070/271] Adds blocker to release if any issue has release-blocker label (#748) Signed-off-by: Simon Davies --- .github/workflows/CreateRelease.yml | 11 ++++ .github/workflows/ReleaseBlockerCheck.yml | 38 +++++++++++ .../workflows/ReleaseBlockerLabelCleanUp.yml | 31 +++++++++ dev/check-release-blockers.sh | 63 +++++++++++++++++++ docs/github-labels.md | 3 +- 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ReleaseBlockerCheck.yml create mode 100644 .github/workflows/ReleaseBlockerLabelCleanUp.yml create mode 100755 dev/check-release-blockers.sh diff --git a/.github/workflows/CreateRelease.yml b/.github/workflows/CreateRelease.yml index 02a3796fe..e3a4894d6 100644 --- a/.github/workflows/CreateRelease.yml +++ b/.github/workflows/CreateRelease.yml @@ -13,10 +13,19 @@ permissions: jobs: + release-blocker-check: + # see https://github.com/orgs/community/discussions/26286#discussioncomment-3251208 for why we need to check the ref + if: ${{ contains(github.ref, 'refs/heads/release/') }} || ${{ github.ref=='refs/heads/main' }} + uses: ./.github/workflows/ReleaseBlockerCheck.yml + with: + repository: ${{ github.repository }} + secrets: inherit + build-rust-ubuntu: # see https://github.com/orgs/community/discussions/26286#discussioncomment-3251208 for why we need to check the ref if: ${{ contains(github.ref, 'refs/heads/release/') }} || ${{ github.ref=='refs/heads/main' }} runs-on: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"] + needs: [release-blocker-check] steps: - uses: actions/checkout@v4 @@ -37,6 +46,7 @@ jobs: # see https://github.com/orgs/community/discussions/26286#discussioncomment-3251208 for why we need to check the ref if: ${{ contains(github.ref, 'refs/heads/release/') }} || ${{ github.ref=='refs/heads/main' }} runs-on: windows-2022 + needs: [release-blocker-check] steps: - uses: actions/checkout@v4 @@ -56,6 +66,7 @@ jobs: build-guest-binaries: uses: ./.github/workflows/dep_build_guest_binaries.yml secrets: inherit + needs: [release-blocker-check] benchmarks: needs: [build-guest-binaries] diff --git a/.github/workflows/ReleaseBlockerCheck.yml b/.github/workflows/ReleaseBlockerCheck.yml new file mode 100644 index 000000000..90ea4ff1e --- /dev/null +++ b/.github/workflows/ReleaseBlockerCheck.yml @@ -0,0 +1,38 @@ +name: Release Blocker Check + +on: + workflow_call: + inputs: + repository: + description: "Repository to check in format 'owner/repo'" + required: false + type: string + default: ${{ github.repository }} + workflow_dispatch: + inputs: + repository: + description: "Repository to check in format 'owner/repo'" + required: false + type: string + +permissions: + issues: read + contents: read + +jobs: + check-blockers: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check for Release Blocking Issues + run: | + REPO="${{ inputs.repository || github.repository }}" + echo "Checking repository: $REPO" + + if ! ./dev/check-release-blockers.sh "$REPO"; then + echo "::error::Release blocked by open issues with 'release-blocker' label" + exit 1 + fi + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ReleaseBlockerLabelCleanUp.yml b/.github/workflows/ReleaseBlockerLabelCleanUp.yml new file mode 100644 index 000000000..306593e0d --- /dev/null +++ b/.github/workflows/ReleaseBlockerLabelCleanUp.yml @@ -0,0 +1,31 @@ +name: Release Blocker Cleanup + +on: + issues: + types: [closed] + +permissions: + issues: write + contents: read + +jobs: + remove-release-blocker: + runs-on: ubuntu-latest + steps: + - name: Remove release-blocker label from closed issue + run: | + ISSUE_NUMBER=${{ github.event.issue.number }} + echo "Checking if issue #$ISSUE_NUMBER has release-blocker label..." + + # Check if the issue has the release-blocker label + HAS_LABEL=$(gh issue view "$ISSUE_NUMBER" --json labels -q '.labels[] | select(.name == "release-blocker") | .name') + + if [ -n "$HAS_LABEL" ]; then + echo "✅ Issue #$ISSUE_NUMBER has release-blocker label, removing it..." + gh issue edit "$ISSUE_NUMBER" --remove-label "release-blocker" + echo "✅ Successfully removed release-blocker label from issue #$ISSUE_NUMBER" + else + echo "ℹ️ Issue #$ISSUE_NUMBER does not have release-blocker label, no action needed" + fi + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/dev/check-release-blockers.sh b/dev/check-release-blockers.sh new file mode 100755 index 000000000..cf7475c65 --- /dev/null +++ b/dev/check-release-blockers.sh @@ -0,0 +1,63 @@ +#!/bin/bash +set -e +set -u +set -o pipefail + +## DESCRIPTION: +## +## This script checks for open issues with the 'release-blocker' label +## in a given GitHub repository. It exits with code 1 if any blocking +## issues are found, or 0 if none are found. +## +## PRE-REQS: +## +## This script assumes that the gh cli is installed and in the PATH +## and that there is a GitHub PAT in the GITHUB_TOKEN env var +## with the following permissions: +## - repo (read) +## - issues (read) +## or that the user is logged into the gh cli with an account with those permissions + + +# Check if repository argument is provided +if [ -z "${1:-}" ]; then + echo "Error: Repository name not provided." + echo "Usage: $0 " + echo "Example: $0 hyperlight-dev/hyperlight" + exit 1 +fi + +REPO="$1" +echo "Checking for open issues with 'release-blocker' label in $REPO..." + +# Extract owner and repo name from the argument +OWNER=$(echo "$REPO" | cut -d'/' -f1) +REPO_NAME=$(echo "$REPO" | cut -d'/' -f2) + +# Get all open issues with release-blocker label +BLOCKING_ISSUES=$(gh api graphql -f query=' + query($owner: String!, $repo: String!) { + repository(owner: $owner, name: $repo) { + issues(first: 100, states: OPEN, labels: ["release-blocker"]) { + totalCount + nodes { + number + title + url + } + } + } + }' -f owner="$OWNER" -f repo="$REPO_NAME" --jq '.data.repository.issues') + +BLOCKER_COUNT=$(echo "$BLOCKING_ISSUES" | jq '.totalCount') + +if [ "$BLOCKER_COUNT" -gt 0 ]; then + echo "❌ Found $BLOCKER_COUNT open release-blocking issue(s):" + echo "$BLOCKING_ISSUES" | jq -r '.nodes[] | " - #\(.number): \(.title) (\(.url))"' + echo "" + echo "Release blocked by open issue(s) with 'release-blocker' label" + exit 1 +else + echo "✅ No open release blocking issues found" + exit 0 +fi diff --git a/docs/github-labels.md b/docs/github-labels.md index 888b0280d..5133f048a 100644 --- a/docs/github-labels.md +++ b/docs/github-labels.md @@ -39,6 +39,7 @@ In addition to lifecycle labels, we use the following labels to further categori - **good-first-issue** - The issue is suitable for new contributors or those looking for a simple task to start with. - **help-wanted** - The issue is a request for help or assistance. - **question** - The issue is a question or request for information. +- **release-blocker** - Critical issues that must be resolved before the next release can be made. The presence of this label on any open issue will prevent releases being created by the release workflow --- @@ -56,4 +57,4 @@ In addition to **kind/*** labels, we use optional **area/*** labels to specify t ## Notes -This document is a work in progress and may be updated as needed. The labels and categories are subject to change based on the evolving needs of the project and community feedback. \ No newline at end of file +This document is a work in progress and may be updated as needed. The labels and categories are subject to change based on the evolving needs of the project and community feedback. From 45bb9fb1d84070f47833e4b65d56a986318a6787 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 31 Jul 2025 12:38:10 +0100 Subject: [PATCH 071/271] Update Rust version to 1.86 (#751) Signed-off-by: Simon Davies --- .devcontainer/Dockerfile | 2 +- .github/workflows/Benchmarks.yml | 2 +- .github/workflows/CargoAudit.yml | 2 +- .github/workflows/CargoPublish.yml | 2 +- .github/workflows/CreateDevcontainerImage.yml | 2 +- .github/workflows/CreateRelease.yml | 6 +++--- .github/workflows/copilot-setup-steps.yml | 2 +- .github/workflows/dep_build_guest_binaries.yml | 2 +- .github/workflows/dep_fuzzing.yml | 2 +- .github/workflows/dep_rust.yml | 4 ++-- Cargo.toml | 2 +- README.md | 2 +- hack/rust-dependabot-patch.Dockerfile | 2 +- rust-toolchain.toml | 2 +- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 6442e420d..db7867495 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -52,7 +52,7 @@ RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhisto USER $USER -ARG RUST_TOOLCHAIN=1.85 +ARG RUST_TOOLCHAIN=1.86 # Install rust RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \ diff --git a/.github/workflows/Benchmarks.yml b/.github/workflows/Benchmarks.yml index 5fd12f922..95adc2e40 100644 --- a/.github/workflows/Benchmarks.yml +++ b/.github/workflows/Benchmarks.yml @@ -30,7 +30,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 with: - rust-toolchain: "1.85" + rust-toolchain: "1.86" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/CargoAudit.yml b/.github/workflows/CargoAudit.yml index 00cf41515..de81fa6f6 100644 --- a/.github/workflows/CargoAudit.yml +++ b/.github/workflows/CargoAudit.yml @@ -19,7 +19,7 @@ jobs: # TODO: Once the runner image is updated to include the necessary tools (without downloading), we can switch to the common workflow. - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.85" + toolchain: "1.86" - uses: rustsec/audit-check@v2.0.0 with: diff --git a/.github/workflows/CargoPublish.yml b/.github/workflows/CargoPublish.yml index 5d80a0523..37494ba1f 100644 --- a/.github/workflows/CargoPublish.yml +++ b/.github/workflows/CargoPublish.yml @@ -34,7 +34,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 with: - rust-toolchain: "1.85" + rust-toolchain: "1.86" - name: Check crate versions shell: bash diff --git a/.github/workflows/CreateDevcontainerImage.yml b/.github/workflows/CreateDevcontainerImage.yml index 81e0a9cb5..1668a5c11 100644 --- a/.github/workflows/CreateDevcontainerImage.yml +++ b/.github/workflows/CreateDevcontainerImage.yml @@ -16,7 +16,7 @@ env: USER: vscode GROUP: vscode LLVM_VERSION: 17 - RUST_TOOLCHAIN_DEFAULT: 1.85 + RUST_TOOLCHAIN_DEFAULT: 1.86 RUST_TOOLCHAIN_FILE: rust-toolchain.toml # There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. diff --git a/.github/workflows/CreateRelease.yml b/.github/workflows/CreateRelease.yml index e3a4894d6..f5d65e077 100644 --- a/.github/workflows/CreateRelease.yml +++ b/.github/workflows/CreateRelease.yml @@ -32,7 +32,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 with: - rust-toolchain: "1.85" + rust-toolchain: "1.86" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -53,7 +53,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 with: - rust-toolchain: "1.85" + rust-toolchain: "1.86" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -113,7 +113,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 with: - rust-toolchain: "1.85" + rust-toolchain: "1.86" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 21c544125..f6f09538b 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -28,6 +28,6 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 with: - rust-toolchain: "1.85" + rust-toolchain: "1.86" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/dep_build_guest_binaries.yml b/.github/workflows/dep_build_guest_binaries.yml index 912a0078e..0edfbd739 100644 --- a/.github/workflows/dep_build_guest_binaries.yml +++ b/.github/workflows/dep_build_guest_binaries.yml @@ -33,7 +33,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 with: - rust-toolchain: "1.85" + rust-toolchain: "1.86" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/dep_fuzzing.yml b/.github/workflows/dep_fuzzing.yml index 0519bfcc4..29832157e 100644 --- a/.github/workflows/dep_fuzzing.yml +++ b/.github/workflows/dep_fuzzing.yml @@ -34,7 +34,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 with: - rust-toolchain: "1.85" + rust-toolchain: "1.86" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index fc68e3e4b..2e45faefd 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -48,7 +48,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 with: - rust-toolchain: "1.85" + rust-toolchain: "1.86" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -100,7 +100,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 with: - rust-toolchain: "1.85" + rust-toolchain: "1.86" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Cargo.toml b/Cargo.toml index 18a311405..d111c1850 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ exclude = [ [workspace.package] version = "0.7.0" edition = "2024" -rust-version = "1.85" +rust-version = "1.86" license = "Apache-2.0" homepage = "https://github.com/hyperlight-dev/hyperlight" repository = "https://github.com/hyperlight-dev/hyperlight" diff --git a/README.md b/README.md index 6ca4ec826..87bcda114 100644 --- a/README.md +++ b/README.md @@ -190,7 +190,7 @@ After having an environment with a hypervisor setup, running the example has the 1. On Linux or WSL, you'll most likely need build essential. For Ubuntu, run `sudo apt install build-essential`. For Azure Linux, run `sudo dnf install build-essential`. -2. [Rust](https://www.rust-lang.org/tools/install). Install toolchain v1.85 or later. +2. [Rust](https://www.rust-lang.org/tools/install). Install toolchain v1.86 or later. 3. [just](https://github.com/casey/just). `cargo install just` On Windows you also need [pwsh](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.4). 4. [clang and LLVM](https://clang.llvm.org/get_started.html). - On Ubuntu, run: diff --git a/hack/rust-dependabot-patch.Dockerfile b/hack/rust-dependabot-patch.Dockerfile index 31c285ef9..03bed249a 100644 --- a/hack/rust-dependabot-patch.Dockerfile +++ b/hack/rust-dependabot-patch.Dockerfile @@ -1,2 +1,2 @@ FROM dependabot/dependabot-script -RUN rustup toolchain install 1.85 && rustup default 1.85 +RUN rustup toolchain install 1.86 && rustup default 1.86 diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5432e53da..b8aa83f43 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.85" +channel = "1.86" # Target used for guest binaries. This is an additive list of targets in addition to host platform. # Will install the target if not already installed when building guest binaries. targets = ["x86_64-unknown-none", "x86_64-unknown-linux-musl"] From 8e5762189132a876121dadeaa27d1d037b9e6ad5 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Thu, 31 Jul 2025 11:04:11 -0700 Subject: [PATCH 072/271] Fix typo in PATH env var (#756) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- src/hyperlight_guest_bin/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hyperlight_guest_bin/build.rs b/src/hyperlight_guest_bin/build.rs index 493f97291..a7bce651b 100644 --- a/src/hyperlight_guest_bin/build.rs +++ b/src/hyperlight_guest_bin/build.rs @@ -204,7 +204,7 @@ fn find_next(root_dir: &Path, tool_name: &str) -> PathBuf { if let Some(path) = env::var_os(format!("HYPERLIGHT_GUEST_{tool_name}")) { return path.into(); } - let path = env::var_os("PATH)").expect("$PATH should exist"); + let path = env::var_os("PATH").expect("$PATH should exist"); let paths: Vec<_> = env::split_paths(&path).collect(); for path in &paths { let abs_path = fs::canonicalize(path); From 367af9c69c6cbc27c0c9285f28d7fa0d03b5047d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Aug 2025 04:26:32 +0000 Subject: [PATCH 073/271] Bump serde_json from 1.0.141 to 1.0.142 (#757) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.141 to 1.0.142. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.141...v1.0.142) --- updated-dependencies: - dependency-name: serde_json dependency-version: 1.0.142 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f3b94fd4..1373c5f85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3117,9 +3117,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.141" +version = "1.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" +checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" dependencies = [ "itoa", "memchr", From 1e23ca05f3c7ae589642276db492ee96a7c9ded8 Mon Sep 17 00:00:00 2001 From: Tomasz Andrzejak Date: Fri, 1 Aug 2025 21:44:18 +0200 Subject: [PATCH 074/271] fix(guest-gin): move logger initialization (#755) Do not run any complex tasks until the global allocator is initialized. Signed-off-by: Tomasz Andrzejak --- src/hyperlight_guest_bin/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hyperlight_guest_bin/src/lib.rs b/src/hyperlight_guest_bin/src/lib.rs index fa5e3a6f5..27918ad3f 100644 --- a/src/hyperlight_guest_bin/src/lib.rs +++ b/src/hyperlight_guest_bin/src/lib.rs @@ -173,12 +173,6 @@ pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_leve // Set the seed for the random number generator for C code using rand; srand(srand_seed); - // set up the logger - let max_log_level = LevelFilter::iter() - .nth(max_log_level as usize) - .expect("Invalid log level"); - init_logger(max_log_level); - // This static is to make it easier to implement the __chkstk function in assembly. // It also means that should we change the layout of the struct in the future, we // don't have to change the assembly code. @@ -206,6 +200,12 @@ pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_leve (*peb_ptr).guest_function_dispatch_ptr = dispatch_function as usize as u64; + // set up the logger + let max_log_level = LevelFilter::iter() + .nth(max_log_level as usize) + .expect("Invalid log level"); + init_logger(max_log_level); + trace!("hyperlight_main", hyperlight_main(); ); From 5d8dffb600111f5c81ca87d7d0d2efcef34a6fb3 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Fri, 1 Aug 2025 20:44:50 +0100 Subject: [PATCH 075/271] Fix label cleanup (#754) Signed-off-by: Simon Davies --- .github/workflows/ReleaseBlockerLabelCleanUp.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ReleaseBlockerLabelCleanUp.yml b/.github/workflows/ReleaseBlockerLabelCleanUp.yml index 306593e0d..d23bd928c 100644 --- a/.github/workflows/ReleaseBlockerLabelCleanUp.yml +++ b/.github/workflows/ReleaseBlockerLabelCleanUp.yml @@ -12,6 +12,8 @@ jobs: remove-release-blocker: runs-on: ubuntu-latest steps: + - name: Checkout code + uses: actions/checkout@v4 - name: Remove release-blocker label from closed issue run: | ISSUE_NUMBER=${{ github.event.issue.number }} From 58fe7bb845bd56ce9facac5d1c20ff1aea5ee74b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Aug 2025 16:52:53 +0100 Subject: [PATCH 076/271] Bump cc from 1.2.30 to 1.2.31 (#759) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.30 to 1.2.31. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.30...cc-v1.2.31) --- updated-dependencies: - dependency-name: cc dependency-version: 1.2.31 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1373c5f85..4355cade9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,9 +362,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.30" +version = "1.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" dependencies = [ "jobserver", "libc", From 0e5d419d016106e17cf35e0c594f7204db535ddb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Aug 2025 16:52:58 +0100 Subject: [PATCH 077/271] Bump tokio from 1.47.0 to 1.47.1 (#758) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.47.0 to 1.47.1. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.47.0...tokio-1.47.1) --- updated-dependencies: - dependency-name: tokio dependency-version: 1.47.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4355cade9..4c414c09a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3447,9 +3447,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.47.0" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43864ed400b6043a4757a25c7a64a8efde741aed79a056a2fb348a406701bb35" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ "backtrace", "bytes", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index eeba95e97..7ebead8e1 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -101,7 +101,7 @@ opentelemetry = "0.30.0" opentelemetry-otlp = { version = "0.30.0", default-features = false, features = ["http-proto", "reqwest-blocking-client"] } opentelemetry-semantic-conventions = "0.30" opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio"] } -tokio = { version = "1.47.0", features = ["full"] } +tokio = { version = "1.47.1", features = ["full"] } criterion = "0.7.0" tracing-chrome = "0.7.2" metrics-util = "0.20.0" From 104f62a5fb63dac48457e5dec87b4bb780be5a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Mon, 4 Aug 2025 18:54:01 +0300 Subject: [PATCH 078/271] Update hyperlight-guest-tracing crate to conditionally enable traces at compile time (#752) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [trace] Add check for empty message to trace macro Signed-off-by: Doru Blânzeanu * [trace] move tracing logic inside tracing module - this helps with later conditionally compiling only the tracing code depending on a feature Signed-off-by: Doru Blânzeanu * [trace] add 'trace' feature to guest tracing crates - This allows the use of the 'hyperlight-guest-tracing' without having the tracing enabled - Now the user can select at compile time whether the macros enable tracing or not - Before this change, the crate using the macros from hyperlight-guest-tracing-macro needed to define a features called 'trace_guest' because the generated code would gate everything with that feature - The change makes the generation of code dependent on the 'trace' feature - Some of the variables used in the macros were prefixed with an '_' to avoid warnings when the 'trace' feature is not set Signed-off-by: Doru Blânzeanu * [trace] move macros tests to the tracing crate - This is needed for the tests to pass because the macros use 'hyperlight_guest_tracing::' which cannot be imported by 'hyperlight_guest_tracing_macro' bacause it would create a circular dependency. - The caveat is that when using 'hyperlight_guest_tracing_macro' one needs to have as a dependency 'hyperlight_guest_tracing' also Signed-off-by: Doru Blânzeanu * update guests to use the tracing crate to intrument functions Signed-off-by: Doru Blânzeanu --------- Signed-off-by: Doru Blânzeanu --- src/hyperlight_guest/Cargo.toml | 4 +- src/hyperlight_guest_bin/Cargo.toml | 4 +- src/hyperlight_guest_tracing/Cargo.toml | 6 +- src/hyperlight_guest_tracing/src/lib.rs | 465 +++++++++++------- src/hyperlight_guest_tracing_macro/Cargo.toml | 1 + src/hyperlight_guest_tracing_macro/src/lib.rs | 163 +++--- src/hyperlight_host/Cargo.toml | 2 +- .../rust_guests/callbackguest/Cargo.lock | 1 + .../rust_guests/callbackguest/Cargo.toml | 5 +- .../rust_guests/callbackguest/src/main.rs | 12 + src/tests/rust_guests/simpleguest/Cargo.lock | 1 + src/tests/rust_guests/simpleguest/Cargo.toml | 3 +- src/tests/rust_guests/simpleguest/src/main.rs | 49 ++ src/tests/rust_guests/witguest/Cargo.toml | 4 +- 14 files changed, 422 insertions(+), 298 deletions(-) diff --git a/src/hyperlight_guest/Cargo.toml b/src/hyperlight_guest/Cargo.toml index 5788bedc6..90155bb3d 100644 --- a/src/hyperlight_guest/Cargo.toml +++ b/src/hyperlight_guest/Cargo.toml @@ -15,8 +15,8 @@ Provides only the essential building blocks for interacting with the host enviro anyhow = { version = "1.0.98", default-features = false } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } hyperlight-common = { workspace = true } -hyperlight-guest-tracing = { workspace = true } +hyperlight-guest-tracing = { workspace = true, default-features = false } [features] default = [] -trace_guest = [] +trace_guest = ["hyperlight-guest-tracing/trace"] diff --git a/src/hyperlight_guest_bin/Cargo.toml b/src/hyperlight_guest_bin/Cargo.toml index 83ac2a454..79fad4450 100644 --- a/src/hyperlight_guest_bin/Cargo.toml +++ b/src/hyperlight_guest_bin/Cargo.toml @@ -17,13 +17,13 @@ and third-party code used by our C-API needed to build a native hyperlight-guest default = ["libc", "printf"] libc = [] # compile musl libc printf = [ "libc" ] # compile printf -trace_guest = ["hyperlight-common/trace_guest", "hyperlight-guest/trace_guest"] +trace_guest = ["hyperlight-common/trace_guest", "hyperlight-guest/trace_guest", "hyperlight-guest-tracing/trace"] mem_profile = ["hyperlight-common/unwind_guest","hyperlight-common/mem_profile"] [dependencies] hyperlight-guest = { workspace = true, default-features = false } hyperlight-common = { workspace = true, default-features = false } -hyperlight-guest-tracing = { workspace = true } +hyperlight-guest-tracing = { workspace = true, default-features = false } buddy_system_allocator = "0.11.0" log = { version = "0.4", default-features = false } spin = "0.10.0" diff --git a/src/hyperlight_guest_tracing/Cargo.toml b/src/hyperlight_guest_tracing/Cargo.toml index 873f9e37d..4e9bf9758 100644 --- a/src/hyperlight_guest_tracing/Cargo.toml +++ b/src/hyperlight_guest_tracing/Cargo.toml @@ -10,9 +10,13 @@ readme.workspace = true description = """Provides the tracing functionality for the hyperlight guest.""" [dependencies] -hyperlight-common = { workspace = true, default-features = false, features = ["trace_guest"] } +hyperlight-common = { workspace = true, default-features = false } hyperlight-guest-tracing-macro = { workspace = true } spin = "0.10.0" [lints] workspace = true + +[features] +default = [] +trace = [ "hyperlight-guest-tracing-macro/trace", "hyperlight-common/trace_guest" ] diff --git a/src/hyperlight_guest_tracing/src/lib.rs b/src/hyperlight_guest_tracing/src/lib.rs index bcf4ee4dd..92902e3da 100644 --- a/src/hyperlight_guest_tracing/src/lib.rs +++ b/src/hyperlight_guest_tracing/src/lib.rs @@ -15,30 +15,99 @@ limitations under the License. */ #![no_std] -// === Dependencies === -extern crate alloc; - -use core::mem::MaybeUninit; - -use hyperlight_common::outb::OutBAction; -use spin::Mutex; - -/// Type alias for the function that sends trace records to the host. -type SendToHostFn = fn(u64, &[TraceRecord]); - -/// Global trace buffer for storing trace records. -static TRACE_BUFFER: Mutex> = Mutex::new(TraceBuffer::new(send_to_host)); - -/// Maximum number of entries in the trace buffer. -/// From local testing, 32 entries seems to be a good balance between performance and memory usage. -const MAX_NO_OF_ENTRIES: usize = 32; - -/// Maximum length of a trace message in bytes. -pub const MAX_TRACE_MSG_LEN: usize = 64; - /// Re-export the tracing macros /// This allows users to use the macros without needing to import them explicitly. +/// +/// # Tracing Macros Usage +/// +/// ## The `trace_function` macro can be used to trace function calls. +/// +/// ```rust +/// #[hyperlight_guest_tracing_macro::trace_function] +/// fn my_function() { +/// // // Function body +/// } +/// ``` +/// +/// ## The `trace!` macro can be used to create trace records with a message. +/// +/// ```rust +/// use hyperlight_guest_tracing_macro::trace; +/// trace!("message"); +/// trace!("message", { /* block of code */ }); +/// ``` +/// +/// ## Basic usage: trace with message only +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// trace!("hello"); +/// ``` +/// +/// ## Trace with a block, returning a value +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// let x = trace!("block", { 42 }); +/// assert_eq!(x, 42); +/// ``` +/// +/// ## Trace with a block using local variables +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// let y = 10; +/// let z = trace!("sum", { y + 5 }); +/// assert_eq!(z, 15); +/// ``` +/// +/// ## Trace with a block that returns a reference +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// let s = String::from("abc"); +/// let r: &str = trace!("ref", { &s }); +/// assert_eq!(r, "abc"); +/// ``` +/// +/// ## Control flow: `return` inside the block returns from the function +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// fn foo() -> i32 { +/// let _ = trace!("fail", { +/// // This return only exits the closure, not the function `foo`. +/// return 42; +/// }); +/// assert!(false, "This should not be reached"); +/// } +/// ``` +/// +/// ## Control flow: `break` inside the block exits the outer loop +/// +/// ``` +/// use hyperlight_guest_tracing_macro::trace; +/// let mut x = 0; +/// for i in 1..3 { +/// x = i; +/// let _ = trace!("msg", { +/// // This break should exit the loop. +/// break; +/// }); +/// } +/// assert_eq!(x, 1, "Loop should break after the first iteration"); +/// ``` +/// +/// ## Flush the trace buffer +/// ```rust +/// hyperlight_guest_tracing_macro::flush!(); +/// ``` pub use hyperlight_guest_tracing_macro::*; +#[cfg(feature = "trace")] +pub use trace::{create_trace_record, flush_trace_buffer}; + +/// Maximum length of a trace message in bytes. +pub const MAX_TRACE_MSG_LEN: usize = 64; #[derive(Debug, Copy, Clone)] /// Represents a trace record of a guest with a number of cycles and a message. @@ -51,82 +120,6 @@ pub struct TraceRecord { pub msg: [u8; MAX_TRACE_MSG_LEN], } -impl From<&str> for TraceRecord { - fn from(mut msg: &str) -> Self { - if msg.len() > MAX_TRACE_MSG_LEN { - // If the message is too long, truncate it to fit the maximum length - msg = &msg[..MAX_TRACE_MSG_LEN]; - } - - let cycles = invariant_tsc::read_tsc(); - - TraceRecord { - cycles, - msg: { - let mut arr = [0u8; MAX_TRACE_MSG_LEN]; - arr[..msg.len()].copy_from_slice(msg.as_bytes()); - arr - }, - msg_len: msg.len(), - } - } -} - -/// A buffer for storing trace records. -struct TraceBuffer { - /// The entries in the trace buffer. - entries: [TraceRecord; MAX_NO_OF_ENTRIES], - /// The index where the next entry will be written. - write_index: usize, - /// Function to send the trace records to the host. - send_to_host: F, -} - -impl TraceBuffer { - /// Creates a new `TraceBuffer` with uninitialized entries. - const fn new(f: F) -> Self { - Self { - entries: unsafe { [MaybeUninit::zeroed().assume_init(); MAX_NO_OF_ENTRIES] }, - write_index: 0, - send_to_host: f, - } - } - - /// Push a new trace record into the buffer. - /// If the buffer is full, it sends the records to the host. - fn push(&mut self, entry: TraceRecord) { - let mut write_index = self.write_index; - - self.entries[write_index] = entry; - write_index = (write_index + 1) % MAX_NO_OF_ENTRIES; - - self.write_index = write_index; - - if write_index == 0 { - // If buffer is full send to host - (self.send_to_host)(MAX_NO_OF_ENTRIES as u64, &self.entries); - } - } - - /// Flush the trace buffer, sending any remaining records to the host. - fn flush(&mut self) { - if self.write_index > 0 { - (self.send_to_host)(self.write_index as u64, &self.entries); - self.write_index = 0; // Reset write index after flushing - } - } -} - -/// Send the trace records to the host. -fn send_to_host(len: u64, records: &[TraceRecord]) { - unsafe { - core::arch::asm!("out dx, al", - in("dx") OutBAction::TraceRecord as u16, - in("rax") len, - in("rcx") records.as_ptr() as u64); - } -} - /// Module for checking invariant TSC support and reading the timestamp counter pub mod invariant_tsc { use core::arch::x86_64::{__cpuid, _rdtsc}; @@ -161,121 +154,223 @@ pub mod invariant_tsc { } } -/// Create a trace record from the message and push it to the trace buffer. -/// -/// **NOTE**: If the message is too long it will be truncated to fit within `MAX_TRACE_MSG_LEN`. -/// This is useful for ensuring that the trace buffer does not overflow. -pub fn create_trace_record(msg: &str) { - let entry = TraceRecord::from(msg); - let mut buffer = TRACE_BUFFER.lock(); +#[cfg(feature = "trace")] +mod trace { + // === Dependencies === + extern crate alloc; - buffer.push(entry); -} + use core::mem::MaybeUninit; -/// Flush the trace buffer to send any remaining trace records to the host. -pub fn flush_trace_buffer() { - let mut buffer = TRACE_BUFFER.lock(); - buffer.flush(); -} + use hyperlight_common::outb::OutBAction; + use spin::Mutex; + + use super::{MAX_TRACE_MSG_LEN, TraceRecord, invariant_tsc}; + + /// Type alias for the function that sends trace records to the host. + type SendToHostFn = fn(u64, &[TraceRecord]); -#[cfg(test)] -mod tests { - use alloc::format; + /// Global trace buffer for storing trace records. + static TRACE_BUFFER: Mutex> = + Mutex::new(TraceBuffer::new(send_to_host)); - use super::*; + /// Maximum number of entries in the trace buffer. + /// From local testing, 32 entries seems to be a good balance between performance and memory usage. + const MAX_NO_OF_ENTRIES: usize = 32; - /// This is a mock function for testing purposes. - /// In a real scenario, this would send the trace records to the host. - fn mock_send_to_host(_len: u64, _records: &[TraceRecord]) {} + impl From<&str> for TraceRecord { + fn from(mut msg: &str) -> Self { + if msg.len() > MAX_TRACE_MSG_LEN { + // If the message is too long, truncate it to fit the maximum length + msg = &msg[..MAX_TRACE_MSG_LEN]; + } - fn create_test_entry(msg: &str) -> TraceRecord { - let cycles = invariant_tsc::read_tsc(); + let cycles = invariant_tsc::read_tsc(); - TraceRecord { - cycles, - msg: { - let mut arr = [0u8; MAX_TRACE_MSG_LEN]; - arr[..msg.len()].copy_from_slice(msg.as_bytes()); - arr - }, - msg_len: msg.len(), + TraceRecord { + cycles, + msg: { + let mut arr = [0u8; MAX_TRACE_MSG_LEN]; + arr[..msg.len()].copy_from_slice(msg.as_bytes()); + arr + }, + msg_len: msg.len(), + } } } - #[test] - fn test_push_trace_record() { - let mut buffer = TraceBuffer::new(mock_send_to_host); + /// A buffer for storing trace records. + struct TraceBuffer { + /// The entries in the trace buffer. + entries: [TraceRecord; MAX_NO_OF_ENTRIES], + /// The index where the next entry will be written. + write_index: usize, + /// Function to send the trace records to the host. + send_to_host: F, + } - let msg = "Test message"; - let entry = create_test_entry(msg); + impl TraceBuffer { + /// Creates a new `TraceBuffer` with uninitialized entries. + const fn new(f: F) -> Self { + Self { + entries: unsafe { [MaybeUninit::zeroed().assume_init(); MAX_NO_OF_ENTRIES] }, + write_index: 0, + send_to_host: f, + } + } - buffer.push(entry); - assert_eq!(buffer.write_index, 1); - assert_eq!(buffer.entries[0].msg_len, msg.len()); - assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); - assert!(buffer.entries[0].cycles > 0); // Ensure cycles is set + /// Push a new trace record into the buffer. + /// If the buffer is full, it sends the records to the host. + fn push(&mut self, entry: TraceRecord) { + let mut write_index = self.write_index; + + self.entries[write_index] = entry; + write_index = (write_index + 1) % MAX_NO_OF_ENTRIES; + + self.write_index = write_index; + + if write_index == 0 { + // If buffer is full send to host + (self.send_to_host)(MAX_NO_OF_ENTRIES as u64, &self.entries); + } + } + + /// Flush the trace buffer, sending any remaining records to the host. + fn flush(&mut self) { + if self.write_index > 0 { + (self.send_to_host)(self.write_index as u64, &self.entries); + self.write_index = 0; // Reset write index after flushing + } + } } - #[test] - fn test_flush_trace_buffer() { - let mut buffer = TraceBuffer::new(mock_send_to_host); + /// Send the trace records to the host. + fn send_to_host(len: u64, records: &[TraceRecord]) { + unsafe { + core::arch::asm!("out dx, al", + in("dx") OutBAction::TraceRecord as u16, + in("rax") len, + in("rcx") records.as_ptr() as u64); + } + } - let msg = "Test message"; - let entry = create_test_entry(msg); + /// Create a trace record from the message and push it to the trace buffer. + /// + /// **NOTE**: If the message is too long it will be truncated to fit within `MAX_TRACE_MSG_LEN`. + /// This is useful for ensuring that the trace buffer does not overflow. + #[inline(always)] + pub fn create_trace_record(msg: &str) { + let entry = TraceRecord::from(msg); + let mut buffer = TRACE_BUFFER.lock(); buffer.push(entry); - assert_eq!(buffer.write_index, 1); - assert_eq!(buffer.entries[0].msg_len, msg.len()); - assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); - assert!(buffer.entries[0].cycles > 0); + } - // Flush the buffer + /// Flush the trace buffer to send any remaining trace records to the host. + #[inline(always)] + pub fn flush_trace_buffer() { + let mut buffer = TRACE_BUFFER.lock(); buffer.flush(); - - // After flushing, the entryes should still be intact, we don't clear them - assert_eq!(buffer.write_index, 0); - assert_eq!(buffer.entries[0].msg_len, msg.len()); - assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); - assert!(buffer.entries[0].cycles > 0); } - #[test] - fn test_auto_flush_on_full() { - let mut buffer = TraceBuffer::new(mock_send_to_host); + #[cfg(test)] + mod tests { + use alloc::format; + + use super::*; + + /// This is a mock function for testing purposes. + /// In a real scenario, this would send the trace records to the host. + fn mock_send_to_host(_len: u64, _records: &[TraceRecord]) {} + + fn create_test_entry(msg: &str) -> TraceRecord { + let cycles = invariant_tsc::read_tsc(); + + TraceRecord { + cycles, + msg: { + let mut arr = [0u8; MAX_TRACE_MSG_LEN]; + arr[..msg.len()].copy_from_slice(msg.as_bytes()); + arr + }, + msg_len: msg.len(), + } + } + + #[test] + fn test_push_trace_record() { + let mut buffer = TraceBuffer::new(mock_send_to_host); + + let msg = "Test message"; + let entry = create_test_entry(msg); - // Fill the buffer to trigger auto-flush - for i in 0..MAX_NO_OF_ENTRIES { - let msg = format!("Message {}", i); - let entry = create_test_entry(&msg); buffer.push(entry); + assert_eq!(buffer.write_index, 1); + assert_eq!(buffer.entries[0].msg_len, msg.len()); + assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); + assert!(buffer.entries[0].cycles > 0); // Ensure cycles is set } - // After filling, the write index should be 0 (buffer is full) - assert_eq!(buffer.write_index, 0); + #[test] + fn test_flush_trace_buffer() { + let mut buffer = TraceBuffer::new(mock_send_to_host); - // The first entry should still be intact - assert_eq!(buffer.entries[0].msg_len, "Message 0".len()); - } + let msg = "Test message"; + let entry = create_test_entry(msg); - /// Test TraceRecord creation with a valid message - #[test] - fn test_trace_record_creation_valid() { - let msg = "Valid message"; - let entry = TraceRecord::try_from(msg).expect("Failed to create TraceRecord"); - assert_eq!(entry.msg_len, msg.len()); - assert_eq!(&entry.msg[..msg.len()], msg.as_bytes()); - assert!(entry.cycles > 0); // Ensure cycles is set - } + buffer.push(entry); + assert_eq!(buffer.write_index, 1); + assert_eq!(buffer.entries[0].msg_len, msg.len()); + assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); + assert!(buffer.entries[0].cycles > 0); + + // Flush the buffer + buffer.flush(); + + // After flushing, the entryes should still be intact, we don't clear them + assert_eq!(buffer.write_index, 0); + assert_eq!(buffer.entries[0].msg_len, msg.len()); + assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); + assert!(buffer.entries[0].cycles > 0); + } + + #[test] + fn test_auto_flush_on_full() { + let mut buffer = TraceBuffer::new(mock_send_to_host); + + // Fill the buffer to trigger auto-flush + for i in 0..MAX_NO_OF_ENTRIES { + let msg = format!("Message {}", i); + let entry = create_test_entry(&msg); + buffer.push(entry); + } - /// Test TraceRecord creation with a message that exceeds the maximum length - #[test] - fn test_trace_record_creation_too_long() { - let long_msg = "A".repeat(MAX_TRACE_MSG_LEN + 1); - let result = TraceRecord::from(long_msg.as_str()); - assert_eq!(result.msg_len, MAX_TRACE_MSG_LEN); - assert_eq!( - &result.msg[..MAX_TRACE_MSG_LEN], - &long_msg.as_bytes()[..MAX_TRACE_MSG_LEN], - ); + // After filling, the write index should be 0 (buffer is full) + assert_eq!(buffer.write_index, 0); + + // The first entry should still be intact + assert_eq!(buffer.entries[0].msg_len, "Message 0".len()); + } + + /// Test TraceRecord creation with a valid message + #[test] + fn test_trace_record_creation_valid() { + let msg = "Valid message"; + let entry = TraceRecord::try_from(msg).expect("Failed to create TraceRecord"); + assert_eq!(entry.msg_len, msg.len()); + assert_eq!(&entry.msg[..msg.len()], msg.as_bytes()); + assert!(entry.cycles > 0); // Ensure cycles is set + } + + /// Test TraceRecord creation with a message that exceeds the maximum length + #[test] + fn test_trace_record_creation_too_long() { + let long_msg = "A".repeat(MAX_TRACE_MSG_LEN + 1); + let result = TraceRecord::from(long_msg.as_str()); + assert_eq!(result.msg_len, MAX_TRACE_MSG_LEN); + assert_eq!( + &result.msg[..MAX_TRACE_MSG_LEN], + &long_msg.as_bytes()[..MAX_TRACE_MSG_LEN], + ); + } } } diff --git a/src/hyperlight_guest_tracing_macro/Cargo.toml b/src/hyperlight_guest_tracing_macro/Cargo.toml index 6e749ac20..9fc1df9d5 100644 --- a/src/hyperlight_guest_tracing_macro/Cargo.toml +++ b/src/hyperlight_guest_tracing_macro/Cargo.toml @@ -16,6 +16,7 @@ syn = { version = "2.0.104", features = ["full"] } [features] default = [] +trace = [] [lib] proc-macro = true diff --git a/src/hyperlight_guest_tracing_macro/src/lib.rs b/src/hyperlight_guest_tracing_macro/src/lib.rs index 24b790864..22a5cdf0e 100644 --- a/src/hyperlight_guest_tracing_macro/src/lib.rs +++ b/src/hyperlight_guest_tracing_macro/src/lib.rs @@ -19,16 +19,7 @@ use quote::quote; use syn::{ItemFn, parse_macro_input}; /// A procedural macro attribute for tracing function calls. -/// Usage: -/// ```rust -/// #[hyperlight_guest_tracing_macro::trace_function] -/// fn my_function() { -/// // // Function body -/// } -/// ``` -/// -/// This macro will create a trace record when the function is called, if the `trace_guest` -/// feature is enabled. +/// This macro will create a trace record when the function is called /// /// The trace record will contain the function name as a string. /// Note: This macro is intended to be used with the `hyperlight_guest_tracing` crate. @@ -46,46 +37,64 @@ pub fn trace_function(_attr: TokenStream, item: TokenStream) -> TokenStream { // Compose entry/exit messages let entry_msg = format!("> {}", fn_name_str); - let exit_msg = format!("< {}", fn_name_str); + let _exit_msg = format!("< {}", fn_name_str); let expanded = match fn_output { syn::ReturnType::Default => { // No return value (unit) + #[cfg(feature = "trace")] quote! { #(#fn_attrs)* #fn_vis #fn_sig { - #[cfg(feature = "trace_guest")] const _: () = assert!( #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, "Trace message exceeds the maximum bytes length", ); - #[cfg(feature = "trace_guest")] ::hyperlight_guest_tracing::create_trace_record(#entry_msg); // Call the original function body #fn_block - #[cfg(feature = "trace_guest")] - ::hyperlight_guest_tracing::create_trace_record(#exit_msg); + ::hyperlight_guest_tracing::create_trace_record(#_exit_msg); + } + } + #[cfg(not(feature = "trace"))] + quote! { + #(#fn_attrs)* + #fn_vis #fn_sig { + const _: () = assert!( + #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, + "Trace message exceeds the maximum bytes length", + ); + #fn_block } } } syn::ReturnType::Type(_, _) => { // Has a return value + #[cfg(feature = "trace")] quote! { #(#fn_attrs)* #fn_vis #fn_sig { - #[cfg(feature = "trace_guest")] const _: () = assert!( #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, "Trace message exceeds the maximum bytes length", ); - #[cfg(feature = "trace_guest")] ::hyperlight_guest_tracing::create_trace_record(#entry_msg); let __trace_result = (|| #fn_block )(); - #[cfg(feature = "trace_guest")] - ::hyperlight_guest_tracing::create_trace_record(#exit_msg); + ::hyperlight_guest_tracing::create_trace_record(#_exit_msg); __trace_result } } + #[cfg(not(feature = "trace"))] + quote! { + #(#fn_attrs)* + #fn_vis #fn_sig { + const _: () = assert!( + #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, + "Trace message exceeds the maximum bytes length", + ); + #fn_block + } + } } }; @@ -104,6 +113,11 @@ impl syn::parse::Parse for TraceMacroInput { if !matches!(message, syn::Lit::Str(_)) { return Err(input.error("first argument to trace! must be a string literal")); } + if let syn::Lit::Str(ref lit_str) = message { + if lit_str.value().is_empty() { + return Err(input.error("trace message must not be empty")); + } + } let statement = if input.peek(syn::Token![,]) { let _: syn::Token![,] = input.parse()?; @@ -117,78 +131,8 @@ impl syn::parse::Parse for TraceMacroInput { /// This macro creates a trace record with a message, or traces a block with entry/exit records. /// -/// Usage: -/// ```rust -/// use hyperlight_guest_tracing_macro::trace; -/// trace!("message"); -/// trace!("message", { /* block of code */ }); -/// ``` -/// /// When called with an expression or statement as the second argument, it is wrapped in a block, /// entry and exit trace records are created at the start and end of block, and the result of the block is returned. -/// -/// # Examples -/// -/// ## Basic usage: trace with message only -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// trace!("hello"); -/// ``` -/// -/// ## Trace with a block, returning a value -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// let x = trace!("block", { 42 }); -/// assert_eq!(x, 42); -/// ``` -/// -/// ## Trace with a block using local variables -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// let y = 10; -/// let z = trace!("sum", { y + 5 }); -/// assert_eq!(z, 15); -/// ``` -/// -/// ## Trace with a block that returns a reference -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// let s = String::from("abc"); -/// let r: &str = trace!("ref", { &s }); -/// assert_eq!(r, "abc"); -/// ``` -/// -/// ## Control flow: `return` inside the block returns from the function -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// fn foo() -> i32 { -/// let _ = trace!("fail", { -/// // This return only exits the closure, not the function `foo`. -/// return 42; -/// }); -/// assert!(false, "This should not be reached"); -/// } -/// ``` -/// -/// ## Control flow: `break` inside the block exits the outer loop -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// let mut x = 0; -/// for i in 1..3 { -/// x = i; -/// let _ = trace!("msg", { -/// // This break should exit the loop. -/// break; -/// }); -/// } -/// assert_eq!(x, 1, "Loop should break after the first iteration"); -/// ``` #[proc_macro] pub fn trace(input: TokenStream) -> TokenStream { let parsed = syn::parse_macro_input!(input as TraceMacroInput); @@ -198,53 +142,68 @@ pub fn trace(input: TokenStream) -> TokenStream { }; if let Some(statement) = parsed.statement { let entry_msg = format!("+ {}", trace_message); - let exit_msg = format!("- {}", trace_message); + let _exit_msg = format!("- {}", trace_message); + #[cfg(feature = "trace")] let expanded = quote! { { - #[cfg(feature = "trace_guest")] const _: () = assert!( #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, "Trace message exceeds the maximum bytes length", ); - #[cfg(feature = "trace_guest")] ::hyperlight_guest_tracing::create_trace_record(#entry_msg); let __trace_result = #statement; - #[cfg(feature = "trace_guest")] - ::hyperlight_guest_tracing::create_trace_record(#exit_msg); + ::hyperlight_guest_tracing::create_trace_record(#_exit_msg); __trace_result } }; + #[cfg(not(feature = "trace"))] + let expanded = quote! { + { + const _: () = assert!( + #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, + "Trace message exceeds the maximum bytes length", + ); + #statement + } + }; + TokenStream::from(expanded) } else { + #[cfg(feature = "trace")] let expanded = quote! { { - #[cfg(feature = "trace_guest")] const _: () = assert!( #trace_message.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, "Trace message exceeds the maximum bytes length", ); - #[cfg(feature = "trace_guest")] ::hyperlight_guest_tracing::create_trace_record(#trace_message); } }; + #[cfg(not(feature = "trace"))] + let expanded = quote! { + { + const _: () = assert!( + #trace_message.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, + "Trace message exceeds the maximum bytes length", + ); + } + }; + TokenStream::from(expanded) } } /// This macro flushes the trace buffer, sending any remaining trace records to the host. -/// -/// Usage: -/// ```rust -/// hyperlight_guest_tracing_macro::flush!(); -/// ``` #[proc_macro] pub fn flush(_input: TokenStream) -> TokenStream { + #[cfg(feature = "trace")] let expanded = quote! { { - #[cfg(feature = "trace_guest")] ::hyperlight_guest_tracing::flush_trace_buffer(); } }; + #[cfg(not(feature = "trace"))] + let expanded = quote! {}; TokenStream::from(expanded) } diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 7ebead8e1..4a6bd4e1e 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -132,7 +132,7 @@ executable_heap = [] print_debug = [] # Dumps the VM state to a file on unexpected errors or crashes. The path of the file will be printed on stdout and logged. crashdump = ["dep:chrono"] -trace_guest = ["hyperlight-common/trace_guest", "dep:hyperlight-guest-tracing"] +trace_guest = ["hyperlight-common/trace_guest", "hyperlight-guest-tracing/trace"] # This feature enables unwinding the guest stack from the host, in # order to produce stack traces for debugging or profiling. unwind_guest = [ "trace_guest", "dep:framehop", "dep:fallible-iterator", "hyperlight-common/unwind_guest" ] diff --git a/src/tests/rust_guests/callbackguest/Cargo.lock b/src/tests/rust_guests/callbackguest/Cargo.lock index 24c80469e..e1de2399e 100644 --- a/src/tests/rust_guests/callbackguest/Cargo.lock +++ b/src/tests/rust_guests/callbackguest/Cargo.lock @@ -36,6 +36,7 @@ dependencies = [ "hyperlight-common", "hyperlight-guest", "hyperlight-guest-bin", + "hyperlight-guest-tracing", ] [[package]] diff --git a/src/tests/rust_guests/callbackguest/Cargo.toml b/src/tests/rust_guests/callbackguest/Cargo.toml index 2d63452e4..b1040eb5d 100644 --- a/src/tests/rust_guests/callbackguest/Cargo.toml +++ b/src/tests/rust_guests/callbackguest/Cargo.toml @@ -7,9 +7,10 @@ edition = "2021" hyperlight-guest = { path = "../../../hyperlight_guest" } hyperlight-guest-bin = { path = "../../../hyperlight_guest_bin" } hyperlight-common = { path = "../../../hyperlight_common", default-features = false } +hyperlight-guest-tracing = { path = "../../../hyperlight_guest_tracing" } [features] default = [] -trace_guest = ["hyperlight-guest-bin/trace_guest"] +trace_guest = ["hyperlight-guest-bin/trace_guest", "hyperlight-guest/trace_guest", "hyperlight-guest-tracing/trace"] unwind_guest = ["hyperlight-common/unwind_guest"] -mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] \ No newline at end of file +mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] diff --git a/src/tests/rust_guests/callbackguest/src/main.rs b/src/tests/rust_guests/callbackguest/src/main.rs index 0b79d578e..d217ccd88 100644 --- a/src/tests/rust_guests/callbackguest/src/main.rs +++ b/src/tests/rust_guests/callbackguest/src/main.rs @@ -37,6 +37,7 @@ use hyperlight_guest_bin::guest_function::register::register_function; use hyperlight_guest_bin::guest_logger::log_message; use hyperlight_guest_bin::host_comm::{call_host_function, print_output_with_host_print}; +#[hyperlight_guest_tracing::trace_function] fn send_message_to_host_method( method_name: &str, guest_message: &str, @@ -52,6 +53,7 @@ fn send_message_to_host_method( Ok(get_flatbuffer_result(res)) } +#[hyperlight_guest_tracing::trace_function] fn guest_function(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("HostMethod", "Hello from GuestFunction, ", message) @@ -63,6 +65,7 @@ fn guest_function(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn guest_function1(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("HostMethod1", "Hello from GuestFunction1, ", message) @@ -74,6 +77,7 @@ fn guest_function1(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn guest_function2(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("HostMethod1", "Hello from GuestFunction2, ", message) @@ -85,6 +89,7 @@ fn guest_function2(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn guest_function3(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("HostMethod1", "Hello from GuestFunction3, ", message) @@ -96,6 +101,7 @@ fn guest_function3(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn guest_function4(_: &FunctionCall) -> Result> { call_host_function::<()>( "HostMethod4", @@ -108,6 +114,7 @@ fn guest_function4(_: &FunctionCall) -> Result> { Ok(get_flatbuffer_result(())) } +#[hyperlight_guest_tracing::trace_function] fn guest_log_message(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(message), @@ -141,6 +148,7 @@ fn guest_log_message(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn call_error_method(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("ErrorMethod", "Error From Host: ", message) @@ -152,11 +160,13 @@ fn call_error_method(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn call_host_spin(_: &FunctionCall) -> Result> { call_host_function::<()>("Spin", None, ReturnType::Void)?; Ok(get_flatbuffer_result(())) } +#[hyperlight_guest_tracing::trace_function] fn host_call_loop(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { loop { @@ -171,6 +181,7 @@ fn host_call_loop(function_call: &FunctionCall) -> Result> { } #[no_mangle] +#[hyperlight_guest_tracing::trace_function] pub extern "C" fn hyperlight_main() { let print_output_def = GuestFunctionDefinition::new( "PrintOutput".to_string(), @@ -258,6 +269,7 @@ pub extern "C" fn hyperlight_main() { } #[no_mangle] +#[hyperlight_guest_tracing::trace_function] pub fn guest_dispatch_function(function_call: FunctionCall) -> Result> { Err(HyperlightGuestError::new( ErrorCode::GuestFunctionNotFound, diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index 07672d6f1..db313889c 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -231,6 +231,7 @@ dependencies = [ "hyperlight-common", "hyperlight-guest", "hyperlight-guest-bin", + "hyperlight-guest-tracing", "log", ] diff --git a/src/tests/rust_guests/simpleguest/Cargo.toml b/src/tests/rust_guests/simpleguest/Cargo.toml index 515b618d5..8748bdc0b 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.toml +++ b/src/tests/rust_guests/simpleguest/Cargo.toml @@ -7,11 +7,12 @@ edition = "2021" hyperlight-guest = { path = "../../../hyperlight_guest" } hyperlight-guest-bin = { path = "../../../hyperlight_guest_bin" } hyperlight-common = { path = "../../../hyperlight_common", default-features = false } +hyperlight-guest-tracing = { path = "../../../hyperlight_guest_tracing" } log = {version = "0.4", default-features = false } [features] default = [] -trace_guest = ["hyperlight-guest-bin/trace_guest"] +trace_guest = ["hyperlight-guest-bin/trace_guest", "hyperlight-guest/trace_guest", "hyperlight-guest-tracing/trace"] unwind_guest = ["hyperlight-common/unwind_guest"] mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index 405087e25..5b5fe4dcf 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -56,6 +56,7 @@ extern crate hyperlight_guest; static mut BIGARRAY: [i32; 1024 * 1024] = [0; 1024 * 1024]; +#[hyperlight_guest_tracing::trace_function] fn set_static(_: &FunctionCall) -> Result> { unsafe { #[allow(static_mut_refs)] @@ -67,6 +68,7 @@ fn set_static(_: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn echo_double(function_call: &FunctionCall) -> Result> { if let ParameterValue::Double(value) = function_call.parameters.clone().unwrap()[0].clone() { Ok(get_flatbuffer_result(value)) @@ -78,6 +80,7 @@ fn echo_double(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn echo_float(function_call: &FunctionCall) -> Result> { if let ParameterValue::Float(value) = function_call.parameters.clone().unwrap()[0].clone() { Ok(get_flatbuffer_result(value)) @@ -89,6 +92,7 @@ fn echo_float(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_output(message: &str) -> Result> { let res = call_host_function::( "HostPrint", @@ -99,6 +103,7 @@ fn print_output(message: &str) -> Result> { Ok(get_flatbuffer_result(res)) } +#[hyperlight_guest_tracing::trace_function] fn simple_print_output(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = function_call.parameters.clone().unwrap()[0].clone() { print_output(&message) @@ -110,6 +115,7 @@ fn simple_print_output(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn set_byte_array_to_zero(function_call: &FunctionCall) -> Result> { if let ParameterValue::VecBytes(mut vec) = function_call.parameters.clone().unwrap()[0].clone() { @@ -123,6 +129,7 @@ fn set_byte_array_to_zero(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_two_args(function_call: &FunctionCall) -> Result> { if let (ParameterValue::String(arg1), ParameterValue::Int(arg2)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -138,6 +145,7 @@ fn print_two_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_three_args(function_call: &FunctionCall) -> Result> { if let (ParameterValue::String(arg1), ParameterValue::Int(arg2), ParameterValue::Long(arg3)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -154,6 +162,7 @@ fn print_three_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_four_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -179,6 +188,7 @@ fn print_four_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_five_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -206,6 +216,7 @@ fn print_five_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_six_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -235,6 +246,7 @@ fn print_six_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_seven_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -266,6 +278,7 @@ fn print_seven_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_eight_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -299,6 +312,7 @@ fn print_eight_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_nine_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -334,6 +348,7 @@ fn print_nine_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_ten_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -371,6 +386,7 @@ fn print_ten_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn print_eleven_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -410,6 +426,7 @@ fn print_eleven_args(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn buffer_overrun(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(value) = function_call.parameters.clone().unwrap()[0].clone() { let c_str = value.as_str(); @@ -432,6 +449,7 @@ fn buffer_overrun(function_call: &FunctionCall) -> Result> { } #[allow(unconditional_recursion)] +#[hyperlight_guest_tracing::trace_function] fn infinite_recursion(_a: &FunctionCall) -> Result> { // blackbox is needed so something //is written to the stack in release mode, @@ -441,6 +459,7 @@ fn infinite_recursion(_a: &FunctionCall) -> Result> { infinite_recursion(_a) } +#[hyperlight_guest_tracing::trace_function] fn stack_overflow(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(i) = function_call.parameters.clone().unwrap()[0].clone() { loop_stack_overflow(i); @@ -453,6 +472,7 @@ fn stack_overflow(function_call: &FunctionCall) -> Result> { } } // This function will allocate i * (8KiB + 1B) on the stack +#[hyperlight_guest_tracing::trace_function] fn loop_stack_overflow(i: i32) { if i > 0 { let _nums = black_box([0u8; 0x2000 + 1]); // chkstk guaranteed to be called for > 8KiB @@ -460,16 +480,19 @@ fn loop_stack_overflow(i: i32) { } } +#[hyperlight_guest_tracing::trace_function] fn large_var(_: &FunctionCall) -> Result> { let _buffer = black_box([0u8; (DEFAULT_GUEST_STACK_SIZE + 1) as usize]); Ok(get_flatbuffer_result(DEFAULT_GUEST_STACK_SIZE + 1)) } +#[hyperlight_guest_tracing::trace_function] fn small_var(_: &FunctionCall) -> Result> { let _buffer = black_box([0u8; 1024]); Ok(get_flatbuffer_result(1024)) } +#[hyperlight_guest_tracing::trace_function] fn call_malloc(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(size) = function_call.parameters.clone().unwrap()[0].clone() { // will panic if OOM, and we need blackbox to avoid optimizing away this test @@ -484,6 +507,7 @@ fn call_malloc(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn malloc_and_free(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(size) = function_call.parameters.clone().unwrap()[0].clone() { let alloc_length = if size < DEFAULT_GUEST_STACK_SIZE { @@ -503,6 +527,7 @@ fn malloc_and_free(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn echo(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(value) = function_call.parameters.clone().unwrap()[0].clone() { Ok(get_flatbuffer_result(&*value)) @@ -514,6 +539,7 @@ fn echo(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn get_size_prefixed_buffer(function_call: &FunctionCall) -> Result> { if let ParameterValue::VecBytes(data) = function_call.parameters.clone().unwrap()[0].clone() { Ok(get_flatbuffer_result(&*data)) @@ -538,6 +564,7 @@ fn spin(_: &FunctionCall) -> Result> { Ok(get_flatbuffer_result(())) } +#[hyperlight_guest_tracing::trace_function] fn test_abort(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(code) = function_call.parameters.clone().unwrap()[0].clone() { abort_with_code(&[code as u8]); @@ -545,6 +572,7 @@ fn test_abort(function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result(())) } +#[hyperlight_guest_tracing::trace_function] fn test_abort_with_code_and_message(function_call: &FunctionCall) -> Result> { if let (ParameterValue::Int(code), ParameterValue::String(message)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -557,6 +585,7 @@ fn test_abort_with_code_and_message(function_call: &FunctionCall) -> Result Result> { if let ParameterValue::String(message) = function_call.parameters.clone().unwrap()[0].clone() { panic!("{}", message); @@ -564,6 +593,7 @@ fn test_guest_panic(function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result(())) } +#[hyperlight_guest_tracing::trace_function] fn test_write_raw_ptr(function_call: &FunctionCall) -> Result> { if let ParameterValue::Long(offset) = function_call.parameters.clone().unwrap()[0].clone() { let min_stack_addr = unsafe { MIN_STACK_ADDRESS }; @@ -587,6 +617,7 @@ fn test_write_raw_ptr(function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result("fail")) } +#[hyperlight_guest_tracing::trace_function] fn execute_on_stack(_function_call: &FunctionCall) -> Result> { unsafe { let mut noop: u8 = 0x90; @@ -596,6 +627,7 @@ fn execute_on_stack(_function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result("fail")) } +#[hyperlight_guest_tracing::trace_function] fn execute_on_heap(_function_call: &FunctionCall) -> Result> { unsafe { // NO-OP followed by RET @@ -608,6 +640,7 @@ fn execute_on_heap(_function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result("fail")) } +#[hyperlight_guest_tracing::trace_function] fn test_rust_malloc(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(code) = function_call.parameters.clone().unwrap()[0].clone() { let ptr = unsafe { malloc(code as usize) }; @@ -620,6 +653,7 @@ fn test_rust_malloc(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn log_message(function_call: &FunctionCall) -> Result> { if let (ParameterValue::String(message), ParameterValue::Int(level)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -642,6 +676,7 @@ fn log_message(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn trigger_exception(_: &FunctionCall) -> Result> { unsafe { core::arch::asm!("ud2"); @@ -651,6 +686,7 @@ fn trigger_exception(_: &FunctionCall) -> Result> { static mut COUNTER: i32 = 0; +#[hyperlight_guest_tracing::trace_function] fn add_to_static(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(i) = function_call.parameters.clone().unwrap()[0].clone() { let res = unsafe { @@ -666,6 +702,7 @@ fn add_to_static(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn get_static(function_call: &FunctionCall) -> Result> { if function_call.parameters.is_none() { Ok(get_flatbuffer_result(unsafe { COUNTER })) @@ -677,6 +714,7 @@ fn get_static(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn add_to_static_and_fail(_: &FunctionCall) -> Result> { unsafe { COUNTER += 10; @@ -687,6 +725,7 @@ fn add_to_static_and_fail(_: &FunctionCall) -> Result> { )) } +#[hyperlight_guest_tracing::trace_function] fn violate_seccomp_filters(function_call: &FunctionCall) -> Result> { if function_call.parameters.is_none() { let res = call_host_function::("MakeGetpidSyscall", None, ReturnType::ULong)?; @@ -700,6 +739,7 @@ fn violate_seccomp_filters(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn call_given_paramless_hostfunc_that_returns_i64(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(hostfuncname) = function_call.parameters.clone().unwrap()[0].clone() @@ -715,6 +755,7 @@ fn call_given_paramless_hostfunc_that_returns_i64(function_call: &FunctionCall) } } +#[hyperlight_guest_tracing::trace_function] fn add(function_call: &FunctionCall) -> Result> { if let (ParameterValue::Int(a), ParameterValue::Int(b)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -735,6 +776,7 @@ fn add(function_call: &FunctionCall) -> Result> { } // Does nothing, but used for testing large parameters +#[hyperlight_guest_tracing::trace_function] fn large_parameters(function_call: &FunctionCall) -> Result> { if let (ParameterValue::VecBytes(v), ParameterValue::String(s)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -750,6 +792,7 @@ fn large_parameters(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn read_from_user_memory(function_call: &FunctionCall) -> Result> { if let (ParameterValue::ULong(num), ParameterValue::VecBytes(expected)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -775,6 +818,7 @@ fn read_from_user_memory(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn read_mapped_buffer(function_call: &FunctionCall) -> Result> { if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -798,6 +842,7 @@ fn read_mapped_buffer(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn write_mapped_buffer(function_call: &FunctionCall) -> Result> { if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -825,6 +870,7 @@ fn write_mapped_buffer(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] fn exec_mapped_buffer(function_call: &FunctionCall) -> Result> { if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -853,6 +899,7 @@ fn exec_mapped_buffer(function_call: &FunctionCall) -> Result> { } #[no_mangle] +#[hyperlight_guest_tracing::trace_function] pub extern "C" fn hyperlight_main() { let read_from_user_memory_def = GuestFunctionDefinition::new( "ReadFromUserMemory".to_string(), @@ -1301,6 +1348,7 @@ pub extern "C" fn hyperlight_main() { } #[no_mangle] +#[hyperlight_guest_tracing::trace_function] pub fn guest_dispatch_function(function_call: FunctionCall) -> Result> { // This test checks the stack behavior of the input/output buffer // by calling the host before serializing the function call. @@ -1346,6 +1394,7 @@ pub fn guest_dispatch_function(function_call: FunctionCall) -> Result> { } // Interprets the given guest function call as a host function call and dispatches it to the host. +#[hyperlight_guest_tracing::trace_function] fn fuzz_host_function(func: FunctionCall) -> Result> { let mut params = func.parameters.unwrap(); // first parameter must be string (the name of the host function to call) diff --git a/src/tests/rust_guests/witguest/Cargo.toml b/src/tests/rust_guests/witguest/Cargo.toml index 0be5aec00..611b96b29 100644 --- a/src/tests/rust_guests/witguest/Cargo.toml +++ b/src/tests/rust_guests/witguest/Cargo.toml @@ -11,6 +11,6 @@ hyperlight-component-macro = { path = "../../../hyperlight_component_macro" } [features] default = [] -trace_guest = ["hyperlight-guest-bin/trace_guest"] +trace_guest = ["hyperlight-guest-bin/trace_guest", "hyperlight-guest/trace_guest"] unwind_guest = ["hyperlight-common/unwind_guest"] -mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] \ No newline at end of file +mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] From 652affb5811a524db8a9a5a232820fb2e7cda7f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 04:22:38 +0000 Subject: [PATCH 079/271] Bump signal-hook-registry from 1.4.5 to 1.4.6 (#760) Bumps [signal-hook-registry](https://github.com/vorner/signal-hook) from 1.4.5 to 1.4.6. - [Changelog](https://github.com/vorner/signal-hook/blob/master/CHANGELOG.md) - [Commits](https://github.com/vorner/signal-hook/compare/registry-v1.4.5...registry-v1.4.6) --- updated-dependencies: - dependency-name: signal-hook-registry dependency-version: 1.4.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4c414c09a..49331334d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3223,9 +3223,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 4a6bd4e1e..932d754a9 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -83,7 +83,7 @@ mshv-ioctls3 = { package="mshv-ioctls", version = "=0.3.2", optional = true} [dev-dependencies] uuid = { version = "1.17.0", features = ["v4"] } -signal-hook-registry = "1.4.5" +signal-hook-registry = "1.4.6" envy = { version = "0.4.2" } serde = "1.0" proptest = "1.7.0" From 70a856f516ba8bd9dbee641c07ee117362d20992 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Tue, 5 Aug 2025 14:14:28 -0700 Subject: [PATCH 080/271] Fix some cargo docs (#749) * Fix cargo doc warnings Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Update docs for UninitializedSandbox Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Update docs for MultiUseSandbox Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Add crate-level docs to lib.rs Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Test cargo doc on ci Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --------- Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- Justfile | 4 +- .../src/flatbuffer_wrappers/function_types.rs | 8 +- src/hyperlight_host/src/func/ret_type.rs | 4 +- src/hyperlight_host/src/func/utils.rs | 7 +- src/hyperlight_host/src/lib.rs | 22 ++- src/hyperlight_host/src/mem/shared_mem.rs | 30 ++-- .../src/sandbox/initialized_multi_use.rs | 153 +++++++++++++++--- src/hyperlight_host/src/sandbox/snapshot.rs | 2 +- .../src/sandbox/uninitialized.rs | 73 +++++---- 9 files changed, 218 insertions(+), 85 deletions(-) diff --git a/Justfile b/Justfile index e6cf371bb..9ae49e3d2 100644 --- a/Justfile +++ b/Justfile @@ -143,7 +143,7 @@ like-ci config=default-target hypervisor="kvm": just bench-ci main {{config}} {{ if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } }} # runs all tests -test target=default-target features="": (test-unit target features) (test-isolated target features) (test-integration "rust" target features) (test-integration "c" target features) (test-seccomp target features) +test target=default-target features="": (test-unit target features) (test-isolated target features) (test-integration "rust" target features) (test-integration "c" target features) (test-seccomp target features) (test-doc target features) # runs unit tests test-unit target=default-target features="": @@ -218,6 +218,8 @@ test-rust-tracing target=default-target features="": just build-rust-guests {{ target }} just move-rust-guests {{ target }} +test-doc target=default-target features="": + cargo test --profile={{ if target == "debug" { "dev" } else { target } }} {{ if features =="" {''} else { "--features " + features } }} --doc ################ ### LINTING #### ################ diff --git a/src/hyperlight_common/src/flatbuffer_wrappers/function_types.rs b/src/hyperlight_common/src/flatbuffer_wrappers/function_types.rs index b726140db..b381da592 100644 --- a/src/hyperlight_common/src/flatbuffer_wrappers/function_types.rs +++ b/src/hyperlight_common/src/flatbuffer_wrappers/function_types.rs @@ -51,7 +51,7 @@ pub enum ParameterValue { String(String), /// bool Bool(bool), - /// Vec + /// `Vec` VecBytes(Vec), } @@ -75,7 +75,7 @@ pub enum ParameterType { String, /// bool Bool, - /// Vec + /// `Vec` VecBytes, } @@ -100,7 +100,7 @@ pub enum ReturnValue { Bool(bool), /// () Void(()), - /// Vec + /// `Vec` VecBytes(Vec), } @@ -128,7 +128,7 @@ pub enum ReturnType { Bool, /// () Void, - /// Vec + /// `Vec` VecBytes, } diff --git a/src/hyperlight_host/src/func/ret_type.rs b/src/hyperlight_host/src/func/ret_type.rs index e4b69e7bc..89fe1481f 100644 --- a/src/hyperlight_host/src/func/ret_type.rs +++ b/src/hyperlight_host/src/func/ret_type.rs @@ -32,12 +32,12 @@ pub trait SupportedReturnType: Sized + Clone + Send + Sync + 'static { fn from_value(value: ReturnValue) -> Result; } -/// A trait to handle either a SupportedReturnType or a Result +/// A trait to handle either a [`SupportedReturnType`] or a [`Result`] pub trait ResultType { /// The return type of the supported return value type ReturnType: SupportedReturnType; - /// Convert the return type into a Result + /// Convert the return type into a `Result` fn into_result(self) -> Result; } diff --git a/src/hyperlight_host/src/func/utils.rs b/src/hyperlight_host/src/func/utils.rs index f06c35a3c..6e92ca041 100644 --- a/src/hyperlight_host/src/func/utils.rs +++ b/src/hyperlight_host/src/func/utils.rs @@ -18,10 +18,9 @@ limitations under the License. /// up to 32 parameters. This is useful to implement traits on functions /// for may parameter tuples. /// -/// Usage: -/// ```rust -/// use hyperlight_host::func::for_each_tuple; +/// This is an internal utility macro used within the func module. /// +/// ```ignore /// macro_rules! my_macro { /// ([$count:expr] ($($name:ident: $type:ident),*)) => { /// // $count is the arity of the tuple @@ -30,7 +29,7 @@ limitations under the License. /// }; /// } /// -/// for_each_tuple!(impl_host_function); +/// for_each_tuple!(my_macro); /// ``` macro_rules! for_each_tuple { (@ diff --git a/src/hyperlight_host/src/lib.rs b/src/hyperlight_host/src/lib.rs index 7e6a69a9c..9a32a9ecc 100644 --- a/src/hyperlight_host/src/lib.rs +++ b/src/hyperlight_host/src/lib.rs @@ -14,8 +14,26 @@ See the License for the specific language governing permissions and limitations under the License. */ #![warn(dead_code, missing_docs, unused_mut)] -//! This crate contains an SDK that is used to execute specially- -// compiled binaries within a very lightweight hypervisor environment. +//! Hyperlight host runtime for executing guest code in lightweight virtual machines. +//! +//! This crate provides the host-side runtime for Hyperlight, enabling safe execution +//! of untrusted guest code within micro virtual machines with minimal overhead. +//! The runtime manages sandbox creation, guest function calls, memory isolation, +//! and host-guest communication. +//! +//! The primary entry points are [`UninitializedSandbox`] for initial setup and +//! [`MultiUseSandbox`] for executing guest functions. +//! +//! ## Guest Requirements +//! +//! Hyperlight requires specially compiled guest binaries and cannot run regular +//! container images or executables. Guests must be built using either the Rust +//! API ([`hyperlight_guest`] with optional use of [`hyperlight_guest_bin`]), +//! or with the C API (`hyperlight_guest_capi`). +//! +//! [`hyperlight_guest`]: https://docs.rs/hyperlight_guest +//! [`hyperlight_guest_bin`]: https://docs.rs/hyperlight_guest_bin +//! #![cfg_attr(not(any(test, debug_assertions)), warn(clippy::panic))] #![cfg_attr(not(any(test, debug_assertions)), warn(clippy::expect_used))] diff --git a/src/hyperlight_host/src/mem/shared_mem.rs b/src/hyperlight_host/src/mem/shared_mem.rs index e61e1b7ee..bd39a73fd 100644 --- a/src/hyperlight_host/src/mem/shared_mem.rs +++ b/src/hyperlight_host/src/mem/shared_mem.rs @@ -183,11 +183,11 @@ unsafe impl Send for GuestSharedMemory {} /// /// Unfortunately, there appears to be no way to do this with defined /// behaviour in present Rust (see -/// e.g. https://github.com/rust-lang/unsafe-code-guidelines/issues/152). +/// e.g. ). /// Rust does not yet have its own defined memory model, but in the /// interim, it is widely treated as inheriting the current C/C++ /// memory models. The most immediate problem is that regardless of -/// anything else, under those memory models [1, p. 17-18; 2, p. 88], +/// anything else, under those memory models \[1, p. 17-18; 2, p. 88\], /// /// > The execution of a program contains a _data race_ if it /// > contains two [C++23: "potentially concurrent"] conflicting @@ -205,7 +205,7 @@ unsafe impl Send for GuestSharedMemory {} /// Despite Rust's de jure inheritance of the C memory model at the /// present time, the compiler in many cases de facto adheres to LLVM /// semantics, so it is worthwhile to consider what LLVM does in this -/// case as well. According to the the LangRef [3] memory model, +/// case as well. According to the the LangRef \[3\] memory model, /// loads which are involved in a race that includes at least one /// non-atomic access (whether the load or a store) return `undef`, /// making them roughly equivalent to reading uninitialized @@ -213,20 +213,20 @@ unsafe impl Send for GuestSharedMemory {} /// /// Considering a different direction, recent C++ papers have seemed /// to lean towards using `volatile` for similar use cases. For -/// example, in P1152R0 [4], JF Bastien notes that +/// example, in P1152R0 \[4\], JF Bastien notes that /// /// > We’ve shown that volatile is purposely defined to denote /// > external modifications. This happens for: /// > - Shared memory with untrusted code, where volatile is the /// > right way to avoid time-of-check time-of-use (ToCToU) -/// > races which lead to security bugs such as [PWN2OWN] and -/// > [XENXSA155]. +/// > races which lead to security bugs such as \[PWN2OWN\] and +/// > \[XENXSA155\]. /// /// Unfortunately, although this paper was adopted for C++20 (and, /// sadly, mostly un-adopted for C++23, although that does not concern /// us), the paper did not actually redefine volatile accesses or data /// races to prevent volatile accesses from racing with other accesses -/// and causing undefined behaviour. P1382R1 [5] would have amended +/// and causing undefined behaviour. P1382R1 \[5\] would have amended /// the wording of the data race definition to specifically exclude /// volatile, but, unfortunately, despite receiving a /// generally-positive reception at its first WG21 meeting more than @@ -272,8 +272,8 @@ unsafe impl Send for GuestSharedMemory {} /// the guest in this case. Unfortunately, while those operations are /// defined in LLVM, they are not presently exposed to Rust. While /// atomic fences that are not associated with memory accesses -/// (std::sync::atomic::fence) might at first glance seem to help with -/// this problem, they unfortunately do not [6]: +/// ([`std::sync::atomic::fence`]) might at first glance seem to help with +/// this problem, they unfortunately do not \[6\]: /// /// > A fence ‘A’ which has (at least) Release ordering semantics, /// > synchronizes with a fence ‘B’ with (at least) Acquire @@ -289,12 +289,12 @@ unsafe impl Send for GuestSharedMemory {} /// fence on a vmenter/vmexit between data being read and written. /// This is unsafe (not guaranteed in the type system)! /// -/// [1] N3047 C23 Working Draft. https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf -/// [2] N4950 C++23 Working Draft. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4950.pdf -/// [3] LLVM Language Reference Manual, Memory Model for Concurrent Operations. https://llvm.org/docs/LangRef.html#memmodel -/// [4] P1152R0: Deprecating `volatile`. JF Bastien. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1152r0.html -/// [5] P1382R1: `volatile_load` and `volatile_store`. JF Bastien, Paul McKenney, Jeffrey Yasskin, and the indefatigable TBD. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1382r1.pdf -/// [6] Documentation for std::sync::atomic::fence. https://doc.rust-lang.org/std/sync/atomic/fn.fence.html +/// \[1\] N3047 C23 Working Draft. +/// \[2\] N4950 C++23 Working Draft. +/// \[3\] LLVM Language Reference Manual, Memory Model for Concurrent Operations. +/// \[4\] P1152R0: Deprecating `volatile`. JF Bastien. +/// \[5\] P1382R1: `volatile_load` and `volatile_store`. JF Bastien, Paul McKenney, Jeffrey Yasskin, and the indefatigable TBD. +/// \[6\] Documentation for std::sync::atomic::fence. #[derive(Clone, Debug)] pub struct HostSharedMemory { region: Arc, diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 6b925f264..7692a4379 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -49,14 +49,10 @@ use crate::{HyperlightError, Result, log_then_return}; /// Global counter for assigning unique IDs to sandboxes static SANDBOX_ID_COUNTER: AtomicU64 = AtomicU64::new(0); -/// A sandbox that supports being used Multiple times. -/// The implication of being used multiple times is two-fold: +/// A fully initialized sandbox that can execute guest functions multiple times. /// -/// 1. The sandbox can be used to call guest functions multiple times, each time a -/// guest function is called the state of the sandbox is reset to the state it was in before the call was made. -/// -/// 2. A MultiUseGuestCallContext can be created from the sandbox and used to make multiple guest function calls to the Sandbox. -/// in this case the state of the sandbox is not reset until the context is finished and the `MultiUseSandbox` is returned. +/// Guest functions can be called repeatedly while maintaining state between calls. +/// The sandbox supports creating snapshots and restoring to previous states. pub struct MultiUseSandbox { /// Unique identifier for this sandbox instance id: u64, @@ -94,7 +90,29 @@ impl MultiUseSandbox { } } - /// Create a snapshot of the current state of the sandbox's memory. + /// Creates a snapshot of the sandbox's current memory state. + /// + /// The snapshot is tied to this specific sandbox instance and can only be + /// restored to the same sandbox it was created from. + /// + /// # Examples + /// + /// ```no_run + /// # use hyperlight_host::{MultiUseSandbox, UninitializedSandbox, GuestBinary}; + /// # fn example() -> Result<(), Box> { + /// let mut sandbox: MultiUseSandbox = UninitializedSandbox::new( + /// GuestBinary::FilePath("guest.bin".into()), + /// None + /// )?.evolve()?; + /// + /// // Modify sandbox state + /// sandbox.call_guest_function_by_name::("SetValue", 42)?; + /// + /// // Create snapshot belonging to this sandbox + /// let snapshot = sandbox.snapshot()?; + /// # Ok(()) + /// # } + /// ``` #[instrument(err(Debug), skip_all, parent = Span::current())] pub fn snapshot(&mut self) -> Result { let mapped_regions_iter = self.vm.get_mapped_regions(); @@ -108,7 +126,37 @@ impl MultiUseSandbox { }) } - /// Restore the sandbox's memory to the state captured in the given snapshot. + /// Restores the sandbox's memory to a previously captured snapshot state. + /// + /// The snapshot must have been created from this same sandbox instance. + /// Attempting to restore a snapshot from a different sandbox will return + /// a [`SnapshotSandboxMismatch`](crate::HyperlightError::SnapshotSandboxMismatch) error. + /// + /// # Examples + /// + /// ```no_run + /// # use hyperlight_host::{MultiUseSandbox, UninitializedSandbox, GuestBinary}; + /// # fn example() -> Result<(), Box> { + /// let mut sandbox: MultiUseSandbox = UninitializedSandbox::new( + /// GuestBinary::FilePath("guest.bin".into()), + /// None + /// )?.evolve()?; + /// + /// // Take initial snapshot from this sandbox + /// let snapshot = sandbox.snapshot()?; + /// + /// // Modify sandbox state + /// sandbox.call_guest_function_by_name::("SetValue", 100)?; + /// let value: i32 = sandbox.call_guest_function_by_name("GetValue", ())?; + /// assert_eq!(value, 100); + /// + /// // Restore to previous state (same sandbox) + /// sandbox.restore(&snapshot)?; + /// let restored_value: i32 = sandbox.call_guest_function_by_name("GetValue", ())?; + /// assert_eq!(restored_value, 0); // Back to initial state + /// # Ok(()) + /// # } + /// ``` #[instrument(err(Debug), skip_all, parent = Span::current())] pub fn restore(&mut self, snapshot: &Snapshot) -> Result<()> { if self.id != snapshot.inner.sandbox_id() { @@ -136,8 +184,37 @@ impl MultiUseSandbox { Ok(()) } - /// Call a guest function by name, with the given return type and arguments. - /// The changes made to the sandbox are persisted + /// Calls a guest function by name with the specified arguments. + /// + /// Changes made to the sandbox during execution are persisted. + /// + /// # Examples + /// + /// ```no_run + /// # use hyperlight_host::{MultiUseSandbox, UninitializedSandbox, GuestBinary}; + /// # fn example() -> Result<(), Box> { + /// let mut sandbox: MultiUseSandbox = UninitializedSandbox::new( + /// GuestBinary::FilePath("guest.bin".into()), + /// None + /// )?.evolve()?; + /// + /// // Call function with no arguments + /// let result: i32 = sandbox.call_guest_function_by_name("GetCounter", ())?; + /// + /// // Call function with single argument + /// let doubled: i32 = sandbox.call_guest_function_by_name("Double", 21)?; + /// assert_eq!(doubled, 42); + /// + /// // Call function with multiple arguments + /// let sum: i32 = sandbox.call_guest_function_by_name("Add", (10, 32))?; + /// assert_eq!(sum, 42); + /// + /// // Call function returning string + /// let message: String = sandbox.call_guest_function_by_name("Echo", "Hello, World!".to_string())?; + /// assert_eq!(message, "Hello, World!"); + /// # Ok(()) + /// # } + /// ``` #[instrument(err(Debug), skip(self, args), parent = Span::current())] pub fn call_guest_function_by_name( &mut self, @@ -154,19 +231,16 @@ impl MultiUseSandbox { }) } - /// Map a region of host memory into the sandbox. - /// - /// Depending on the host platform, there are likely alignment - /// requirements of at least one page for base and len. + /// Maps a region of host memory into the sandbox address space. /// - /// `rgn.region_type` is ignored, since guest PTEs are not created - /// for the new memory. + /// The base address and length must meet platform alignment requirements + /// (typically page-aligned). The `region_type` field is ignored as guest + /// page table entries are not created. /// /// # Safety - /// It is the caller's responsibility to ensure that the host side - /// of the region remains intact and is not written to until this - /// mapping is removed, either due to the destruction of the - /// sandbox or due to a state rollback + /// + /// The caller must ensure the host memory region remains valid and unmodified + /// for the lifetime of `self`. #[instrument(err(Debug), skip(self, rgn), parent = Span::current())] pub unsafe fn map_region(&mut self, rgn: &MemoryRegion) -> Result<()> { if rgn.flags.contains(MemoryRegionFlags::STACK_GUARD) { @@ -187,7 +261,7 @@ impl MultiUseSandbox { /// Map the contents of a file into the guest at a particular address /// - /// Returns the length of the mapping + /// Returns the length of the mapping in bytes. #[allow(dead_code)] #[instrument(err(Debug), skip(self, _fp, _guest_base), parent = Span::current())] pub fn map_file_cow(&mut self, _fp: &Path, _guest_base: u64) -> Result { @@ -225,7 +299,9 @@ impl MultiUseSandbox { } } - /// This function is kept here for fuzz testing the parameter and return types + /// Calls a guest function with type-erased parameters and return values. + /// + /// This function is used for fuzz testing parameter and return type handling. #[cfg(feature = "fuzzing")] #[instrument(err(Debug), skip(self, args), parent = Span::current())] pub fn call_type_erased_guest_function_by_name( @@ -281,8 +357,35 @@ impl MultiUseSandbox { res } - /// Get a handle to the interrupt handler for this sandbox, - /// capable of interrupting guest execution. + /// Returns a handle for interrupting guest execution. + /// + /// # Examples + /// + /// ```no_run + /// # use hyperlight_host::{MultiUseSandbox, UninitializedSandbox, GuestBinary}; + /// # use std::thread; + /// # use std::time::Duration; + /// # fn example() -> Result<(), Box> { + /// let mut sandbox: MultiUseSandbox = UninitializedSandbox::new( + /// GuestBinary::FilePath("guest.bin".into()), + /// None + /// )?.evolve()?; + /// + /// // Get interrupt handle before starting long-running operation + /// let interrupt_handle = sandbox.interrupt_handle(); + /// + /// // Spawn thread to interrupt after timeout + /// let handle_clone = interrupt_handle.clone(); + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(5)); + /// handle_clone.kill(); + /// }); + /// + /// // This call may be interrupted by the spawned thread + /// let result = sandbox.call_guest_function_by_name::("LongRunningFunction", ()); + /// # Ok(()) + /// # } + /// ``` pub fn interrupt_handle(&self) -> Arc { self.vm.interrupt_handle() } diff --git a/src/hyperlight_host/src/sandbox/snapshot.rs b/src/hyperlight_host/src/sandbox/snapshot.rs index d91f52437..e9e996e7a 100644 --- a/src/hyperlight_host/src/sandbox/snapshot.rs +++ b/src/hyperlight_host/src/sandbox/snapshot.rs @@ -19,6 +19,6 @@ use crate::mem::shared_mem_snapshot::SharedMemorySnapshot; /// A snapshot capturing the state of the memory in a `MultiUseSandbox`. #[derive(Clone)] pub struct Snapshot { - /// TODO: Use Arc + // TODO: Use Arc pub(crate) inner: SharedMemorySnapshot, } diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index cfac5979c..65e9d9a80 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -62,13 +62,17 @@ pub(crate) struct SandboxRuntimeConfig { pub(crate) guest_core_dump: bool, } -/// A preliminary `Sandbox`, not yet ready to execute guest code. +/// A preliminary sandbox that represents allocated memory and registered host functions, +/// but has not yet created the underlying virtual machine. /// -/// Prior to initializing a full-fledged `Sandbox`, you must create one of -/// these `UninitializedSandbox`es with the `new` function, register all the -/// host-implemented functions you need to be available to the guest, then -/// call `evolve` to transform your -/// `UninitializedSandbox` into an initialized `Sandbox`. +/// This struct holds the configuration and setup needed for a sandbox without actually +/// creating the VM. It allows you to: +/// - Set up memory layout and load guest binary data +/// - Register host functions that will be available to the guest +/// - Configure sandbox settings before VM creation +/// +/// The virtual machine is not created until you call [`evolve`](Self::evolve) to transform +/// this into an initialized [`MultiUseSandbox`]. pub struct UninitializedSandbox { /// Registered host functions pub(crate) host_funcs: Arc>, @@ -90,7 +94,11 @@ impl Debug for UninitializedSandbox { } impl UninitializedSandbox { - /// Evolve `self` to a `MultiUseSandbox` without any additional metadata. + /// Creates and initializes the virtual machine, transforming this into a ready-to-use sandbox. + /// + /// This method consumes the `UninitializedSandbox` and performs the final initialization + /// steps to create the underlying virtual machine. Once evolved, the resulting + /// [`MultiUseSandbox`] can execute guest code and handle function calls. #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] pub fn evolve(self) -> Result { evolve_impl_multi_use(self) @@ -125,7 +133,10 @@ impl<'a> From<&'a [u8]> for GuestBlob<'a> { } } -/// A `GuestEnvironment` is a structure that contains the guest binary and an optional GuestBinary. +/// Container for a guest binary and optional initialization data. +/// +/// This struct combines a guest binary (either from a file or memory buffer) with +/// optional data that will be available to the guest during execution. #[derive(Debug)] pub struct GuestEnvironment<'a, 'b> { /// The guest binary, which can be a file path or a buffer. @@ -154,13 +165,12 @@ impl<'a> From> for GuestEnvironment<'a, '_> { } impl UninitializedSandbox { - /// Create a new sandbox configured to run the binary at path - /// `bin_path`. + /// Creates a new uninitialized sandbox for the given guest environment. /// - /// The instrument attribute is used to generate tracing spans and also to emit an error should the Result be an error. - /// The skip attribute is used to skip the guest binary from being printed in the tracing span. - /// The name attribute is used to name the tracing span. - /// The err attribute is used to emit an error should the Result be an error, it uses the std::`fmt::Debug trait` to print the error. + /// The guest binary can be provided as either a file path or memory buffer. + /// An optional configuration can customize memory sizes and sandbox settings. + /// After creation, register host functions using [`register`](Self::register) + /// before calling [`evolve`](Self::evolve) to complete initialization and create the VM. #[instrument( err(Debug), skip(env), @@ -294,14 +304,15 @@ impl UninitializedSandbox { SandboxMemoryManager::load_guest_binary_into_memory(cfg, exe_info, guest_blob) } - /// Set the max log level to be used by the guest. - /// If this is not set then the log level will be determined by parsing the RUST_LOG environment variable. - /// If the RUST_LOG environment variable is not set then the max log level will be set to `LevelFilter::Error`. + /// Sets the maximum log level for guest code execution. + /// + /// If not set, the log level is determined by the `RUST_LOG` environment variable, + /// defaulting to [`LevelFilter::Error`] if unset. pub fn set_max_guest_log_level(&mut self, log_level: LevelFilter) { self.max_guest_log_level = Some(log_level); } - /// Register a host function with the given name in the sandbox. + /// Registers a host function that the guest can call. pub fn register( &mut self, name: impl AsRef, @@ -310,9 +321,10 @@ impl UninitializedSandbox { register_host_function(host_func, self, name.as_ref(), None) } - /// Register the host function with the given name in the sandbox. - /// Unlike `register`, this variant takes a list of extra syscalls that will - /// allowed during the execution of the function handler. + /// Registers a host function with additional allowed syscalls during execution. + /// + /// Unlike [`register`](Self::register), this variant allows specifying extra syscalls + /// that will be permitted when the function handler runs. #[cfg(all(feature = "seccomp", target_os = "linux"))] pub fn register_with_extra_allowed_syscalls< Args: ParameterTuple, @@ -327,10 +339,11 @@ impl UninitializedSandbox { register_host_function(host_func, self, name.as_ref(), Some(extra_allowed_syscalls)) } - /// Register a host function named "HostPrint" that will be called by the guest - /// when it wants to print to the console. - /// The "HostPrint" host function is kind of special, as we expect it to have the - /// `FnMut(String) -> i32` signature. + /// Registers the special "HostPrint" function for guest printing. + /// + /// This overrides the default behavior of writing to stdout. + /// The function expects the signature `FnMut(String) -> i32` + /// and will be called when the guest wants to print output. pub fn register_print( &mut self, print_func: impl Into>, @@ -348,12 +361,10 @@ impl UninitializedSandbox { Ok(()) } - /// Register a host function named "HostPrint" that will be called by the guest - /// when it wants to print to the console. - /// The "HostPrint" host function is kind of special, as we expect it to have the - /// `FnMut(String) -> i32` signature. - /// Unlike `register_print`, this variant takes a list of extra syscalls that will - /// allowed during the execution of the function handler. + /// Registers the "HostPrint" function with additional allowed syscalls. + /// + /// Like [`register_print`](Self::register_print), but allows specifying extra syscalls + /// that will be permitted during function execution. #[cfg(all(feature = "seccomp", target_os = "linux"))] pub fn register_print_with_extra_allowed_syscalls( &mut self, From e609c9446465e12c5eb71422d3720ce3cd18e855 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Tue, 5 Aug 2025 16:28:02 -0700 Subject: [PATCH 081/271] Give release blocker action permission to read github issues when called from CreateRelease (#766) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- .github/workflows/CreateRelease.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/CreateRelease.yml b/.github/workflows/CreateRelease.yml index f5d65e077..1d8d2cbc7 100644 --- a/.github/workflows/CreateRelease.yml +++ b/.github/workflows/CreateRelease.yml @@ -10,6 +10,7 @@ on: permissions: contents: write id-token: write + issues: read jobs: From 9510c87805669ca65bd47042cdefb7afaff884b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 16:54:58 -0700 Subject: [PATCH 082/271] Bump crate-ci/typos from 1.34.0 to 1.35.1 (#764) * Bump crate-ci/typos from 1.34.0 to 1.35.1 Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.34.0 to 1.35.1. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.34.0...v1.35.1) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.35.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Fix typo Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- .github/workflows/ValidatePullRequest.yml | 2 +- src/hyperlight_component_util/src/emit.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index 4c8432cd7..f37cb2fab 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -65,7 +65,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Spell Check Repo - uses: crate-ci/typos@v1.34.0 + uses: crate-ci/typos@v1.35.1 license-headers: name: check license headers diff --git a/src/hyperlight_component_util/src/emit.rs b/src/hyperlight_component_util/src/emit.rs index 447467aff..d075f973b 100644 --- a/src/hyperlight_component_util/src/emit.rs +++ b/src/hyperlight_component_util/src/emit.rs @@ -621,7 +621,7 @@ pub struct WitName<'a> { pub _version: Vec<&'a str>, } impl<'a> WitName<'a> { - /// Extract a list of Rust module names correspondign to the WIT + /// Extract a list of Rust module names corresponding to the WIT /// namespace/package pub fn namespace_idents(&self) -> Vec { self.namespaces From 95f91389137ade28c066965628155722042265cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 04:32:28 +0000 Subject: [PATCH 083/271] Bump tracing-forest from 0.1.6 to 0.2.0 (#770) Bumps [tracing-forest](https://github.com/QnnOkabayashi/tracing-forest) from 0.1.6 to 0.2.0. - [Commits](https://github.com/QnnOkabayashi/tracing-forest/commits) --- updated-dependencies: - dependency-name: tracing-forest dependency-version: 0.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 49331334d..ae5a0a7fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3649,14 +3649,14 @@ dependencies = [ [[package]] name = "tracing-forest" -version = "0.1.6" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee40835db14ddd1e3ba414292272eddde9dad04d3d4b65509656414d1c42592f" +checksum = "3298fe855716711a00474eceb89cc7dc254bbe67f6bc4afafdeec5f0c538771c" dependencies = [ "chrono", "serde", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.12", "tracing", "tracing-subscriber", "uuid", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 932d754a9..bfceabf77 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -93,7 +93,7 @@ tracing-serde = "0.2.0" serial_test = "3.1.1" hyperlight-testing = { workspace = true } env_logger = "0.11.8" -tracing-forest = { version = "0.1.6", features = ["uuid", "chrono", "smallvec", "serde", "env-filter"] } +tracing-forest = { version = "0.2.0", features = ["uuid", "chrono", "smallvec", "serde", "env-filter"] } tracing = "0.1.41" tracing-subscriber = {version = "0.3.19", features = ["std", "env-filter"]} tracing-opentelemetry = "0.31.0" From e842ed45c938b1edc1013f8d3dddb4b76602bf0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 04:33:23 +0000 Subject: [PATCH 084/271] Bump framehop from 0.14.0 to 0.15.0 (#769) Bumps [framehop](https://github.com/mstange/framehop) from 0.14.0 to 0.15.0. - [Commits](https://github.com/mstange/framehop/compare/v0.14.0...v0.15.0) --- updated-dependencies: - dependency-name: framehop dependency-version: 0.15.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ae5a0a7fa..29eb868af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -903,9 +903,9 @@ dependencies = [ [[package]] name = "framehop" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0586ca77af938ae3d66a103d3082ac997b432e82e65d644be6ad2fa340f582d" +checksum = "78a7d65f75e837647bf8b1594ad3b559a929ee9a58d956d9f46999749957b6b9" dependencies = [ "arrayvec", "cfg-if", @@ -2394,9 +2394,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pe-unwind-info" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500fa4cdeacd98997c5865e3d0d1cb8fe7e9d7d75ecc775e07989a433a9a9a59" +checksum = "97f6fccfd2d9d2df765ca23ff85fe5cc437fb0e6d3e164e4d3cbe09d14780c93" dependencies = [ "arrayvec", "bitflags 2.9.1", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index bfceabf77..5408b83fe 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -28,7 +28,7 @@ rand = { version = "0.9" } cfg-if = { version = "1.0.1" } libc = { version = "0.2.174" } flatbuffers = "25.2.10" -framehop = { version = "0.14.0", optional = true } +framehop = { version = "0.15.0", optional = true } fallible-iterator = { version = "0.3.0", optional = true } blake3 = "1.8.2" page_size = "0.6.0" From 9ad85693aaa6ce0047940c3cbfc38538fabf4008 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 15:16:05 -0700 Subject: [PATCH 085/271] Bump actions/download-artifact from 4 to 5 (#768) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/Benchmarks.yml | 2 +- .github/workflows/CreateRelease.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Benchmarks.yml b/.github/workflows/Benchmarks.yml index 95adc2e40..e987f0e2d 100644 --- a/.github/workflows/Benchmarks.yml +++ b/.github/workflows/Benchmarks.yml @@ -35,7 +35,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Download Guest Binaries - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: guest-binaries-release path: ./downloaded-guest-binaries-release diff --git a/.github/workflows/CreateRelease.yml b/.github/workflows/CreateRelease.yml index 1d8d2cbc7..a0ca117a4 100644 --- a/.github/workflows/CreateRelease.yml +++ b/.github/workflows/CreateRelease.yml @@ -134,7 +134,7 @@ jobs: just tar-static-lib - name: Download all benchmarks - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: pattern: benchmarks_* From 65217f3c734bb965944efef83c3ec5d3acad9169 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Fri, 8 Aug 2025 08:29:33 -0700 Subject: [PATCH 086/271] Introduces a separate KVM error variant of HyperlightError. (#771) Fixes a common build error which occurs when the version of vmm-sys-util crate does not match between mshv/kvm. VmmSysError variant is now solely used for our signal registration, and is not used by mshv nor kvm code. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- Cargo.lock | 24 +++++++++++++------ src/hyperlight_host/Cargo.toml | 2 +- src/hyperlight_host/src/error.rs | 5 ++++ .../src/hypervisor/hyperv_linux.rs | 15 ++++++------ 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29eb868af..9f64916f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1494,7 +1494,7 @@ dependencies = [ "tracing-subscriber", "tracing-tracy", "uuid", - "vmm-sys-util", + "vmm-sys-util 0.15.0", "windows", "windows-result", "windows-sys 0.60.2", @@ -1787,7 +1787,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf3432d9f609fbede9f624d1dbefcce77985a9322de1d0e6d460ec05502b7fd0" dependencies = [ - "vmm-sys-util", + "vmm-sys-util 0.14.0", ] [[package]] @@ -1799,7 +1799,7 @@ dependencies = [ "bitflags 2.9.1", "kvm-bindings", "libc", - "vmm-sys-util", + "vmm-sys-util 0.14.0", ] [[package]] @@ -2055,7 +2055,7 @@ checksum = "f416b4432174e5a3f956a7887f4c1a4acea9511d81def67fcb8473293630ab9e" dependencies = [ "libc", "num_enum", - "vmm-sys-util", + "vmm-sys-util 0.14.0", "zerocopy 0.7.35", ] @@ -2067,7 +2067,7 @@ checksum = "1e0cb5031f3243a7459b7c13d960d25420980874eebda816db24ce6077e21d43" dependencies = [ "libc", "num_enum", - "vmm-sys-util", + "vmm-sys-util 0.14.0", "zerocopy 0.8.26", ] @@ -2080,7 +2080,7 @@ dependencies = [ "libc", "mshv-bindings 0.2.1", "thiserror 1.0.69", - "vmm-sys-util", + "vmm-sys-util 0.14.0", ] [[package]] @@ -2092,7 +2092,7 @@ dependencies = [ "libc", "mshv-bindings 0.3.2", "thiserror 2.0.12", - "vmm-sys-util", + "vmm-sys-util 0.14.0", ] [[package]] @@ -3919,6 +3919,16 @@ dependencies = [ "libc", ] +[[package]] +name = "vmm-sys-util" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "506c62fdf617a5176827c2f9afbcf1be155b03a9b4bf9617a60dbc07e3a1642f" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + [[package]] name = "wait-timeout" version = "0.2.1" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 5408b83fe..0a40161c1 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -40,7 +40,7 @@ tracing-log = "0.2.0" tracing-core = "0.1.34" hyperlight-common = { workspace = true, default-features = true, features = [ "std" ] } hyperlight-guest-tracing = { workspace = true, default-features = true, optional = true } -vmm-sys-util = "0.14.0" +vmm-sys-util = "0.15.0" crossbeam-channel = "0.5.15" thiserror = "2.0.12" chrono = { version = "0.4", optional = true } diff --git a/src/hyperlight_host/src/error.rs b/src/hyperlight_host/src/error.rs index 951066c53..c07f9857f 100644 --- a/src/hyperlight_host/src/error.rs +++ b/src/hyperlight_host/src/error.rs @@ -138,6 +138,11 @@ pub enum HyperlightError { #[error("Conversion of str data to json failed")] JsonConversionFailure(#[from] serde_json::Error), + /// KVM Error Occurred + #[error("KVM Error {0:?}")] + #[cfg(kvm)] + KVMError(#[from] kvm_ioctls::Error), + /// An attempt to get a lock from a Mutex failed. #[error("Unable to lock resource")] LockAttemptFailed(String), diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 0f8a68521..cc7528610 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -53,7 +53,7 @@ use mshv_bindings::{ hv_register_name, hv_register_name_HV_X64_REGISTER_RAX, hv_register_name_HV_X64_REGISTER_RBP, hv_register_name_HV_X64_REGISTER_RCX, hv_register_name_HV_X64_REGISTER_RSP, }; -use mshv_ioctls::{Mshv, MshvError, VcpuFd, VmFd}; +use mshv_ioctls::{Mshv, VcpuFd, VmFd}; use tracing::{Span, instrument}; #[cfg(crashdump)] use {super::crashdump, std::path::Path}; @@ -794,9 +794,7 @@ impl Hypervisor for HypervLinuxDriver { .load(Ordering::Relaxed) || debug_interrupt { - Err(MshvError::Errno(vmm_sys_util::errno::Error::new( - libc::EINTR, - ))) + Err(mshv_ioctls::MshvError::from(libc::EINTR)) } else { #[cfg(feature = "trace_guest")] if self.trace_info.guest_start_epoch.is_none() { @@ -847,7 +845,7 @@ impl Hypervisor for HypervLinuxDriver { HyperlightExit::Halt() } IO_PORT_INTERCEPT_MESSAGE => { - let io_message = m.to_ioport_info()?; + let io_message = m.to_ioport_info().map_err(mshv_ioctls::MshvError::from)?; let port_number = io_message.port_number; let rip = io_message.header.rip; let rax = io_message.rax; @@ -861,7 +859,7 @@ impl Hypervisor for HypervLinuxDriver { ) } UNMAPPED_GPA_MESSAGE => { - let mimo_message = m.to_memory_info()?; + let mimo_message = m.to_memory_info().map_err(mshv_ioctls::MshvError::from)?; let addr = mimo_message.guest_physical_address; crate::debug!( "mshv MMIO unmapped GPA -Details: Address: {} \n {:#?}", @@ -871,7 +869,7 @@ impl Hypervisor for HypervLinuxDriver { HyperlightExit::Mmio(addr) } INVALID_GPA_ACCESS_MESSAGE => { - let mimo_message = m.to_memory_info()?; + let mimo_message = m.to_memory_info().map_err(mshv_ioctls::MshvError::from)?; let gpa = mimo_message.guest_physical_address; let access_info = MemoryRegionFlags::try_from(mimo_message)?; crate::debug!( @@ -896,7 +894,8 @@ impl Hypervisor for HypervLinuxDriver { EXCEPTION_INTERCEPT => { // Extract exception info from the message so we can figure out // more information about the vCPU state - let ex_info = match m.to_exception_info() { + let ex_info = match m.to_exception_info().map_err(mshv_ioctls::MshvError::from) + { Ok(info) => info, Err(e) => { log_then_return!("Error converting to exception info: {:?}", e); From 0f88a6629df3c0d99ec1fca5defa528315ed8b98 Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Fri, 8 Aug 2025 19:14:27 +0100 Subject: [PATCH 087/271] Bring back the previous behavior of `call_guest_function_by_name` (#761) * bring back the previous call_guest_function_by_name behavior Signed-off-by: Jorge Prendes * update uses of call_guest_function_by_name with call Signed-off-by: Jorge Prendes * use the snapshot member as a mini snapshot cache Signed-off-by: Jorge Prendes * Use non-persisting guest calls for Callable trait Signed-off-by: Jorge Prendes --------- Signed-off-by: Jorge Prendes --- README.md | 2 +- fuzz/fuzz_targets/host_print.rs | 2 +- src/hyperlight_host/benches/benchmarks.rs | 9 +- src/hyperlight_host/examples/func_ctx/main.rs | 8 +- .../examples/guest-debugging/main.rs | 4 +- .../examples/hello-world/main.rs | 2 +- src/hyperlight_host/examples/logging/main.rs | 8 +- src/hyperlight_host/examples/metrics/main.rs | 8 +- .../examples/tracing-chrome/main.rs | 2 +- .../examples/tracing-otlp/main.rs | 8 +- .../examples/tracing-tracy/main.rs | 2 +- src/hyperlight_host/examples/tracing/main.rs | 8 +- src/hyperlight_host/src/metrics/mod.rs | 6 +- .../src/sandbox/initialized_multi_use.rs | 138 +++++++++++++++--- src/hyperlight_host/src/sandbox/snapshot.rs | 5 +- .../src/sandbox/uninitialized.rs | 2 +- src/hyperlight_host/tests/integration_test.rs | 107 +++++--------- .../tests/sandbox_host_tests.rs | 36 ++--- 18 files changed, 194 insertions(+), 163 deletions(-) diff --git a/README.md b/README.md index 87bcda114..7dbf56e50 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ fn main() -> hyperlight_host::Result<()> { let message = "Hello, World! I am executing inside of a VM :)\n".to_string(); // in order to call a function it first must be defined in the guest and exposed so that // the host can call it - multi_use_sandbox.call_guest_function_by_name::( + multi_use_sandbox.call::( "PrintOutput", message, )?; diff --git a/fuzz/fuzz_targets/host_print.rs b/fuzz/fuzz_targets/host_print.rs index c9c889e9e..59dc1ed13 100644 --- a/fuzz/fuzz_targets/host_print.rs +++ b/fuzz/fuzz_targets/host_print.rs @@ -27,7 +27,7 @@ fuzz_target!( |data: String| -> Corpus { let mut sandbox = SANDBOX.get().unwrap().lock().unwrap(); - let len: i32 = sandbox.call_guest_function_by_name::( + let len: i32 = sandbox.call::( "PrintOutput", data, ) diff --git a/src/hyperlight_host/benches/benchmarks.rs b/src/hyperlight_host/benches/benchmarks.rs index 96cc7ecf0..4896d9e14 100644 --- a/src/hyperlight_host/benches/benchmarks.rs +++ b/src/hyperlight_host/benches/benchmarks.rs @@ -16,9 +16,7 @@ limitations under the License. use criterion::{Criterion, criterion_group, criterion_main}; use hyperlight_host::GuestBinary; -use hyperlight_host::sandbox::{ - Callable, MultiUseSandbox, SandboxConfiguration, UninitializedSandbox, -}; +use hyperlight_host::sandbox::{MultiUseSandbox, SandboxConfiguration, UninitializedSandbox}; use hyperlight_testing::simple_guest_as_string; fn create_uninit_sandbox() -> UninitializedSandbox { @@ -99,10 +97,7 @@ fn guest_call_benchmark_large_param(c: &mut Criterion) { b.iter(|| { sandbox - .call_guest_function_by_name::<()>( - "LargeParameters", - (large_vec.clone(), large_string.clone()), - ) + .call::<()>("LargeParameters", (large_vec.clone(), large_string.clone())) .unwrap() }); }); diff --git a/src/hyperlight_host/examples/func_ctx/main.rs b/src/hyperlight_host/examples/func_ctx/main.rs index 2692f9487..8aedf0983 100644 --- a/src/hyperlight_host/examples/func_ctx/main.rs +++ b/src/hyperlight_host/examples/func_ctx/main.rs @@ -29,13 +29,9 @@ fn main() { // Do several calls against a sandbox running the `simpleguest.exe` binary, // and print their results - let res: String = sbox - .call_guest_function_by_name("Echo", "hello".to_string()) - .unwrap(); + let res: String = sbox.call("Echo", "hello".to_string()).unwrap(); println!("got Echo res: {res}"); - let res: i32 = sbox - .call_guest_function_by_name("CallMalloc", 200_i32) - .unwrap(); + let res: i32 = sbox.call("CallMalloc", 200_i32).unwrap(); println!("got CallMalloc res: {res}"); } diff --git a/src/hyperlight_host/examples/guest-debugging/main.rs b/src/hyperlight_host/examples/guest-debugging/main.rs index cc39b1705..e414b72d8 100644 --- a/src/hyperlight_host/examples/guest-debugging/main.rs +++ b/src/hyperlight_host/examples/guest-debugging/main.rs @@ -75,7 +75,7 @@ fn main() -> hyperlight_host::Result<()> { let message = "Hello, World! I am executing inside of a VM with debugger attached :)\n".to_string(); multi_use_sandbox_dbg - .call_guest_function_by_name::( + .call::( "PrintOutput", // function must be defined in the guest binary message.clone(), ) @@ -84,7 +84,7 @@ fn main() -> hyperlight_host::Result<()> { let message = "Hello, World! I am executing inside of a VM without debugger attached :)\n".to_string(); multi_use_sandbox - .call_guest_function_by_name::( + .call::( "PrintOutput", // function must be defined in the guest binary message.clone(), ) diff --git a/src/hyperlight_host/examples/hello-world/main.rs b/src/hyperlight_host/examples/hello-world/main.rs index e8461954a..4a403515b 100644 --- a/src/hyperlight_host/examples/hello-world/main.rs +++ b/src/hyperlight_host/examples/hello-world/main.rs @@ -40,7 +40,7 @@ fn main() -> hyperlight_host::Result<()> { // Call guest function let message = "Hello, World! I am executing inside of a VM :)\n".to_string(); multi_use_sandbox - .call_guest_function_by_name::( + .call::( "PrintOutput", // function must be defined in the guest binary message, ) diff --git a/src/hyperlight_host/examples/logging/main.rs b/src/hyperlight_host/examples/logging/main.rs index 470441e72..23a642886 100644 --- a/src/hyperlight_host/examples/logging/main.rs +++ b/src/hyperlight_host/examples/logging/main.rs @@ -50,7 +50,7 @@ fn main() -> Result<()> { // Call a guest function 5 times to generate some log entries. for _ in 0..5 { multiuse_sandbox - .call_guest_function_by_name::("Echo", "a".to_string()) + .call::("Echo", "a".to_string()) .unwrap(); } @@ -61,7 +61,7 @@ fn main() -> Result<()> { // Call a guest function that calls the HostPrint host function 5 times to generate some log entries. for _ in 0..5 { multiuse_sandbox - .call_guest_function_by_name::("PrintOutput", msg.clone()) + .call::("PrintOutput", msg.clone()) .unwrap(); } Ok(()) @@ -94,9 +94,7 @@ fn main() -> Result<()> { for _ in 0..NUM_CALLS { barrier.wait(); - multiuse_sandbox - .call_guest_function_by_name::<()>("Spin", ()) - .unwrap_err(); + multiuse_sandbox.call::<()>("Spin", ()).unwrap_err(); } thread.join().unwrap(); diff --git a/src/hyperlight_host/examples/metrics/main.rs b/src/hyperlight_host/examples/metrics/main.rs index 4328a3bfa..3401a3140 100644 --- a/src/hyperlight_host/examples/metrics/main.rs +++ b/src/hyperlight_host/examples/metrics/main.rs @@ -61,7 +61,7 @@ fn do_hyperlight_stuff() { // Call a guest function 5 times to generate some metrics. for _ in 0..5 { multiuse_sandbox - .call_guest_function_by_name::("Echo", "a".to_string()) + .call::("Echo", "a".to_string()) .unwrap(); } @@ -72,7 +72,7 @@ fn do_hyperlight_stuff() { // Call a guest function that calls the HostPrint host function 5 times to generate some metrics. for _ in 0..5 { multiuse_sandbox - .call_guest_function_by_name::("PrintOutput", msg.clone()) + .call::("PrintOutput", msg.clone()) .unwrap(); } Ok(()) @@ -108,9 +108,7 @@ fn do_hyperlight_stuff() { for _ in 0..NUM_CALLS { barrier.wait(); - multiuse_sandbox - .call_guest_function_by_name::<()>("Spin", ()) - .unwrap_err(); + multiuse_sandbox.call::<()>("Spin", ()).unwrap_err(); } for join_handle in join_handles { diff --git a/src/hyperlight_host/examples/tracing-chrome/main.rs b/src/hyperlight_host/examples/tracing-chrome/main.rs index 259a37057..7c4001106 100644 --- a/src/hyperlight_host/examples/tracing-chrome/main.rs +++ b/src/hyperlight_host/examples/tracing-chrome/main.rs @@ -36,7 +36,7 @@ fn main() -> Result<()> { // do the function call let current_time = std::time::Instant::now(); - let res: String = sbox.call_guest_function_by_name("Echo", "Hello, World!".to_string())?; + let res: String = sbox.call("Echo", "Hello, World!".to_string())?; let elapsed = current_time.elapsed(); println!("Function call finished in {:?}.", elapsed); assert_eq!(res, "Hello, World!"); diff --git a/src/hyperlight_host/examples/tracing-otlp/main.rs b/src/hyperlight_host/examples/tracing-otlp/main.rs index 69d318c1f..db5c9baf4 100644 --- a/src/hyperlight_host/examples/tracing-otlp/main.rs +++ b/src/hyperlight_host/examples/tracing-otlp/main.rs @@ -136,7 +136,7 @@ fn run_example(wait_input: bool) -> HyperlightResult<()> { // Call a guest function 5 times to generate some log entries. for _ in 0..5 { multiuse_sandbox - .call_guest_function_by_name::("Echo", "a".to_string()) + .call::("Echo", "a".to_string()) .unwrap(); } @@ -147,7 +147,7 @@ fn run_example(wait_input: bool) -> HyperlightResult<()> { // Call a guest function that calls the HostPrint host function 5 times to generate some log entries. for _ in 0..5 { multiuse_sandbox - .call_guest_function_by_name::("PrintOutput", msg.clone()) + .call::("PrintOutput", msg.clone()) .unwrap(); } @@ -179,9 +179,7 @@ fn run_example(wait_input: bool) -> HyperlightResult<()> { ); let _entered = span.enter(); barrier.wait(); - multiuse_sandbox - .call_guest_function_by_name::<()>("Spin", ()) - .unwrap_err(); + multiuse_sandbox.call::<()>("Spin", ()).unwrap_err(); } thread.join().expect("Thread panicked"); } diff --git a/src/hyperlight_host/examples/tracing-tracy/main.rs b/src/hyperlight_host/examples/tracing-tracy/main.rs index 03867f0d5..1c3912ebf 100644 --- a/src/hyperlight_host/examples/tracing-tracy/main.rs +++ b/src/hyperlight_host/examples/tracing-tracy/main.rs @@ -42,7 +42,7 @@ fn main() -> Result<()> { // do the function call let current_time = std::time::Instant::now(); - let res: String = sbox.call_guest_function_by_name("Echo", "Hello, World!".to_string())?; + let res: String = sbox.call("Echo", "Hello, World!".to_string())?; let elapsed = current_time.elapsed(); println!("Function call finished in {:?}.", elapsed); assert_eq!(res, "Hello, World!"); diff --git a/src/hyperlight_host/examples/tracing/main.rs b/src/hyperlight_host/examples/tracing/main.rs index 66020dcfa..fce5215e4 100644 --- a/src/hyperlight_host/examples/tracing/main.rs +++ b/src/hyperlight_host/examples/tracing/main.rs @@ -78,7 +78,7 @@ fn run_example() -> Result<()> { // Call a guest function 5 times to generate some log entries. for _ in 0..5 { multiuse_sandbox - .call_guest_function_by_name::("Echo", "a".to_string()) + .call::("Echo", "a".to_string()) .unwrap(); } @@ -89,7 +89,7 @@ fn run_example() -> Result<()> { // Call a guest function that calls the HostPrint host function 5 times to generate some log entries. for _ in 0..5 { multiuse_sandbox - .call_guest_function_by_name::("PrintOutput", msg.clone()) + .call::("PrintOutput", msg.clone()) .unwrap(); } Ok(()) @@ -131,9 +131,7 @@ fn run_example() -> Result<()> { ); let _entered = span.enter(); barrier.wait(); - multiuse_sandbox - .call_guest_function_by_name::<()>("Spin", ()) - .unwrap_err(); + multiuse_sandbox.call::<()>("Spin", ()).unwrap_err(); } for join_handle in join_handles { diff --git a/src/hyperlight_host/src/metrics/mod.rs b/src/hyperlight_host/src/metrics/mod.rs index a2f4026e5..76e9b93a3 100644 --- a/src/hyperlight_host/src/metrics/mod.rs +++ b/src/hyperlight_host/src/metrics/mod.rs @@ -116,12 +116,10 @@ mod tests { }); multi - .call_guest_function_by_name::("PrintOutput", "Hello".to_string()) + .call::("PrintOutput", "Hello".to_string()) .unwrap(); - multi - .call_guest_function_by_name::("Spin", ()) - .unwrap_err(); + multi.call::("Spin", ()).unwrap_err(); thread.join().unwrap(); snapshotter.snapshot() diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 7692a4379..671dbe7db 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -63,6 +63,9 @@ pub struct MultiUseSandbox { dispatch_ptr: RawPtr, #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, + /// If the current state of the sandbox has been captured in a snapshot, + /// that snapshot is stored here. + snapshot: Option, } impl MultiUseSandbox { @@ -87,6 +90,7 @@ impl MultiUseSandbox { dispatch_ptr, #[cfg(gdb)] dbg_mem_access_fn, + snapshot: None, } } @@ -115,15 +119,19 @@ impl MultiUseSandbox { /// ``` #[instrument(err(Debug), skip_all, parent = Span::current())] pub fn snapshot(&mut self) -> Result { + if let Some(snapshot) = &self.snapshot { + return Ok(snapshot.clone()); + } let mapped_regions_iter = self.vm.get_mapped_regions(); let mapped_regions_vec: Vec = mapped_regions_iter.cloned().collect(); let memory_snapshot = self .mem_mgr .unwrap_mgr_mut() .snapshot(self.id, mapped_regions_vec)?; - Ok(Snapshot { - inner: memory_snapshot, - }) + let inner = Arc::new(memory_snapshot); + let snapshot = Snapshot { inner }; + self.snapshot = Some(snapshot.clone()); + Ok(snapshot) } /// Restores the sandbox's memory to a previously captured snapshot state. @@ -159,6 +167,13 @@ impl MultiUseSandbox { /// ``` #[instrument(err(Debug), skip_all, parent = Span::current())] pub fn restore(&mut self, snapshot: &Snapshot) -> Result<()> { + if let Some(snap) = &self.snapshot { + if Arc::ptr_eq(&snap.inner, &snapshot.inner) { + // If the snapshot is already the current one, no need to restore + return Ok(()); + } + } + if self.id != snapshot.inner.sandbox_id() { return Err(SnapshotSandboxMismatch); } @@ -181,12 +196,15 @@ impl MultiUseSandbox { unsafe { self.vm.map_region(region)? }; } + // The restored snapshot is now our most current snapshot + self.snapshot = Some(snapshot.clone()); + Ok(()) } /// Calls a guest function by name with the specified arguments. /// - /// Changes made to the sandbox during execution are persisted. + /// Changes made to the sandbox during execution are *not* persisted. /// /// # Examples /// @@ -215,12 +233,62 @@ impl MultiUseSandbox { /// # Ok(()) /// # } /// ``` + #[doc(hidden)] + #[deprecated( + since = "0.8.0", + note = "Deprecated in favour of call and snapshot/restore." + )] #[instrument(err(Debug), skip(self, args), parent = Span::current())] pub fn call_guest_function_by_name( &mut self, func_name: &str, args: impl ParameterTuple, ) -> Result { + let snapshot = self.snapshot()?; + let res = self.call(func_name, args); + self.restore(&snapshot)?; + res + } + + /// Calls a guest function by name with the specified arguments. + /// + /// Changes made to the sandbox during execution are persisted. + /// + /// # Examples + /// + /// ```no_run + /// # use hyperlight_host::{MultiUseSandbox, UninitializedSandbox, GuestBinary}; + /// # fn example() -> Result<(), Box> { + /// let mut sandbox: MultiUseSandbox = UninitializedSandbox::new( + /// GuestBinary::FilePath("guest.bin".into()), + /// None + /// )?.evolve()?; + /// + /// // Call function with no arguments + /// let result: i32 = sandbox.call("GetCounter", ())?; + /// + /// // Call function with single argument + /// let doubled: i32 = sandbox.call("Double", 21)?; + /// assert_eq!(doubled, 42); + /// + /// // Call function with multiple arguments + /// let sum: i32 = sandbox.call("Add", (10, 32))?; + /// assert_eq!(sum, 42); + /// + /// // Call function returning string + /// let message: String = sandbox.call("Echo", "Hello, World!".to_string())?; + /// assert_eq!(message, "Hello, World!"); + /// # Ok(()) + /// # } + /// ``` + #[instrument(err(Debug), skip(self, args), parent = Span::current())] + pub fn call( + &mut self, + func_name: &str, + args: impl ParameterTuple, + ) -> Result { + // Reset snapshot since we are mutating the sandbox state + self.snapshot = None; maybe_time_and_emit_guest_call(func_name, || { let ret = self.call_guest_function_by_name_no_reset( func_name, @@ -254,6 +322,8 @@ impl MultiUseSandbox { // writes can be rolled back when necessary. log_then_return!("TODO: Writable mappings not yet supported"); } + // Reset snapshot since we are mutating the sandbox state + self.snapshot = None; unsafe { self.vm.map_region(rgn) }?; self.mem_mgr.unwrap_mgr_mut().mapped_rgns += 1; Ok(()) @@ -397,7 +467,7 @@ impl Callable for MultiUseSandbox { func_name: &str, args: impl ParameterTuple, ) -> Result { - self.call_guest_function_by_name(func_name, args) + self.call(func_name, args) } } @@ -429,9 +499,35 @@ mod tests { use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags, MemoryRegionType}; #[cfg(target_os = "linux")] use crate::mem::shared_mem::{ExclusiveSharedMemory, GuestSharedMemory, SharedMemory as _}; - use crate::sandbox::{Callable, SandboxConfiguration}; + use crate::sandbox::SandboxConfiguration; use crate::{GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox}; + /// Tests that call_guest_function_by_name restores the state correctly + #[test] + fn test_call_guest_function_by_name() { + let mut sbox: MultiUseSandbox = { + let path = simple_guest_as_string().unwrap(); + let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap(); + u_sbox.evolve() + } + .unwrap(); + + let snapshot = sbox.snapshot().unwrap(); + + let _ = sbox.call::("AddToStatic", 5i32).unwrap(); + let res: i32 = sbox.call("GetStatic", ()).unwrap(); + assert_eq!(res, 5); + + sbox.restore(&snapshot).unwrap(); + #[allow(deprecated)] + let _ = sbox + .call_guest_function_by_name::("AddToStatic", 5i32) + .unwrap(); + #[allow(deprecated)] + let res: i32 = sbox.call_guest_function_by_name("GetStatic", ()).unwrap(); + assert_eq!(res, 0); + } + // Tests to ensure that many (1000) function calls can be made in a call context with a small stack (1K) and heap(14K). // This test effectively ensures that the stack is being properly reset after each call and we are not leaking memory in the Guest. #[test] @@ -481,15 +577,13 @@ mod tests { let snapshot = sbox.snapshot().unwrap(); - let _ = sbox - .call_guest_function_by_name::("AddToStatic", 5i32) - .unwrap(); + let _ = sbox.call::("AddToStatic", 5i32).unwrap(); - let res: i32 = sbox.call_guest_function_by_name("GetStatic", ()).unwrap(); + let res: i32 = sbox.call("GetStatic", ()).unwrap(); assert_eq!(res, 5); sbox.restore(&snapshot).unwrap(); - let res: i32 = sbox.call_guest_function_by_name("GetStatic", ()).unwrap(); + let res: i32 = sbox.call("GetStatic", ()).unwrap(); assert_eq!(res, 0); } @@ -515,7 +609,7 @@ mod tests { let mut sbox: MultiUseSandbox = usbox.evolve()?; - let res: Result = sbox.call_guest_function_by_name("ViolateSeccompFilters", ()); + let res: Result = sbox.call("ViolateSeccompFilters", ()); #[cfg(feature = "seccomp")] match res { @@ -551,7 +645,7 @@ mod tests { let mut sbox: MultiUseSandbox = usbox.evolve()?; - let res: Result = sbox.call_guest_function_by_name("ViolateSeccompFilters", ()); + let res: Result = sbox.call("ViolateSeccompFilters", ()); match res { Ok(_) => {} @@ -605,7 +699,7 @@ mod tests { let mut sbox = ubox.evolve().unwrap(); let host_func_result = sbox - .call_guest_function_by_name::( + .call::( "CallGivenParamlessHostFuncThatReturnsI64", "Openat_Hostfunc".to_string(), ) @@ -634,8 +728,8 @@ mod tests { [libc::SYS_openat], )?; let mut sbox = ubox.evolve().unwrap(); - let host_func_result = sbox - .call_guest_function_by_name::( + let host_func_result: i64 = sbox + .call::( "CallGivenParamlessHostFuncThatReturnsI64", "Openat_Hostfunc".to_string(), ) @@ -658,7 +752,7 @@ mod tests { let mut multi_use_sandbox: MultiUseSandbox = usbox.evolve().unwrap(); - let res: Result<()> = multi_use_sandbox.call_guest_function_by_name("TriggerException", ()); + let res: Result<()> = multi_use_sandbox.call("TriggerException", ()); assert!(res.is_err()); @@ -698,9 +792,7 @@ mod tests { let mut multi_use_sandbox: MultiUseSandbox = usbox.evolve().unwrap(); - let res: i32 = multi_use_sandbox - .call_guest_function_by_name("GetStatic", ()) - .unwrap(); + let res: i32 = multi_use_sandbox.call("GetStatic", ()).unwrap(); assert_eq!(res, 0); } @@ -742,7 +834,7 @@ mod tests { let _guard = map_mem.lock.try_read().unwrap(); let actual: Vec = sbox - .call_guest_function_by_name( + .call( "ReadMappedBuffer", (guest_base as u64, expected.len() as u64), ) @@ -780,7 +872,7 @@ mod tests { // Execute should pass since memory is executable let succeed = sbox - .call_guest_function_by_name::( + .call::( "ExecMappedBuffer", (guest_base as u64, expected.len() as u64), ) @@ -789,7 +881,7 @@ mod tests { // write should fail because the memory is mapped as read-only let err = sbox - .call_guest_function_by_name::( + .call::( "WriteMappedBuffer", (guest_base as u64, expected.len() as u64), ) diff --git a/src/hyperlight_host/src/sandbox/snapshot.rs b/src/hyperlight_host/src/sandbox/snapshot.rs index e9e996e7a..c00aa4487 100644 --- a/src/hyperlight_host/src/sandbox/snapshot.rs +++ b/src/hyperlight_host/src/sandbox/snapshot.rs @@ -14,11 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ +use std::sync::Arc; + use crate::mem::shared_mem_snapshot::SharedMemorySnapshot; /// A snapshot capturing the state of the memory in a `MultiUseSandbox`. #[derive(Clone)] pub struct Snapshot { - // TODO: Use Arc - pub(crate) inner: SharedMemorySnapshot, + pub(crate) inner: Arc, } diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index 65e9d9a80..6d905cf52 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -434,7 +434,7 @@ mod tests { let mut sandbox: MultiUseSandbox = uninitialized_sandbox.evolve().unwrap(); let res = sandbox - .call_guest_function_by_name::>("ReadFromUserMemory", (4u64, buffer.to_vec())) + .call::>("ReadFromUserMemory", (4u64, buffer.to_vec())) .expect("Failed to call ReadFromUserMemory"); assert_eq!(res, buffer.to_vec()); diff --git a/src/hyperlight_host/tests/integration_test.rs b/src/hyperlight_host/tests/integration_test.rs index 967d93c53..eceabd479 100644 --- a/src/hyperlight_host/tests/integration_test.rs +++ b/src/hyperlight_host/tests/integration_test.rs @@ -70,9 +70,7 @@ fn interrupt_host_call() { } }); - let result = sandbox - .call_guest_function_by_name::("CallHostSpin", ()) - .unwrap_err(); + let result = sandbox.call::("CallHostSpin", ()).unwrap_err(); assert!(matches!(result, HyperlightError::ExecutionCanceledByHost())); thread.join().unwrap(); @@ -96,16 +94,12 @@ fn interrupt_in_progress_guest_call() { assert!(interrupt_handle.dropped()); }); - let res = sbox1 - .call_guest_function_by_name::("Spin", ()) - .unwrap_err(); + let res = sbox1.call::("Spin", ()).unwrap_err(); assert!(matches!(res, HyperlightError::ExecutionCanceledByHost())); barrier.wait(); // Make sure we can still call guest functions after the VM was interrupted - sbox1 - .call_guest_function_by_name::("Echo", "hello".to_string()) - .unwrap(); + sbox1.call::("Echo", "hello".to_string()).unwrap(); // drop vm to make sure other thread can detect it drop(sbox1); @@ -131,15 +125,11 @@ fn interrupt_guest_call_in_advance() { }); barrier.wait(); // wait until `kill()` is called before starting the guest call - let res = sbox1 - .call_guest_function_by_name::("Spin", ()) - .unwrap_err(); + let res = sbox1.call::("Spin", ()).unwrap_err(); assert!(matches!(res, HyperlightError::ExecutionCanceledByHost())); // Make sure we can still call guest functions after the VM was interrupted - sbox1 - .call_guest_function_by_name::("Echo", "hello".to_string()) - .unwrap(); + sbox1.call::("Echo", "hello".to_string()).unwrap(); // drop vm to make sure other thread can detect it drop(sbox1); @@ -181,9 +171,9 @@ fn interrupt_same_thread() { for _ in 0..NUM_ITERS { barrier.wait(); sbox1 - .call_guest_function_by_name::("Echo", "hello".to_string()) + .call::("Echo", "hello".to_string()) .expect("Only sandbox 2 is allowed to be interrupted"); - match sbox2.call_guest_function_by_name::("Echo", "hello".to_string()) { + match sbox2.call::("Echo", "hello".to_string()) { Ok(_) | Err(HyperlightError::ExecutionCanceledByHost()) => { // Only allow successful calls or interrupted. // The call can be successful in case the call is finished before kill() is called. @@ -191,7 +181,7 @@ fn interrupt_same_thread() { _ => panic!("Unexpected return"), }; sbox3 - .call_guest_function_by_name::("Echo", "hello".to_string()) + .call::("Echo", "hello".to_string()) .expect("Only sandbox 2 is allowed to be interrupted"); } thread.join().expect("Thread should finish"); @@ -225,9 +215,9 @@ fn interrupt_same_thread_no_barrier() { barrier.wait(); for _ in 0..NUM_ITERS { sbox1 - .call_guest_function_by_name::("Echo", "hello".to_string()) + .call::("Echo", "hello".to_string()) .expect("Only sandbox 2 is allowed to be interrupted"); - match sbox2.call_guest_function_by_name::("Echo", "hello".to_string()) { + match sbox2.call::("Echo", "hello".to_string()) { Ok(_) | Err(HyperlightError::ExecutionCanceledByHost()) => { // Only allow successful calls or interrupted. // The call can be successful in case the call is finished before kill() is called. @@ -235,7 +225,7 @@ fn interrupt_same_thread_no_barrier() { _ => panic!("Unexpected return"), }; sbox3 - .call_guest_function_by_name::("Echo", "hello".to_string()) + .call::("Echo", "hello".to_string()) .expect("Only sandbox 2 is allowed to be interrupted"); } workload_done.store(true, Ordering::Relaxed); @@ -257,9 +247,7 @@ fn interrupt_moved_sandbox() { let thread = thread::spawn(move || { barrier2.wait(); - let res = sbox1 - .call_guest_function_by_name::("Spin", ()) - .unwrap_err(); + let res = sbox1.call::("Spin", ()).unwrap_err(); assert!(matches!(res, HyperlightError::ExecutionCanceledByHost())); }); @@ -272,9 +260,7 @@ fn interrupt_moved_sandbox() { assert!(interrupt_handle2.kill()); }); - let res = sbox2 - .call_guest_function_by_name::("Spin", ()) - .unwrap_err(); + let res = sbox2.call::("Spin", ()).unwrap_err(); assert!(matches!(res, HyperlightError::ExecutionCanceledByHost())); thread.join().expect("Thread should finish"); @@ -315,9 +301,7 @@ fn interrupt_custom_signal_no_and_retry_delay() { }); for _ in 0..NUM_ITERS { - let res = sbox1 - .call_guest_function_by_name::("Spin", ()) - .unwrap_err(); + let res = sbox1.call::("Spin", ()).unwrap_err(); assert!(matches!(res, HyperlightError::ExecutionCanceledByHost())); // immediately reenter another guest function call after having being cancelled, // so that the vcpu is running again before the interruptor-thread has a chance to see that the vcpu is not running @@ -354,7 +338,7 @@ fn interrupt_spamming_host_call() { barrier.wait(); // This guest call calls "HostFunc1" in a loop let res = sbox1 - .call_guest_function_by_name::("HostCallLoop", "HostFunc1".to_string()) + .call::("HostCallLoop", "HostFunc1".to_string()) .unwrap_err(); assert!(matches!(res, HyperlightError::ExecutionCanceledByHost())); @@ -369,7 +353,7 @@ fn print_four_args_c_guest() { let uninit = UninitializedSandbox::new(guest_path, None); let mut sbox1 = uninit.unwrap().evolve().unwrap(); - let res = sbox1.call_guest_function_by_name::( + let res = sbox1.call::( "PrintFourArgs", ("Test4".to_string(), 3_i32, 4_i64, "Tested".to_string()), ); @@ -383,7 +367,7 @@ fn guest_abort() { let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let error_code: u8 = 13; // this is arbitrary let res = sbox1 - .call_guest_function_by_name::<()>("GuestAbortWithCode", error_code as i32) + .call::<()>("GuestAbortWithCode", error_code as i32) .unwrap_err(); println!("{:?}", res); assert!( @@ -396,7 +380,7 @@ fn guest_abort_with_context1() { let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let res = sbox1 - .call_guest_function_by_name::<()>("GuestAbortWithMessage", (25_i32, "Oh no".to_string())) + .call::<()>("GuestAbortWithMessage", (25_i32, "Oh no".to_string())) .unwrap_err(); println!("{:?}", res); assert!( @@ -441,10 +425,7 @@ fn guest_abort_with_context2() { Proin sagittis nisl rhoncus mattis rhoncus urna. Magna eget est lorem ipsum."; let res = sbox1 - .call_guest_function_by_name::<()>( - "GuestAbortWithMessage", - (60_i32, abort_message.to_string()), - ) + .call::<()>("GuestAbortWithMessage", (60_i32, abort_message.to_string())) .unwrap_err(); println!("{:?}", res); assert!( @@ -463,7 +444,7 @@ fn guest_abort_c_guest() { let mut sbox1 = uninit.unwrap().evolve().unwrap(); let res = sbox1 - .call_guest_function_by_name::<()>( + .call::<()>( "GuestAbortWithMessage", (75_i32, "This is a test error message".to_string()), ) @@ -480,7 +461,7 @@ fn guest_panic() { let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let res = sbox1 - .call_guest_function_by_name::<()>("guest_panic", "Error... error...".to_string()) + .call::<()>("guest_panic", "Error... error...".to_string()) .unwrap_err(); println!("{:?}", res); assert!( @@ -494,9 +475,7 @@ fn guest_malloc() { let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let size_to_allocate = 2000_i32; - sbox1 - .call_guest_function_by_name::("TestMalloc", size_to_allocate) - .unwrap(); + sbox1.call::("TestMalloc", size_to_allocate).unwrap(); } #[test] @@ -506,7 +485,7 @@ fn guest_allocate_vec() { let size_to_allocate = 2000_i32; let res = sbox1 - .call_guest_function_by_name::( + .call::( "CallMalloc", // uses the rust allocator to allocate a vector on heap size_to_allocate, ) @@ -522,9 +501,7 @@ fn guest_malloc_abort() { let size = 20000000_i32; // some big number that should fail when allocated - let res = sbox1 - .call_guest_function_by_name::("TestMalloc", size) - .unwrap_err(); + let res = sbox1.call::("TestMalloc", size).unwrap_err(); println!("{:?}", res); assert!( matches!(res, HyperlightError::GuestAborted(code, _) if code == ErrorCode::MallocFailed as u8) @@ -544,7 +521,7 @@ fn guest_malloc_abort() { .unwrap(); let mut sbox2 = uninit.evolve().unwrap(); - let res = sbox2.call_guest_function_by_name::( + let res = sbox2.call::( "CallMalloc", // uses the rust allocator to allocate a vector on heap size_to_allocate as i32, ); @@ -564,13 +541,11 @@ fn dynamic_stack_allocate_c_guest() { let uninit = UninitializedSandbox::new(guest_path, None); let mut sbox1: MultiUseSandbox = uninit.unwrap().evolve().unwrap(); - let res: i32 = sbox1 - .call_guest_function_by_name("StackAllocate", 100_i32) - .unwrap(); + let res: i32 = sbox1.call("StackAllocate", 100_i32).unwrap(); assert_eq!(res, 100); let res = sbox1 - .call_guest_function_by_name::("StackAllocate", 0x800_0000_i32) + .call::("StackAllocate", 0x800_0000_i32) .unwrap_err(); assert!(matches!(res, HyperlightError::StackOverflow())); } @@ -580,7 +555,7 @@ fn dynamic_stack_allocate_c_guest() { fn static_stack_allocate() { let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); - let res: i32 = sbox1.call_guest_function_by_name("SmallVar", ()).unwrap(); + let res: i32 = sbox1.call("SmallVar", ()).unwrap(); assert_eq!(res, 1024); } @@ -588,9 +563,7 @@ fn static_stack_allocate() { #[test] fn static_stack_allocate_overflow() { let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); - let res = sbox1 - .call_guest_function_by_name::("LargeVar", ()) - .unwrap_err(); + let res = sbox1.call::("LargeVar", ()).unwrap_err(); assert!(matches!(res, HyperlightError::StackOverflow())); } @@ -601,9 +574,7 @@ fn recursive_stack_allocate() { let iterations = 1_i32; - sbox1 - .call_guest_function_by_name::("StackOverflow", iterations) - .unwrap(); + sbox1.call::("StackOverflow", iterations).unwrap(); } // checks stack guard page (between guest stack and heap) @@ -628,7 +599,7 @@ fn guard_page_check() { // we have to create a sandbox each iteration because can't reuse after MMIO error in release mode let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); - let result = sbox1.call_guest_function_by_name::("test_write_raw_ptr", offset); + let result = sbox1.call::("test_write_raw_ptr", offset); if guard_range.contains(&offset) { // should have failed assert!(matches!( @@ -646,9 +617,7 @@ fn guard_page_check_2() { // this test is rust-guest only let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); - let result = sbox1 - .call_guest_function_by_name::<()>("InfiniteRecursion", ()) - .unwrap_err(); + let result = sbox1.call::<()>("InfiniteRecursion", ()).unwrap_err(); assert!(matches!(result, HyperlightError::StackOverflow())); } @@ -656,9 +625,7 @@ fn guard_page_check_2() { fn execute_on_stack() { let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); - let result = sbox1 - .call_guest_function_by_name::("ExecuteOnStack", ()) - .unwrap_err(); + let result = sbox1.call::("ExecuteOnStack", ()).unwrap_err(); let err = result.to_string(); assert!( @@ -671,7 +638,7 @@ fn execute_on_stack() { #[ignore] // ran from Justfile because requires feature "executable_heap" fn execute_on_heap() { let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); - let result = sbox1.call_guest_function_by_name::("ExecuteOnHeap", ()); + let result = sbox1.call::("ExecuteOnHeap", ()); println!("{:#?}", result); #[cfg(feature = "executable_heap")] @@ -693,9 +660,7 @@ fn recursive_stack_allocate_overflow() { let iterations = 10_i32; - let res = sbox1 - .call_guest_function_by_name::<()>("StackOverflow", iterations) - .unwrap_err(); + let res = sbox1.call::<()>("StackOverflow", iterations).unwrap_err(); println!("{:?}", res); assert!(matches!(res, HyperlightError::StackOverflow())); } @@ -768,7 +733,7 @@ fn log_test_messages(levelfilter: Option) { let message = format!("Hello from log_message level {}", level as i32); sbox1 - .call_guest_function_by_name::<()>("LogMessage", (message.to_string(), level as i32)) + .call::<()>("LogMessage", (message.to_string(), level as i32)) .unwrap(); } } diff --git a/src/hyperlight_host/tests/sandbox_host_tests.rs b/src/hyperlight_host/tests/sandbox_host_tests.rs index 7ca0ba5dc..32047653c 100644 --- a/src/hyperlight_host/tests/sandbox_host_tests.rs +++ b/src/hyperlight_host/tests/sandbox_host_tests.rs @@ -19,7 +19,7 @@ use std::sync::mpsc::channel; use std::sync::{Arc, Mutex}; use common::new_uninit; -use hyperlight_host::sandbox::{Callable, SandboxConfiguration}; +use hyperlight_host::sandbox::SandboxConfiguration; use hyperlight_host::{ GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox, new_error, }; @@ -85,9 +85,7 @@ fn float_roundtrip() { ]; let mut sandbox: MultiUseSandbox = new_uninit().unwrap().evolve().unwrap(); for f in doubles.iter() { - let res: f64 = sandbox - .call_guest_function_by_name("EchoDouble", *f) - .unwrap(); + let res: f64 = sandbox.call("EchoDouble", *f).unwrap(); assert!( res.total_cmp(f).is_eq(), @@ -97,9 +95,7 @@ fn float_roundtrip() { ); } for f in floats.iter() { - let res: f32 = sandbox - .call_guest_function_by_name("EchoFloat", *f) - .unwrap(); + let res: f32 = sandbox.call("EchoFloat", *f).unwrap(); assert!( res.total_cmp(f).is_eq(), @@ -115,7 +111,7 @@ fn float_roundtrip() { fn invalid_guest_function_name() { for mut sandbox in get_simpleguest_sandboxes(None).into_iter() { let fn_name = "FunctionDoesntExist"; - let res = sandbox.call_guest_function_by_name::(fn_name, ()); + let res = sandbox.call::(fn_name, ()); println!("{:?}", res); assert!( matches!(res.unwrap_err(), HyperlightError::GuestError(hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode::GuestFunctionNotFound, error_name) if error_name == fn_name) @@ -128,7 +124,7 @@ fn invalid_guest_function_name() { fn set_static() { for mut sandbox in get_simpleguest_sandboxes(None).into_iter() { let fn_name = "SetStatic"; - let res = sandbox.call_guest_function_by_name::(fn_name, ()); + let res = sandbox.call::(fn_name, ()); println!("{:?}", res); assert!(res.is_ok()); // the result is the size of the static array in the guest @@ -162,7 +158,7 @@ fn multiple_parameters() { macro_rules! test_case { ($sandbox:ident, $rx:ident, $name:literal, ($($p:ident),+)) => {{ let ($($p),+, ..) = args.clone(); - let res: i32 = $sandbox.call_guest_function_by_name($name, ($($p.0,)+)).unwrap(); + let res: i32 = $sandbox.call($name, ($($p.0,)+)).unwrap(); println!("{res:?}"); let output = $rx.try_recv().unwrap(); println!("{output:?}"); @@ -188,7 +184,7 @@ fn multiple_parameters() { #[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn incorrect_parameter_type() { for mut sandbox in get_simpleguest_sandboxes(None) { - let res = sandbox.call_guest_function_by_name::( + let res = sandbox.call::( "Echo", 2_i32, // should be string ); @@ -206,7 +202,7 @@ fn incorrect_parameter_type() { #[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn incorrect_parameter_num() { for mut sandbox in get_simpleguest_sandboxes(None).into_iter() { - let res = sandbox.call_guest_function_by_name::("Echo", ("1".to_string(), 2_i32)); + let res = sandbox.call::("Echo", ("1".to_string(), 2_i32)); assert!(matches!( res.unwrap_err(), HyperlightError::GuestError( @@ -237,7 +233,7 @@ fn max_memory_sandbox() { fn iostack_is_working() { for mut sandbox in get_simpleguest_sandboxes(None).into_iter() { let res: i32 = sandbox - .call_guest_function_by_name::("ThisIsNotARealFunctionButTheNameIsImportant", ()) + .call::("ThisIsNotARealFunctionButTheNameIsImportant", ()) .unwrap(); assert_eq!(res, 99); } @@ -260,19 +256,15 @@ fn simple_test_helper() -> Result<()> { let message2 = "world"; for mut sandbox in get_simpleguest_sandboxes(Some(writer.into())).into_iter() { - let res: i32 = sandbox - .call_guest_function_by_name("PrintOutput", message.to_string()) - .unwrap(); + let res: i32 = sandbox.call("PrintOutput", message.to_string()).unwrap(); assert_eq!(res, 5); - let res: String = sandbox - .call_guest_function_by_name("Echo", message2.to_string()) - .unwrap(); + let res: String = sandbox.call("Echo", message2.to_string()).unwrap(); assert_eq!(res, "world"); let buffer = [1u8, 2, 3, 4, 5, 6]; let res: Vec = sandbox - .call_guest_function_by_name("GetSizePrefixedBuffer", buffer.to_vec()) + .call("GetSizePrefixedBuffer", buffer.to_vec()) .unwrap(); assert_eq!(res, buffer); } @@ -332,7 +324,7 @@ fn callback_test_helper() -> Result<()> { // call guest function that calls host function let mut init_sandbox: MultiUseSandbox = sandbox.evolve()?; let msg = "Hello world"; - init_sandbox.call_guest_function_by_name::("GuestMethod1", msg.to_string())?; + init_sandbox.call::("GuestMethod1", msg.to_string())?; let messages = rx.try_iter().collect::>(); assert_eq!(messages, [format!("Hello from GuestFunction1, {msg}")]); @@ -375,7 +367,7 @@ fn host_function_error() -> Result<()> { let mut init_sandbox: MultiUseSandbox = sandbox.evolve()?; let msg = "Hello world"; let res = init_sandbox - .call_guest_function_by_name::("GuestMethod1", msg.to_string()) + .call::("GuestMethod1", msg.to_string()) .unwrap_err(); assert!(matches!(res, HyperlightError::Error(msg) if msg == "Host function error!")); } From 1669f7f90734a364739ae99c3b4911bce09d27d1 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Fri, 8 Aug 2025 15:36:20 -0700 Subject: [PATCH 088/271] Updates for v0.8.0 release (#773) * Updates for v0.8.0 release Signed-off-by: James Sturtevant * Fix typos Signed-off-by: James Sturtevant * Add tracing to publishing Signed-off-by: James Sturtevant --------- Signed-off-by: James Sturtevant --- .github/workflows/CargoPublish.yml | 18 ++++++++++- CHANGELOG.md | 30 +++++++++++++++++++ Cargo.lock | 18 +++++------ Cargo.toml | 18 +++++------ .../rust_guests/callbackguest/Cargo.lock | 10 +++---- src/tests/rust_guests/simpleguest/Cargo.lock | 10 +++---- typos.toml | 1 + 7 files changed, 76 insertions(+), 29 deletions(-) diff --git a/.github/workflows/CargoPublish.yml b/.github/workflows/CargoPublish.yml index 37494ba1f..fd80e1532 100644 --- a/.github/workflows/CargoPublish.yml +++ b/.github/workflows/CargoPublish.yml @@ -46,7 +46,7 @@ jobs: VERSION="${VERSION#refs/heads/release/v}" echo "VERSION=$VERSION" >> $GITHUB_ENV fi - ./dev/verify-version.sh "$VERSION" hyperlight-common hyperlight-guest hyperlight-guest-bin hyperlight-host hyperlight-component-util hyperlight-component-macro + ./dev/verify-version.sh "$VERSION" hyperlight-common hyperlight-guest hyperlight-guest-bin hyperlight-host hyperlight-component-util hyperlight-component-macro hyperlight-guest-tracing-macro hyperlight-guest-tracing - name: Determine which crates need publishing run: | @@ -75,6 +75,8 @@ jobs: needs_publish hyperlight-component-util needs_publish hyperlight-component-macro needs_publish hyperlight-host + needs_publish hyperlight-guest-tracing-macro + needs_publish hyperlight-guest-tracing - name: Publish hyperlight-common continue-on-error: ${{ inputs.dry_run }} @@ -82,6 +84,20 @@ jobs: env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_PUBLISH_TOKEN }} if: env.PUBLISH_HYPERLIGHT_COMMON != 'false' + + - name: Publish hyperlight-guest-tracing-macro + continue-on-error: ${{ inputs.dry_run }} + run: cargo publish --manifest-path ./src/hyperlight_guest_tracing_macro/Cargo.toml ${{ inputs.dry_run && '--dry-run' || '' }} + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_PUBLISH_TOKEN }} + if: env.PUBLISH_HYPERLIGHT_GUEST_TRACING_MACRO != 'false' + + - name: Publish hyperlight-guest-tracing + continue-on-error: ${{ inputs.dry_run }} + run: cargo publish --manifest-path ./src/hyperlight_guest_tracing/Cargo.toml ${{ inputs.dry_run && '--dry-run' || '' }} + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_PUBLISH_TOKEN }} + if: env.PUBLISH_HYPERLIGHT_GUEST_TRACING != 'false' - name: Publish hyperlight-guest continue-on-error: ${{ inputs.dry_run }} diff --git a/CHANGELOG.md b/CHANGELOG.md index f72db57d0..6f3aa1682 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,36 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Prerelease] - Unreleased +## [v0.8.0] - 2025-08-08 + +:warning: `hyperlight_component_macro::host_bindgen` and `hyperlight_component_macro::guest_bindgen` used the `Callable` trait which no longer restores state after each function call and requires an explicit Snapshot Restore using the newly exposed Snapshot API. See https://github.com/hyperlight-dev/hyperlight/pull/697 and https://github.com/hyperlight-dev/hyperlight/pull/761 + +### Fixed +- gdb: fix issue "Debug not enabled" when `gdb` feature was enabled by @dblnz in https://github.com/hyperlight-dev/hyperlight/pull/678 +- Fix Windows build with `--no-default-features` by @danbugs in https://github.com/hyperlight-dev/hyperlight/pull/712 +- fix(guest-bin): move logger initialization by @andreiltd in https://github.com/hyperlight-dev/hyperlight/pull/755 +- Fix mem mgr not initialized by @dblnz in https://github.com/hyperlight-dev/hyperlight/pull/745 + +### Changed +- Remove some dev-dependencies and cargo features to speed up compilation by @ludfjig in https://github.com/hyperlight-dev/hyperlight/pull/535 +- Introduce a separate KVM error variant of HyperlightError. by @ludfjig in https://github.com/hyperlight-dev/hyperlight/pull/771API. by @jprendes in https://github.com/hyperlight-dev/hyperlight/pull/697 +- Evolving and Devolving apis replaced by Snapshot API + - Remove sandbox evolving and devolving and replace it with snapshotting API. by @jprendes in https://github.com/hyperlight-dev/hyperlight/pull/697 + - Bring back the previous behavior of `call_guest_function_by_name` by @jprendes in https://github.com/hyperlight-dev/hyperlight/pull/761 + +### Added +- Memory Mapping Support + - Support mapping host memory into the guest by @syntactically in https://github.com/hyperlight-dev/hyperlight/pull/696 + - Make MultiUseSandbox::map_file_cow public by @ludfjig in https://github.com/hyperlight-dev/hyperlight/pull/725 + - Add memory mapping support with KVM by @jprendes in https://github.com/hyperlight-dev/hyperlight/pull/709 + - Make sure mmapped memory is not mapped writeable into sandbox in kvm by @ludfjig in https://github.com/hyperlight-dev/hyperlight/pull/740 + - Make snapshots region aware by @ludfjig in https://github.com/hyperlight-dev/hyperlight/pull/742 + - Restrict restoring sandboxes to snapshot taken on self by @ludfjig in https://github.com/hyperlight-dev/hyperlight/pull/746 +- Enable guest tracing by @dblnz in https://github.com/hyperlight-dev/hyperlight/pull/695 + +### Removed +- Removed the OutBHandler and MemAccessHandler abstractions and related implementations. by @simongdavies in https://github.com/hyperlight-dev/hyperlight/pull/732 + ## [v0.7.0] - 2025-06-26 ### Fixed diff --git a/Cargo.lock b/Cargo.lock index 9f64916f5..81bebf0f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1336,7 +1336,7 @@ dependencies = [ [[package]] name = "hyperlight-common" -version = "0.7.0" +version = "0.8.0" dependencies = [ "anyhow", "arbitrary", @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "hyperlight-component-macro" -version = "0.7.0" +version = "0.8.0" dependencies = [ "env_logger", "hyperlight-component-util", @@ -1363,7 +1363,7 @@ dependencies = [ [[package]] name = "hyperlight-component-util" -version = "0.7.0" +version = "0.8.0" dependencies = [ "itertools 0.14.0", "log", @@ -1385,7 +1385,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.7.0" +version = "0.8.0" dependencies = [ "anyhow", "hyperlight-common", @@ -1395,7 +1395,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.7.0" +version = "0.8.0" dependencies = [ "buddy_system_allocator", "cc", @@ -1410,7 +1410,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing" -version = "0.7.0" +version = "0.8.0" dependencies = [ "hyperlight-common", "hyperlight-guest-tracing-macro", @@ -1419,7 +1419,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing-macro" -version = "0.7.0" +version = "0.8.0" dependencies = [ "proc-macro2", "quote", @@ -1428,7 +1428,7 @@ dependencies = [ [[package]] name = "hyperlight-host" -version = "0.7.0" +version = "0.8.0" dependencies = [ "anyhow", "bitflags 2.9.1", @@ -1518,7 +1518,7 @@ dependencies = [ [[package]] name = "hyperlight_guest_capi" -version = "0.7.0" +version = "0.8.0" dependencies = [ "cbindgen", "hyperlight-common", diff --git a/Cargo.toml b/Cargo.toml index d111c1850..9a6508cc2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ exclude = [ ] [workspace.package] -version = "0.7.0" +version = "0.8.0" edition = "2024" rust-version = "1.86" license = "Apache-2.0" @@ -37,15 +37,15 @@ repository = "https://github.com/hyperlight-dev/hyperlight" readme = "README.md" [workspace.dependencies] -hyperlight-common = { path = "src/hyperlight_common", version = "0.7.0", default-features = false } -hyperlight-host = { path = "src/hyperlight_host", version = "0.7.0", default-features = false } -hyperlight-guest = { path = "src/hyperlight_guest", version = "0.7.0", default-features = false } -hyperlight-guest-bin = { path = "src/hyperlight_guest_bin", version = "0.7.0", default-features = false } +hyperlight-common = { path = "src/hyperlight_common", version = "0.8.0", default-features = false } +hyperlight-host = { path = "src/hyperlight_host", version = "0.8.0", default-features = false } +hyperlight-guest = { path = "src/hyperlight_guest", version = "0.8.0", default-features = false } +hyperlight-guest-bin = { path = "src/hyperlight_guest_bin", version = "0.8.0", default-features = false } hyperlight-testing = { path = "src/hyperlight_testing", default-features = false } -hyperlight-guest-tracing = { path = "src/hyperlight_guest_tracing", default-features = false } -hyperlight-guest-tracing-macro = { path = "src/hyperlight_guest_tracing_macro", default-features = false } -hyperlight-component-util = { path = "src/hyperlight_component_util", version = "0.7.0", default-features = false } -hyperlight-component-macro = { path = "src/hyperlight_component_macro", version = "0.7.0", default-features = false } +hyperlight-guest-tracing = { path = "src/hyperlight_guest_tracing", version = "0.8.0", default-features = false } +hyperlight-guest-tracing-macro = { path = "src/hyperlight_guest_tracing_macro", version = "0.8.0", default-features = false } +hyperlight-component-util = { path = "src/hyperlight_component_util", version = "0.8.0", default-features = false } +hyperlight-component-macro = { path = "src/hyperlight_component_macro", version = "0.8.0", default-features = false } [workspace.lints.rust] unsafe_op_in_unsafe_fn = "deny" diff --git a/src/tests/rust_guests/callbackguest/Cargo.lock b/src/tests/rust_guests/callbackguest/Cargo.lock index e1de2399e..f0fdb7982 100644 --- a/src/tests/rust_guests/callbackguest/Cargo.lock +++ b/src/tests/rust_guests/callbackguest/Cargo.lock @@ -72,7 +72,7 @@ checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "hyperlight-common" -version = "0.7.0" +version = "0.8.0" dependencies = [ "anyhow", "flatbuffers", @@ -82,7 +82,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.7.0" +version = "0.8.0" dependencies = [ "anyhow", "hyperlight-common", @@ -92,7 +92,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.7.0" +version = "0.8.0" dependencies = [ "buddy_system_allocator", "cc", @@ -107,7 +107,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing" -version = "0.7.0" +version = "0.8.0" dependencies = [ "hyperlight-common", "hyperlight-guest-tracing-macro", @@ -116,7 +116,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing-macro" -version = "0.7.0" +version = "0.8.0" dependencies = [ "proc-macro2", "quote", diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index db313889c..2b323048d 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -62,7 +62,7 @@ checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "hyperlight-common" -version = "0.7.0" +version = "0.8.0" dependencies = [ "anyhow", "flatbuffers", @@ -72,7 +72,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.7.0" +version = "0.8.0" dependencies = [ "anyhow", "hyperlight-common", @@ -82,7 +82,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.7.0" +version = "0.8.0" dependencies = [ "buddy_system_allocator", "cc", @@ -97,7 +97,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing" -version = "0.7.0" +version = "0.8.0" dependencies = [ "hyperlight-common", "hyperlight-guest-tracing-macro", @@ -106,7 +106,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing-macro" -version = "0.7.0" +version = "0.8.0" dependencies = [ "proc-macro2", "quote", diff --git a/typos.toml b/typos.toml index bdf1e81f2..c05ec808d 100644 --- a/typos.toml +++ b/typos.toml @@ -7,3 +7,4 @@ extend-exclude = ["**/*.patch", "src/hyperlight_guest_bin/third_party/**/*", "NO [default.extend-words] # typ is used for field name as type is a reserved keyword typ="typ" +mmaped="mmapped" From 83cddd5cd04a9c96b2397a8ccac09928076b5c72 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 08:37:36 +0000 Subject: [PATCH 089/271] Bump cc from 1.2.31 to 1.2.32 (#776) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.31 to 1.2.32. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.31...cc-v1.2.32) --- updated-dependencies: - dependency-name: cc dependency-version: 1.2.32 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81bebf0f3..96be38ebf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,9 +362,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.31" +version = "1.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" +checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" dependencies = [ "jobserver", "libc", @@ -2055,7 +2055,7 @@ checksum = "f416b4432174e5a3f956a7887f4c1a4acea9511d81def67fcb8473293630ab9e" dependencies = [ "libc", "num_enum", - "vmm-sys-util 0.14.0", + "vmm-sys-util 0.15.0", "zerocopy 0.7.35", ] @@ -2067,7 +2067,7 @@ checksum = "1e0cb5031f3243a7459b7c13d960d25420980874eebda816db24ce6077e21d43" dependencies = [ "libc", "num_enum", - "vmm-sys-util 0.14.0", + "vmm-sys-util 0.15.0", "zerocopy 0.8.26", ] @@ -2080,7 +2080,7 @@ dependencies = [ "libc", "mshv-bindings 0.2.1", "thiserror 1.0.69", - "vmm-sys-util 0.14.0", + "vmm-sys-util 0.15.0", ] [[package]] @@ -2092,7 +2092,7 @@ dependencies = [ "libc", "mshv-bindings 0.3.2", "thiserror 2.0.12", - "vmm-sys-util 0.14.0", + "vmm-sys-util 0.15.0", ] [[package]] From 13f4932383fe3d2cf6db8271d5c00d5e79270aac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 08:37:42 +0000 Subject: [PATCH 090/271] Bump proc-macro2 from 1.0.95 to 1.0.96 (#774) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.95 to 1.0.96. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.95...1.0.96) --- updated-dependencies: - dependency-name: proc-macro2 dependency-version: 1.0.96 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96be38ebf..f442ceb8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2637,9 +2637,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "beef09f85ae72cea1ef96ba6870c51e6382ebfa4f0e85b643459331f3daa5be0" dependencies = [ "unicode-ident", ] diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index 204127cf6..395b6e878 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] wasmparser = { version = "0.236.0" } quote = { version = "1.0.38" } -proc-macro2 = { version = "1.0.95" } +proc-macro2 = { version = "1.0.96" } syn = { version = "2.0.104" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.36" } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index 1c270a18a..6f7dc9acf 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -17,7 +17,7 @@ name = "hyperlight_component_util" [dependencies] wasmparser = { version = "0.236.0" } quote = { version = "1.0.38" } -proc-macro2 = { version = "1.0.95" } +proc-macro2 = { version = "1.0.96" } syn = { version = "2.0.104" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.36" } From 1e3837c4fa540fd5ca9fc40bb5131707abb97746 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 10:37:44 +0100 Subject: [PATCH 091/271] Bump crate-ci/typos from 1.35.1 to 1.35.3 (#775) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.35.1 to 1.35.3. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.35.1...v1.35.3) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.35.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ValidatePullRequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index f37cb2fab..54f4369e5 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -65,7 +65,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Spell Check Repo - uses: crate-ci/typos@v1.35.1 + uses: crate-ci/typos@v1.35.3 license-headers: name: check license headers From f065a27ee0a95ddaab147ba8aaf467c5d6dc466d Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Tue, 12 Aug 2025 09:00:55 +0100 Subject: [PATCH 092/271] fix release blocker so it only blocks on release branches (#777) Signed-off-by: Simon Davies --- .github/workflows/ReleaseBlockerCheck.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ReleaseBlockerCheck.yml b/.github/workflows/ReleaseBlockerCheck.yml index 90ea4ff1e..5baf9881e 100644 --- a/.github/workflows/ReleaseBlockerCheck.yml +++ b/.github/workflows/ReleaseBlockerCheck.yml @@ -30,9 +30,15 @@ jobs: REPO="${{ inputs.repository || github.repository }}" echo "Checking repository: $REPO" - if ! ./dev/check-release-blockers.sh "$REPO"; then - echo "::error::Release blocked by open issues with 'release-blocker' label" - exit 1 + # Only check for release blockers on release branches + if [[ "${{ github.ref }}" == *"refs/heads/release/"* ]]; then + echo "Release branch detected - checking for release blockers..." + if ! ./dev/check-release-blockers.sh "$REPO"; then + echo "::error::Release blocked by open issues with 'release-blocker' label" + exit 1 + fi + else + echo "Non-release branch - skipping release blocker check" fi env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 9c3e042152a9c00937b82f8e22b84c43a9d1be96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 17:24:47 +0000 Subject: [PATCH 093/271] Bump thiserror from 2.0.12 to 2.0.14 (#787) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 2.0.12 to 2.0.14. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/2.0.12...2.0.14) --- updated-dependencies: - dependency-name: thiserror dependency-version: 2.0.14 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 30 +++++++++++++++--------------- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f442ceb8f..2be8e5dc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1482,7 +1482,7 @@ dependencies = [ "signal-hook-registry", "tempfile", "termcolor", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", "tracing", "tracing-chrome", @@ -1935,7 +1935,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149" dependencies = [ - "thiserror 2.0.12", + "thiserror 2.0.14", "zerocopy 0.8.26", "zerocopy-derive 0.8.26", ] @@ -1997,7 +1997,7 @@ dependencies = [ "metrics", "metrics-util", "quanta", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -2091,7 +2091,7 @@ checksum = "89abe853221fa6f14ad4066affb9abda241a03d65622887d5794e1422d0bd75a" dependencies = [ "libc", "mshv-bindings 0.3.2", - "thiserror 2.0.12", + "thiserror 2.0.14", "vmm-sys-util 0.15.0", ] @@ -2213,7 +2213,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.12", + "thiserror 2.0.14", "tracing", ] @@ -2243,7 +2243,7 @@ dependencies = [ "opentelemetry_sdk", "prost", "reqwest", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -2277,7 +2277,7 @@ dependencies = [ "percent-encoding", "rand", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", "tokio-stream", ] @@ -2400,7 +2400,7 @@ checksum = "97f6fccfd2d9d2df765ca23ff85fe5cc437fb0e6d3e164e4d3cbe09d14780c93" dependencies = [ "arrayvec", "bitflags 2.9.1", - "thiserror 2.0.12", + "thiserror 2.0.14", "zerocopy 0.8.26", "zerocopy-derive 0.8.26", ] @@ -2840,7 +2840,7 @@ checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3387,11 +3387,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "0b0949c3a6c842cbde3f1686d6eea5a010516deb7085f79db747562d4102f41e" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.14", ] [[package]] @@ -3407,9 +3407,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227" dependencies = [ "proc-macro2", "quote", @@ -3656,7 +3656,7 @@ dependencies = [ "chrono", "serde", "smallvec", - "thiserror 2.0.12", + "thiserror 2.0.14", "tracing", "tracing-subscriber", "uuid", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 0a40161c1..56c5b1c3d 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -42,7 +42,7 @@ hyperlight-common = { workspace = true, default-features = true, features = [ "s hyperlight-guest-tracing = { workspace = true, default-features = true, optional = true } vmm-sys-util = "0.15.0" crossbeam-channel = "0.5.15" -thiserror = "2.0.12" +thiserror = "2.0.14" chrono = { version = "0.4", optional = true } anyhow = "1.0" metrics = "0.24.2" From c35f3ba155e9d6d4528457013705585ae8fd91a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 18:10:05 +0000 Subject: [PATCH 094/271] Bump anyhow from 1.0.98 to 1.0.99 (#786) Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.98 to 1.0.99. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.98...1.0.99) --- updated-dependencies: - dependency-name: anyhow dependency-version: 1.0.99 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_common/Cargo.toml | 2 +- src/hyperlight_guest/Cargo.toml | 2 +- src/hyperlight_host/Cargo.toml | 2 +- src/hyperlight_testing/Cargo.toml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2be8e5dc5..3bb068551 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -127,9 +127,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "arbitrary" diff --git a/src/hyperlight_common/Cargo.toml b/src/hyperlight_common/Cargo.toml index ac83d6322..a7a307c73 100644 --- a/src/hyperlight_common/Cargo.toml +++ b/src/hyperlight_common/Cargo.toml @@ -16,7 +16,7 @@ workspace = true [dependencies] flatbuffers = { version = "25.2.10", default-features = false } -anyhow = { version = "1.0.98", default-features = false } +anyhow = { version = "1.0.99", default-features = false } log = "0.4.27" tracing = { version = "0.1.41", optional = true } arbitrary = {version = "1.4.1", optional = true, features = ["derive"]} diff --git a/src/hyperlight_guest/Cargo.toml b/src/hyperlight_guest/Cargo.toml index 90155bb3d..73a669862 100644 --- a/src/hyperlight_guest/Cargo.toml +++ b/src/hyperlight_guest/Cargo.toml @@ -12,7 +12,7 @@ Provides only the essential building blocks for interacting with the host enviro """ [dependencies] -anyhow = { version = "1.0.98", default-features = false } +anyhow = { version = "1.0.99", default-features = false } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } hyperlight-common = { workspace = true } hyperlight-guest-tracing = { workspace = true, default-features = false } diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 56c5b1c3d..d42a2c175 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -119,7 +119,7 @@ windows = { version = "0.61", features = [ proc-maps = "0.4.0" [build-dependencies] -anyhow = { version = "1.0.98" } +anyhow = { version = "1.0.99" } cfg_aliases = "0.2.1" built = { version = "0.8.0", optional = true, features = ["chrono", "git2"] } diff --git a/src/hyperlight_testing/Cargo.toml b/src/hyperlight_testing/Cargo.toml index fca693d16..975397c47 100644 --- a/src/hyperlight_testing/Cargo.toml +++ b/src/hyperlight_testing/Cargo.toml @@ -3,7 +3,7 @@ name = "hyperlight-testing" edition = "2021" [dependencies] -anyhow = "1.0.98" +anyhow = "1.0.99" log = "0.4" once_cell = "1.21" tracing = { version = "0.1.41", features = ["log"] } From 3bcdfc6d6a80c672c5492fbfa1ab156b4005b010 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 18:10:58 +0000 Subject: [PATCH 095/271] Bump hyperlight-dev/ci-setup-workflow from 1.5.0 to 1.6.0 (#782) --- .github/workflows/Benchmarks.yml | 2 +- .github/workflows/CargoPublish.yml | 2 +- .github/workflows/CreateRelease.yml | 6 +++--- .github/workflows/copilot-setup-steps.yml | 2 +- .github/workflows/dep_build_guest_binaries.yml | 2 +- .github/workflows/dep_fuzzing.yml | 2 +- .github/workflows/dep_rust.yml | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/Benchmarks.yml b/.github/workflows/Benchmarks.yml index e987f0e2d..f74098293 100644 --- a/.github/workflows/Benchmarks.yml +++ b/.github/workflows/Benchmarks.yml @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@v4 - - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: rust-toolchain: "1.86" env: diff --git a/.github/workflows/CargoPublish.yml b/.github/workflows/CargoPublish.yml index fd80e1532..5ed738cb4 100644 --- a/.github/workflows/CargoPublish.yml +++ b/.github/workflows/CargoPublish.yml @@ -32,7 +32,7 @@ jobs: fetch-depth: 0 fetch-tags: true - - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: rust-toolchain: "1.86" diff --git a/.github/workflows/CreateRelease.yml b/.github/workflows/CreateRelease.yml index a0ca117a4..00b2f28b7 100644 --- a/.github/workflows/CreateRelease.yml +++ b/.github/workflows/CreateRelease.yml @@ -31,7 +31,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: rust-toolchain: "1.86" env: @@ -52,7 +52,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: rust-toolchain: "1.86" env: @@ -112,7 +112,7 @@ jobs: fetch-depth: 0 fetch-tags: true - - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: rust-toolchain: "1.86" env: diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index f6f09538b..d275d883b 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -26,7 +26,7 @@ jobs: with: components: rustfmt - - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: rust-toolchain: "1.86" env: diff --git a/.github/workflows/dep_build_guest_binaries.yml b/.github/workflows/dep_build_guest_binaries.yml index 0edfbd739..3e54e3892 100644 --- a/.github/workflows/dep_build_guest_binaries.yml +++ b/.github/workflows/dep_build_guest_binaries.yml @@ -31,7 +31,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: rust-toolchain: "1.86" env: diff --git a/.github/workflows/dep_fuzzing.yml b/.github/workflows/dep_fuzzing.yml index 29832157e..4bb0d810e 100644 --- a/.github/workflows/dep_fuzzing.yml +++ b/.github/workflows/dep_fuzzing.yml @@ -32,7 +32,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: rust-toolchain: "1.86" env: diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index 2e45faefd..6b0f26fef 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -46,7 +46,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: rust-toolchain: "1.86" env: @@ -98,7 +98,7 @@ jobs: with: components: rustfmt - - uses: hyperlight-dev/ci-setup-workflow@v1.5.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: rust-toolchain: "1.86" env: From 3a3c8adcbfbcdc1b34c27e4e0f09620b833ff7a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 18:11:27 +0000 Subject: [PATCH 096/271] Bump proc-macro2 from 1.0.96 to 1.0.97 (#785) --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3bb068551..4e8cffff4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2637,9 +2637,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.96" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beef09f85ae72cea1ef96ba6870c51e6382ebfa4f0e85b643459331f3daa5be0" +checksum = "d61789d7719defeb74ea5fe81f2fdfdbd28a803847077cecce2ff14e1472f6f1" dependencies = [ "unicode-ident", ] diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index 395b6e878..d15d3dd5a 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] wasmparser = { version = "0.236.0" } quote = { version = "1.0.38" } -proc-macro2 = { version = "1.0.96" } +proc-macro2 = { version = "1.0.97" } syn = { version = "2.0.104" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.36" } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index 6f7dc9acf..a4f347755 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -17,7 +17,7 @@ name = "hyperlight_component_util" [dependencies] wasmparser = { version = "0.236.0" } quote = { version = "1.0.38" } -proc-macro2 = { version = "1.0.96" } +proc-macro2 = { version = "1.0.97" } syn = { version = "2.0.104" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.36" } From 748531927a90bc65b844adfc0107c714748c3e36 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 18:12:53 +0000 Subject: [PATCH 097/271] Bump glob from 0.3.2 to 0.3.3 (#781) Bumps [glob](https://github.com/rust-lang/glob) from 0.3.2 to 0.3.3. - [Release notes](https://github.com/rust-lang/glob/releases) - [Changelog](https://github.com/rust-lang/glob/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/glob/compare/v0.3.2...v0.3.3) --- updated-dependencies: - dependency-name: glob dependency-version: 0.3.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_guest_bin/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e8cffff4..cb29d2152 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1180,9 +1180,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "globset" diff --git a/src/hyperlight_guest_bin/Cargo.toml b/src/hyperlight_guest_bin/Cargo.toml index 79fad4450..c21d00c91 100644 --- a/src/hyperlight_guest_bin/Cargo.toml +++ b/src/hyperlight_guest_bin/Cargo.toml @@ -34,4 +34,4 @@ workspace = true [build-dependencies] cc = "1.2" cfg-if = "1.0" -glob = "0.3.2" +glob = "0.3.3" From 4c46826c88d705a4b138742ed01ee6972b086750 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 18:15:05 +0000 Subject: [PATCH 098/271] Bump libc from 0.2.174 to 0.2.175 (#784) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.174 to 0.2.175. - [Release notes](https://github.com/rust-lang/libc/releases) - [Changelog](https://github.com/rust-lang/libc/blob/0.2.175/CHANGELOG.md) - [Commits](https://github.com/rust-lang/libc/compare/0.2.174...0.2.175) --- updated-dependencies: - dependency-name: libc dependency-version: 0.2.175 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cb29d2152..bdd5d86fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1810,9 +1810,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.174" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libfuzzer-sys" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index d42a2c175..f54bfa7ce 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -26,7 +26,7 @@ gdbstub_arch = { version = "0.3.2", optional = true } goblin = { version = "0.10", default-features = false, features = ["std", "elf32", "elf64", "endian_fd"] } rand = { version = "0.9" } cfg-if = { version = "1.0.1" } -libc = { version = "0.2.174" } +libc = { version = "0.2.175" } flatbuffers = "25.2.10" framehop = { version = "0.15.0", optional = true } fallible-iterator = { version = "0.3.0", optional = true } From 7ed9e2f358215bc8e4be5bfdafe238c8ce124e0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 18:38:32 +0000 Subject: [PATCH 099/271] Bump actions/checkout from 4 to 5 (#780) --- .github/workflows/Benchmarks.yml | 2 +- .github/workflows/CargoAudit.yml | 2 +- .github/workflows/CargoPublish.yml | 2 +- .github/workflows/CleanUpReleasesAndPackages.yml | 2 +- .github/workflows/CreateDevcontainerImage.yml | 2 +- .github/workflows/CreateRelease.yml | 6 +++--- .github/workflows/CreateReleaseBranch.yml | 2 +- .github/workflows/IssueLabelChecker.yml | 2 +- .github/workflows/PRLabelChecker.yml | 2 +- .github/workflows/ReleaseBlockerCheck.yml | 2 +- .github/workflows/ReleaseBlockerLabelCleanUp.yml | 2 +- .github/workflows/ValidatePullRequest.yml | 4 ++-- .github/workflows/auto-merge-dependabot.yml | 2 +- .github/workflows/copilot-setup-steps.yml | 2 +- .github/workflows/dep_build_guest_binaries.yml | 2 +- .github/workflows/dep_fuzzing.yml | 2 +- .github/workflows/dep_rust.yml | 4 ++-- 17 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/Benchmarks.yml b/.github/workflows/Benchmarks.yml index f74098293..3be8c549f 100644 --- a/.github/workflows/Benchmarks.yml +++ b/.github/workflows/Benchmarks.yml @@ -26,7 +26,7 @@ jobs: steps: ### Setup ### - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: diff --git a/.github/workflows/CargoAudit.yml b/.github/workflows/CargoAudit.yml index de81fa6f6..4c19c8a74 100644 --- a/.github/workflows/CargoAudit.yml +++ b/.github/workflows/CargoAudit.yml @@ -13,7 +13,7 @@ jobs: audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 # We are not using the common workflow here because it installs a bunch of tools we don't need. # TODO: Once the runner image is updated to include the necessary tools (without downloading), we can switch to the common workflow. diff --git a/.github/workflows/CargoPublish.yml b/.github/workflows/CargoPublish.yml index 5ed738cb4..a9e77f08e 100644 --- a/.github/workflows/CargoPublish.yml +++ b/.github/workflows/CargoPublish.yml @@ -27,7 +27,7 @@ jobs: if: ${{ startsWith(github.ref, 'refs/heads/release/v') || inputs.dry_run }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 fetch-tags: true diff --git a/.github/workflows/CleanUpReleasesAndPackages.yml b/.github/workflows/CleanUpReleasesAndPackages.yml index 64bce8650..8d2404f4c 100644 --- a/.github/workflows/CleanUpReleasesAndPackages.yml +++ b/.github/workflows/CleanUpReleasesAndPackages.yml @@ -28,7 +28,7 @@ jobs: env: GITHUB_TOKEN: ${{ github.token }} - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Delete old Github Actions Artifacts env: diff --git a/.github/workflows/CreateDevcontainerImage.yml b/.github/workflows/CreateDevcontainerImage.yml index 1668a5c11..72b977f98 100644 --- a/.github/workflows/CreateDevcontainerImage.yml +++ b/.github/workflows/CreateDevcontainerImage.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Read Rust toolchain version from ${{ env.RUST_TOOLCHAIN_FILE }} id: toolchain diff --git a/.github/workflows/CreateRelease.yml b/.github/workflows/CreateRelease.yml index 00b2f28b7..2adc5069d 100644 --- a/.github/workflows/CreateRelease.yml +++ b/.github/workflows/CreateRelease.yml @@ -29,7 +29,7 @@ jobs: needs: [release-blocker-check] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: @@ -50,7 +50,7 @@ jobs: needs: [release-blocker-check] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: @@ -107,7 +107,7 @@ jobs: if: ${{ contains(github.ref, 'refs/heads/release/') }} run: echo "CONFIG=release" >> $GITHUB_ENV - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 fetch-tags: true diff --git a/.github/workflows/CreateReleaseBranch.yml b/.github/workflows/CreateReleaseBranch.yml index 500efc637..275f90928 100644 --- a/.github/workflows/CreateReleaseBranch.yml +++ b/.github/workflows/CreateReleaseBranch.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Create Release Branch run: | diff --git a/.github/workflows/IssueLabelChecker.yml b/.github/workflows/IssueLabelChecker.yml index 53ed1f33f..4d1d0fcc4 100644 --- a/.github/workflows/IssueLabelChecker.yml +++ b/.github/workflows/IssueLabelChecker.yml @@ -11,7 +11,7 @@ jobs: labeler: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Check and Add label run: | # The cryptic head -c -1 is because otherwise gh always terminates output with a newline diff --git a/.github/workflows/PRLabelChecker.yml b/.github/workflows/PRLabelChecker.yml index e824aa5a8..d5186324b 100644 --- a/.github/workflows/PRLabelChecker.yml +++ b/.github/workflows/PRLabelChecker.yml @@ -11,7 +11,7 @@ jobs: check-labels: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Ensure exactly one "kind/*" label is applied run: | # Count the number of "kind/*" labels directly from the PR labels diff --git a/.github/workflows/ReleaseBlockerCheck.yml b/.github/workflows/ReleaseBlockerCheck.yml index 5baf9881e..d6857bc74 100644 --- a/.github/workflows/ReleaseBlockerCheck.yml +++ b/.github/workflows/ReleaseBlockerCheck.yml @@ -23,7 +23,7 @@ jobs: check-blockers: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Check for Release Blocking Issues run: | diff --git a/.github/workflows/ReleaseBlockerLabelCleanUp.yml b/.github/workflows/ReleaseBlockerLabelCleanUp.yml index d23bd928c..7aa93e8a5 100644 --- a/.github/workflows/ReleaseBlockerLabelCleanUp.yml +++ b/.github/workflows/ReleaseBlockerLabelCleanUp.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Remove release-blocker label from closed issue run: | ISSUE_NUMBER=${{ github.event.issue.number }} diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index 54f4369e5..9aa73e781 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -63,7 +63,7 @@ jobs: name: spell check with typos runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Spell Check Repo uses: crate-ci/typos@v1.35.3 @@ -71,7 +71,7 @@ jobs: name: check license headers runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Check License Headers run: ./dev/check-license-headers.sh diff --git a/.github/workflows/auto-merge-dependabot.yml b/.github/workflows/auto-merge-dependabot.yml index 1248d16bb..0586963af 100644 --- a/.github/workflows/auto-merge-dependabot.yml +++ b/.github/workflows/auto-merge-dependabot.yml @@ -33,7 +33,7 @@ jobs: permission-contents: write - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: token: ${{ steps.get-app-token.outputs.token }} persist-credentials: false diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index d275d883b..6abf73e74 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -18,7 +18,7 @@ jobs: # If you do not check out your code, Copilot will do this for you. steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 # For rust-fmt - name: Set up nightly rust diff --git a/.github/workflows/dep_build_guest_binaries.yml b/.github/workflows/dep_build_guest_binaries.yml index 3e54e3892..8cc6d1089 100644 --- a/.github/workflows/dep_build_guest_binaries.yml +++ b/.github/workflows/dep_build_guest_binaries.yml @@ -29,7 +29,7 @@ jobs: config: release steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: diff --git a/.github/workflows/dep_fuzzing.yml b/.github/workflows/dep_fuzzing.yml index 4bb0d810e..95008efd4 100644 --- a/.github/workflows/dep_fuzzing.yml +++ b/.github/workflows/dep_fuzzing.yml @@ -30,7 +30,7 @@ jobs: target: ${{ fromJson(inputs.targets) }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index 6b0f26fef..c266c25cc 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -44,7 +44,7 @@ jobs: (matrix.hypervisor == 'hyperv-ws2025') && 'Windows' || 'Linux', matrix.hypervisor == 'hyperv-ws2025' && 'win2025' || 'kvm')) }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 with: @@ -90,7 +90,7 @@ jobs: matrix.hypervisor == 'hyperv' && 'win2022' || matrix.hypervisor == 'hyperv-ws2025' && 'win2025' || matrix.hypervisor == 'mshv3' && 'azlinux3-mshv' || matrix.hypervisor, matrix.cpu)) }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 # For rust-fmt - name: Set up nightly rust From 2bba904c1e7f5efe491087c90f21ae6b2609341b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Aug 2025 08:53:36 +0100 Subject: [PATCH 100/271] Bump crate-ci/typos from 1.35.3 to 1.35.4 (#788) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.35.3 to 1.35.4. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.35.3...v1.35.4) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.35.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ValidatePullRequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index 9aa73e781..4b6194cf3 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -65,7 +65,7 @@ jobs: steps: - uses: actions/checkout@v5 - name: Spell Check Repo - uses: crate-ci/typos@v1.35.3 + uses: crate-ci/typos@v1.35.4 license-headers: name: check license headers From 158df6260419643bc5e81f2f6d65421007d1fc61 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Aug 2025 08:14:28 +0000 Subject: [PATCH 101/271] Bump uuid from 1.17.0 to 1.18.0 (#783) Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.17.0 to 1.18.0. - [Release notes](https://github.com/uuid-rs/uuid/releases) - [Commits](https://github.com/uuid-rs/uuid/compare/v1.17.0...v1.18.0) --- updated-dependencies: - dependency-name: uuid dependency-version: 1.18.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bdd5d86fc..4cdd52c9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3875,9 +3875,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" dependencies = [ "getrandom 0.3.3", "js-sys", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index f54bfa7ce..812d58fbe 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -48,7 +48,7 @@ anyhow = "1.0" metrics = "0.24.2" serde_json = "1.0" elfcore = "2.0" -uuid = { version = "1.17.0", features = ["v4"] } +uuid = { version = "1.18.0", features = ["v4"] } [target.'cfg(windows)'.dependencies] windows = { version = "0.61", features = [ @@ -82,7 +82,7 @@ mshv-bindings3 = { package="mshv-bindings", version = "=0.3.2", optional = true mshv-ioctls3 = { package="mshv-ioctls", version = "=0.3.2", optional = true} [dev-dependencies] -uuid = { version = "1.17.0", features = ["v4"] } +uuid = { version = "1.18.0", features = ["v4"] } signal-hook-registry = "1.4.6" envy = { version = "0.4.2" } serde = "1.0" From 243913b10fe20301ca18d2dd2c4f8ec9be0e2b02 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Aug 2025 04:17:02 +0000 Subject: [PATCH 102/271] Bump syn from 2.0.104 to 2.0.105 (#790) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.104 to 2.0.105. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.104...2.0.105) --- updated-dependencies: - dependency-name: syn dependency-version: 2.0.105 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- src/hyperlight_guest_tracing_macro/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4cdd52c9f..cb567d6df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3306,9 +3306,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.104" +version = "2.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "7bc3fcb250e53458e712715cf74285c1f889686520d79294a9ef3bd7aa1fc619" dependencies = [ "proc-macro2", "quote", diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index d15d3dd5a..c31f5c634 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -19,7 +19,7 @@ proc-macro = true wasmparser = { version = "0.236.0" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.97" } -syn = { version = "2.0.104" } +syn = { version = "2.0.105" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.36" } hyperlight-component-util = { workspace = true } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index a4f347755..8eaf6c89a 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -18,7 +18,7 @@ name = "hyperlight_component_util" wasmparser = { version = "0.236.0" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.97" } -syn = { version = "2.0.104" } +syn = { version = "2.0.105" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.36" } log = { version = "0.4" } \ No newline at end of file diff --git a/src/hyperlight_guest_tracing_macro/Cargo.toml b/src/hyperlight_guest_tracing_macro/Cargo.toml index 9fc1df9d5..552bf072b 100644 --- a/src/hyperlight_guest_tracing_macro/Cargo.toml +++ b/src/hyperlight_guest_tracing_macro/Cargo.toml @@ -12,7 +12,7 @@ description = """Provides the tracing macros for the hyperlight guest, enabling [dependencies] proc-macro2 = "1.0" quote = "1.0.40" -syn = { version = "2.0.104", features = ["full"] } +syn = { version = "2.0.105", features = ["full"] } [features] default = [] From 7da939f890c023c8485217001d318086f065bb63 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 14 Aug 2025 20:54:34 +0000 Subject: [PATCH 103/271] Enforce release builds for benchmarks and simplify command interface (#741) * Initial plan Signed-off-by: Simon Davies * Enforce release builds for benchmarks in Justfile and source code Co-authored-by: jsturtevant <648372+jsturtevant@users.noreply.github.com> Signed-off-by: Simon Davies * Remove compile-time error for benchmarks to allow profiling with debug symbols Co-authored-by: ludfjig <4257730+ludfjig@users.noreply.github.com> Signed-off-by: Simon Davies * Remove unnecessary target parameter from bench commands - Remove target parameter from bench and bench-ci commands since they only accept release builds - Update GitHub workflows to remove target parameter usage - Simplify command signatures based on @syntactically's feedback Co-authored-by: syntactically <168595099+syntactically@users.noreply.github.com> Signed-off-by: Simon Davies * Update documentation to reflect that debug builds are now supported for profiling Co-authored-by: ludfjig <4257730+ludfjig@users.noreply.github.com> Signed-off-by: Simon Davies --------- Signed-off-by: Simon Davies Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jsturtevant <648372+jsturtevant@users.noreply.github.com> Co-authored-by: ludfjig <4257730+ludfjig@users.noreply.github.com> Co-authored-by: syntactically <168595099+syntactically@users.noreply.github.com> --- .github/workflows/Benchmarks.yml | 2 +- .github/workflows/dep_rust.yml | 2 +- Justfile | 10 ++++++---- docs/benchmarking-hyperlight.md | 4 +++- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/Benchmarks.yml b/.github/workflows/Benchmarks.yml index 3be8c549f..88b628e1e 100644 --- a/.github/workflows/Benchmarks.yml +++ b/.github/workflows/Benchmarks.yml @@ -57,7 +57,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Run Benchmarks - run: just bench-ci main release ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} + run: just bench-ci main ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} - uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index c266c25cc..b93042c50 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -186,5 +186,5 @@ jobs: - name: Run benchmarks run: | - just bench-ci main ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} + just bench-ci main ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} if: ${{ matrix.config == 'release' }} diff --git a/Justfile b/Justfile index 9ae49e3d2..c364937e7 100644 --- a/Justfile +++ b/Justfile @@ -326,11 +326,13 @@ bench-download os hypervisor cpu tag="": tar -zxvf target/benchmarks_{{ os }}_{{ hypervisor }}_{{ cpu }}.tar.gz -C target/criterion/ --strip-components=1 # Warning: compares to and then OVERWRITES the given baseline -bench-ci baseline target=default-target features="": - cargo bench --profile={{ if target == "debug" { "dev" } else { target } }} {{ if features =="" {''} else { "--features " + features } }} -- --verbose --save-baseline {{ baseline }} +bench-ci baseline features="": + @# Benchmarks are always run with release builds for meaningful results + cargo bench --profile=release {{ if features =="" {''} else { "--features " + features } }} -- --verbose --save-baseline {{ baseline }} -bench target=default-target features="": - cargo bench --profile={{ if target == "debug" { "dev" } else { target } }} {{ if features =="" {''} else { "--features " + features } }} -- --verbose +bench features="": + @# Benchmarks are always run with release builds for meaningful results + cargo bench --profile=release {{ if features =="" {''} else { "--features " + features } }} -- --verbose ############### ### FUZZING ### diff --git a/docs/benchmarking-hyperlight.md b/docs/benchmarking-hyperlight.md index 3ae56d55c..5ac2662f4 100644 --- a/docs/benchmarking-hyperlight.md +++ b/docs/benchmarking-hyperlight.md @@ -72,4 +72,6 @@ Found 1 outliers among 100 measurements (1.00%) ## Running benchmarks locally -Use `just bench [debug/release]` parameter to run benchmarks. Comparing local benchmarks results to github-saved benchmarks doesn't make much sense, since you'd be using different hardware, but you can use `just bench-download os hypervisor [tag] ` to download and extract the GitHub release benchmarks to the correct place folder. You can then run `just bench-ci main` to compare to (and overwrite) the previous release benchmarks. Note that `main` is the name of the baselines stored in GitHub. +Use `just bench` to run benchmarks with release builds (the only supported configuration). Comparing local benchmark results to github-saved benchmarks doesn't make much sense, since you'd be using different hardware, but you can use `just bench-download os hypervisor [tag] ` to download and extract the GitHub release benchmarks to the correct place folder. You can then run `just bench-ci main` to compare to (and overwrite) the previous release benchmarks. Note that `main` is the name of the baselines stored in GitHub. + +**Important**: The `just bench` command uses release builds by default to ensure meaningful performance measurements. For profiling purposes, you can compile benchmarks with debug symbols by running `cargo bench` directly. From 5fd3e9817112fc6679c01a34ecd1c15dbfa10f50 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 04:11:30 +0000 Subject: [PATCH 104/271] Bump wasmparser from 0.236.0 to 0.236.1 (#794) Bumps [wasmparser](https://github.com/bytecodealliance/wasm-tools) from 0.236.0 to 0.236.1. - [Release notes](https://github.com/bytecodealliance/wasm-tools/releases) - [Commits](https://github.com/bytecodealliance/wasm-tools/commits) --- updated-dependencies: - dependency-name: wasmparser dependency-version: 0.236.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cb567d6df..2f2165bbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4045,9 +4045,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.236.0" +version = "0.236.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d1eee846a705f6f3cb9d7b9f79b54583810f1fb57a1e3aea76d1742db2e3d2" +checksum = "a9b1e81f3eb254cf7404a82cee6926a4a3ccc5aad80cc3d43608a070c67aa1d7" dependencies = [ "bitflags 2.9.1", "hashbrown", diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index c31f5c634..f0d5d6796 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -16,7 +16,7 @@ name = "hyperlight_component_macro" proc-macro = true [dependencies] -wasmparser = { version = "0.236.0" } +wasmparser = { version = "0.236.1" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.97" } syn = { version = "2.0.105" } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index 8eaf6c89a..d2b58e4f8 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -15,7 +15,7 @@ Shared implementation for the procedural macros that generate Hyperlight host an name = "hyperlight_component_util" [dependencies] -wasmparser = { version = "0.236.0" } +wasmparser = { version = "0.236.1" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.97" } syn = { version = "2.0.105" } From a5e45f4c2b36174c536194fa2b8b2807110d8982 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 04:11:38 +0000 Subject: [PATCH 105/271] Bump gdbstub from 0.7.6 to 0.7.7 (#792) Bumps [gdbstub](https://github.com/daniel5151/gdbstub) from 0.7.6 to 0.7.7. - [Release notes](https://github.com/daniel5151/gdbstub/releases) - [Changelog](https://github.com/daniel5151/gdbstub/blob/master/CHANGELOG.md) - [Commits](https://github.com/daniel5151/gdbstub/compare/0.7.6...0.7.7) --- updated-dependencies: - dependency-name: gdbstub dependency-version: 0.7.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f2165bbf..a64ed65eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1006,9 +1006,9 @@ dependencies = [ [[package]] name = "gdbstub" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d66e32caf5dd59f561be0143e413e01d651bd8498eb9aa0be8c482c81c8d31" +checksum = "b686b198dfaa4109ebd0443d2841bc521e4b4b2915f1d84b3bb50332a8cdc1ae" dependencies = [ "bitflags 2.9.1", "cfg-if", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 812d58fbe..e1f140904 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -21,7 +21,7 @@ bench = false # see https://bheisler.github.io/criterion.rs/book/faq.html#cargo- workspace = true [dependencies] -gdbstub = { version = "0.7.6", optional = true } +gdbstub = { version = "0.7.7", optional = true } gdbstub_arch = { version = "0.3.2", optional = true } goblin = { version = "0.10", default-features = false, features = ["std", "elf32", "elf64", "endian_fd"] } rand = { version = "0.9" } From 1b4bd799d37a62886ca34f9769c91b0ad4ebf101 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 17:39:36 -0700 Subject: [PATCH 106/271] Bump goblin from 0.10.0 to 0.10.1 (#802) Bumps [goblin](https://github.com/m4b/goblin) from 0.10.0 to 0.10.1. - [Changelog](https://github.com/m4b/goblin/blob/master/CHANGELOG.md) - [Commits](https://github.com/m4b/goblin/commits) --- updated-dependencies: - dependency-name: goblin dependency-version: 0.10.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a64ed65eb..69d63ebca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1210,9 +1210,9 @@ dependencies = [ [[package]] name = "goblin" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e961b33649994dcf69303af6b3a332c1228549e604d455d61ec5d2ab5e68d3a" +checksum = "d6a80adfd63bd7ffd94fefc3d22167880c440a724303080e5aa686fa36abaa96" dependencies = [ "log", "plain", From 228c83ea61e1fd82ff42983198445f9ed53393f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 18:09:51 -0700 Subject: [PATCH 107/271] Bump thiserror from 2.0.14 to 2.0.15 (#800) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 2.0.14 to 2.0.15. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/2.0.14...2.0.15) --- updated-dependencies: - dependency-name: thiserror dependency-version: 2.0.15 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 30 +++++++++++++++--------------- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 69d63ebca..5b61e88b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1482,7 +1482,7 @@ dependencies = [ "signal-hook-registry", "tempfile", "termcolor", - "thiserror 2.0.14", + "thiserror 2.0.15", "tokio", "tracing", "tracing-chrome", @@ -1935,7 +1935,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149" dependencies = [ - "thiserror 2.0.14", + "thiserror 2.0.15", "zerocopy 0.8.26", "zerocopy-derive 0.8.26", ] @@ -1997,7 +1997,7 @@ dependencies = [ "metrics", "metrics-util", "quanta", - "thiserror 2.0.14", + "thiserror 2.0.15", ] [[package]] @@ -2091,7 +2091,7 @@ checksum = "89abe853221fa6f14ad4066affb9abda241a03d65622887d5794e1422d0bd75a" dependencies = [ "libc", "mshv-bindings 0.3.2", - "thiserror 2.0.14", + "thiserror 2.0.15", "vmm-sys-util 0.15.0", ] @@ -2213,7 +2213,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.14", + "thiserror 2.0.15", "tracing", ] @@ -2243,7 +2243,7 @@ dependencies = [ "opentelemetry_sdk", "prost", "reqwest", - "thiserror 2.0.14", + "thiserror 2.0.15", ] [[package]] @@ -2277,7 +2277,7 @@ dependencies = [ "percent-encoding", "rand", "serde_json", - "thiserror 2.0.14", + "thiserror 2.0.15", "tokio", "tokio-stream", ] @@ -2400,7 +2400,7 @@ checksum = "97f6fccfd2d9d2df765ca23ff85fe5cc437fb0e6d3e164e4d3cbe09d14780c93" dependencies = [ "arrayvec", "bitflags 2.9.1", - "thiserror 2.0.14", + "thiserror 2.0.15", "zerocopy 0.8.26", "zerocopy-derive 0.8.26", ] @@ -2840,7 +2840,7 @@ checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.14", + "thiserror 2.0.15", ] [[package]] @@ -3387,11 +3387,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.14" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b0949c3a6c842cbde3f1686d6eea5a010516deb7085f79db747562d4102f41e" +checksum = "80d76d3f064b981389ecb4b6b7f45a0bf9fdac1d5b9204c7bd6714fecc302850" dependencies = [ - "thiserror-impl 2.0.14", + "thiserror-impl 2.0.15", ] [[package]] @@ -3407,9 +3407,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.14" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227" +checksum = "44d29feb33e986b6ea906bd9c3559a856983f92371b3eaa5e83782a351623de0" dependencies = [ "proc-macro2", "quote", @@ -3656,7 +3656,7 @@ dependencies = [ "chrono", "serde", "smallvec", - "thiserror 2.0.14", + "thiserror 2.0.15", "tracing", "tracing-subscriber", "uuid", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index e1f140904..1be03d10f 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -42,7 +42,7 @@ hyperlight-common = { workspace = true, default-features = true, features = [ "s hyperlight-guest-tracing = { workspace = true, default-features = true, optional = true } vmm-sys-util = "0.15.0" crossbeam-channel = "0.5.15" -thiserror = "2.0.14" +thiserror = "2.0.15" chrono = { version = "0.4", optional = true } anyhow = "1.0" metrics = "0.24.2" From 0594ed2ef136d6e9fb4cf9f77b1321961165acc5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 18:11:45 -0700 Subject: [PATCH 108/271] Bump syn from 2.0.105 to 2.0.106 (#796) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.105 to 2.0.106. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.105...2.0.106) --- updated-dependencies: - dependency-name: syn dependency-version: 2.0.106 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- src/hyperlight_guest_tracing_macro/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b61e88b4..dbc61377f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3306,9 +3306,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.105" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc3fcb250e53458e712715cf74285c1f889686520d79294a9ef3bd7aa1fc619" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index f0d5d6796..c39ca316e 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -19,7 +19,7 @@ proc-macro = true wasmparser = { version = "0.236.1" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.97" } -syn = { version = "2.0.105" } +syn = { version = "2.0.106" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.36" } hyperlight-component-util = { workspace = true } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index d2b58e4f8..b08e167d9 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -18,7 +18,7 @@ name = "hyperlight_component_util" wasmparser = { version = "0.236.1" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.97" } -syn = { version = "2.0.105" } +syn = { version = "2.0.106" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.36" } log = { version = "0.4" } \ No newline at end of file diff --git a/src/hyperlight_guest_tracing_macro/Cargo.toml b/src/hyperlight_guest_tracing_macro/Cargo.toml index 552bf072b..2070e868f 100644 --- a/src/hyperlight_guest_tracing_macro/Cargo.toml +++ b/src/hyperlight_guest_tracing_macro/Cargo.toml @@ -12,7 +12,7 @@ description = """Provides the tracing macros for the hyperlight guest, enabling [dependencies] proc-macro2 = "1.0" quote = "1.0.40" -syn = { version = "2.0.105", features = ["full"] } +syn = { version = "2.0.106", features = ["full"] } [features] default = [] From 38c4eb989bb61dab57289b331cffdd8e50b7c79e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 04:06:00 +0000 Subject: [PATCH 109/271] Bump proc-macro2 from 1.0.97 to 1.0.101 (#803) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.97 to 1.0.101. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.97...1.0.101) --- updated-dependencies: - dependency-name: proc-macro2 dependency-version: 1.0.101 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbc61377f..d7d0648f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2637,9 +2637,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.97" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61789d7719defeb74ea5fe81f2fdfdbd28a803847077cecce2ff14e1472f6f1" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index c39ca316e..06b7b95b1 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] wasmparser = { version = "0.236.1" } quote = { version = "1.0.38" } -proc-macro2 = { version = "1.0.97" } +proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.36" } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index b08e167d9..e0e0c33fd 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -17,7 +17,7 @@ name = "hyperlight_component_util" [dependencies] wasmparser = { version = "0.236.1" } quote = { version = "1.0.38" } -proc-macro2 = { version = "1.0.97" } +proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.36" } From d48d2b997a94a9d8280238c126860111de5e9066 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 04:06:11 +0000 Subject: [PATCH 110/271] Bump bitflags from 2.9.1 to 2.9.2 (#797) Bumps [bitflags](https://github.com/bitflags/bitflags) from 2.9.1 to 2.9.2. - [Release notes](https://github.com/bitflags/bitflags/releases) - [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md) - [Commits](https://github.com/bitflags/bitflags/compare/2.9.1...2.9.2) --- updated-dependencies: - dependency-name: bitflags dependency-version: 2.9.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 44 +++++++++++++++++----------------- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7d0648f8..d9dfb85e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -202,7 +202,7 @@ version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "cexpr", "clang-sys", "itertools 0.13.0", @@ -239,9 +239,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" [[package]] name = "blake3" @@ -318,7 +318,7 @@ version = "0.20.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e3bd0f4e25afa9cabc157908d14eeef9067d6448c49414d17b3fb55f0eadd0" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "cairo-sys-rs", "glib", "libc", @@ -515,7 +515,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "core-foundation", "core-graphics-types", "foreign-types", @@ -528,7 +528,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "core-foundation", "libc", ] @@ -839,7 +839,7 @@ version = "25.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1045398c1bfd89168b5fd3f1fc11f6e70b34f6f66300c87d44d3de849463abf1" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "rustc_version", ] @@ -1010,7 +1010,7 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b686b198dfaa4109ebd0443d2841bc521e4b4b2915f1d84b3bb50332a8cdc1ae" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "cfg-if", "log", "managed", @@ -1127,7 +1127,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "libc", "libgit2-sys", "log", @@ -1140,7 +1140,7 @@ version = "0.20.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffc4b6e352d4716d84d7dde562dd9aee2a7d48beb872dd9ece7f2d1515b2d683" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "futures-channel", "futures-core", "futures-executor", @@ -1431,7 +1431,7 @@ name = "hyperlight-host" version = "0.8.0" dependencies = [ "anyhow", - "bitflags 2.9.1", + "bitflags 2.9.2", "blake3", "built", "cfg-if", @@ -1675,7 +1675,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "cfg-if", "libc", ] @@ -1796,7 +1796,7 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e00243d27a20feb05cf001ae52ddc79831ac70c020f215ba1153ff9270b650a" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "kvm-bindings", "libc", "vmm-sys-util 0.14.0", @@ -1863,7 +1863,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "libc", ] @@ -2399,7 +2399,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97f6fccfd2d9d2df765ca23ff85fe5cc437fb0e6d3e164e4d3cbe09d14780c93" dependencies = [ "arrayvec", - "bitflags 2.9.1", + "bitflags 2.9.2", "thiserror 2.0.15", "zerocopy 0.8.26", "zerocopy-derive 0.8.26", @@ -2666,7 +2666,7 @@ checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.9.1", + "bitflags 2.9.2", "lazy_static", "num-traits", "rand", @@ -2800,7 +2800,7 @@ version = "11.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", ] [[package]] @@ -2829,7 +2829,7 @@ version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", ] [[package]] @@ -2984,7 +2984,7 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "errno", "libc", "linux-raw-sys", @@ -3570,7 +3570,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "bytes", "futures-util", "http", @@ -4049,7 +4049,7 @@ version = "0.236.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9b1e81f3eb254cf7404a82cee6926a4a3ccc5aad80cc3d43608a070c67aa1d7" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "hashbrown", "indexmap", "semver", @@ -4406,7 +4406,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", ] [[package]] diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 1be03d10f..cc5bc53c6 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -33,7 +33,7 @@ fallible-iterator = { version = "0.3.0", optional = true } blake3 = "1.8.2" page_size = "0.6.0" termcolor = "1.2.0" -bitflags = "2.9.1" +bitflags = "2.9.2" log = "0.4.27" tracing = { version = "0.1.41", features = ["log"] } tracing-log = "0.2.0" From 2522ae62f683f0c5acb4bce492c2f5aab81e268b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 04:41:41 +0000 Subject: [PATCH 111/271] Bump cc from 1.2.32 to 1.2.33 (#798) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.32 to 1.2.33. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.32...cc-v1.2.33) --- updated-dependencies: - dependency-name: cc dependency-version: 1.2.33 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d9dfb85e2..810e0e457 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,9 +362,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.32" +version = "1.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" +checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f" dependencies = [ "jobserver", "libc", From a1997a1aa87e80ee8800e4bd53da0ad419734b73 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 10:01:21 -0700 Subject: [PATCH 112/271] Bump crate-ci/typos from 1.35.4 to 1.35.5 (#806) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.35.4 to 1.35.5. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.35.4...v1.35.5) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.35.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ValidatePullRequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index 4b6194cf3..d3b2c00af 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -65,7 +65,7 @@ jobs: steps: - uses: actions/checkout@v5 - name: Spell Check Repo - uses: crate-ci/typos@v1.35.4 + uses: crate-ci/typos@v1.35.5 license-headers: name: check license headers From ec738e6dd126a5039fa2391b997fe7ae762756e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 10:38:34 -0700 Subject: [PATCH 113/271] Bump prettyplease from 0.2.36 to 0.2.37 (#805) Bumps [prettyplease](https://github.com/dtolnay/prettyplease) from 0.2.36 to 0.2.37. - [Release notes](https://github.com/dtolnay/prettyplease/releases) - [Commits](https://github.com/dtolnay/prettyplease/compare/0.2.36...0.2.37) --- updated-dependencies: - dependency-name: prettyplease dependency-version: 0.2.37 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 810e0e457..f21ed20ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2618,9 +2618,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.36" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", "syn", diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index 06b7b95b1..25bb65dbf 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -21,6 +21,6 @@ quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } itertools = { version = "0.14.0" } -prettyplease = { version = "0.2.36" } +prettyplease = { version = "0.2.37" } hyperlight-component-util = { workspace = true } env_logger = { version = "0.11.8" } \ No newline at end of file diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index e0e0c33fd..598e495c9 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -20,5 +20,5 @@ quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } itertools = { version = "0.14.0" } -prettyplease = { version = "0.2.36" } +prettyplease = { version = "0.2.37" } log = { version = "0.4" } \ No newline at end of file From 3cca03cf034572a2690d6642e83ee064c2004d3f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 18:04:06 +0000 Subject: [PATCH 114/271] Bump arbitrary from 1.4.1 to 1.4.2 (#793) Bumps [arbitrary](https://github.com/rust-fuzz/arbitrary) from 1.4.1 to 1.4.2. - [Changelog](https://github.com/rust-fuzz/arbitrary/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-fuzz/arbitrary/compare/v1.4.1...v1.4.2) --- updated-dependencies: - dependency-name: arbitrary dependency-version: 1.4.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_common/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f21ed20ce..11b6ec31c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -133,9 +133,9 @@ checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" dependencies = [ "derive_arbitrary", ] diff --git a/src/hyperlight_common/Cargo.toml b/src/hyperlight_common/Cargo.toml index a7a307c73..b74dbb023 100644 --- a/src/hyperlight_common/Cargo.toml +++ b/src/hyperlight_common/Cargo.toml @@ -19,7 +19,7 @@ flatbuffers = { version = "25.2.10", default-features = false } anyhow = { version = "1.0.99", default-features = false } log = "0.4.27" tracing = { version = "0.1.41", optional = true } -arbitrary = {version = "1.4.1", optional = true, features = ["derive"]} +arbitrary = {version = "1.4.2", optional = true, features = ["derive"]} spin = "0.10.0" [features] From 80eb6faab0813457f4541a73b924ed58ebb6eb93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Aug 2025 09:44:36 -0700 Subject: [PATCH 115/271] Bump cfg-if from 1.0.1 to 1.0.3 (#807) Bumps [cfg-if](https://github.com/rust-lang/cfg-if) from 1.0.1 to 1.0.3. - [Release notes](https://github.com/rust-lang/cfg-if/releases) - [Changelog](https://github.com/rust-lang/cfg-if/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cfg-if/compare/v1.0.1...v1.0.3) --- updated-dependencies: - dependency-name: cfg-if dependency-version: 1.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 11b6ec31c..c52156d28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -392,9 +392,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "cfg_aliases" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index cc5bc53c6..0c75b294a 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -25,7 +25,7 @@ gdbstub = { version = "0.7.7", optional = true } gdbstub_arch = { version = "0.3.2", optional = true } goblin = { version = "0.10", default-features = false, features = ["std", "elf32", "elf64", "endian_fd"] } rand = { version = "0.9" } -cfg-if = { version = "1.0.1" } +cfg-if = { version = "1.0.3" } libc = { version = "0.2.175" } flatbuffers = "25.2.10" framehop = { version = "0.15.0", optional = true } From 9dc358b40f60aea7b0b5d5f3ee5a4e8a5b72ff36 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Aug 2025 09:45:36 -0700 Subject: [PATCH 116/271] Bump tempfile from 3.20.0 to 3.21.0 (#809) Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.20.0 to 3.21.0. - [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md) - [Commits](https://github.com/Stebalien/tempfile/commits) --- updated-dependencies: - dependency-name: tempfile dependency-version: 3.21.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c52156d28..c744b28a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3356,15 +3356,15 @@ checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" [[package]] name = "tempfile" -version = "3.20.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 0c75b294a..a9e6717db 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -87,7 +87,7 @@ signal-hook-registry = "1.4.6" envy = { version = "0.4.2" } serde = "1.0" proptest = "1.7.0" -tempfile = "3.20.0" +tempfile = "3.21.0" crossbeam-queue = "0.3.12" tracing-serde = "0.2.0" serial_test = "3.1.1" From e760628486181acd44328080b275604d0c9ebabd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Aug 2025 09:46:06 -0700 Subject: [PATCH 117/271] Bump serde_json from 1.0.142 to 1.0.143 (#808) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.142 to 1.0.143. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.142...v1.0.143) --- updated-dependencies: - dependency-name: serde_json dependency-version: 1.0.143 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c744b28a9..cd7c410c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3117,9 +3117,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.142" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ "itoa", "memchr", From cc0fa1ea61be6922a8a5271ce88d0afdf20aae50 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 04:05:58 +0000 Subject: [PATCH 118/271] Bump thiserror from 2.0.15 to 2.0.16 (#812) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 2.0.15 to 2.0.16. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/2.0.15...2.0.16) --- updated-dependencies: - dependency-name: thiserror dependency-version: 2.0.16 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 30 +++++++++++++++--------------- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd7c410c7..bbadd32e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1482,7 +1482,7 @@ dependencies = [ "signal-hook-registry", "tempfile", "termcolor", - "thiserror 2.0.15", + "thiserror 2.0.16", "tokio", "tracing", "tracing-chrome", @@ -1935,7 +1935,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149" dependencies = [ - "thiserror 2.0.15", + "thiserror 2.0.16", "zerocopy 0.8.26", "zerocopy-derive 0.8.26", ] @@ -1997,7 +1997,7 @@ dependencies = [ "metrics", "metrics-util", "quanta", - "thiserror 2.0.15", + "thiserror 2.0.16", ] [[package]] @@ -2091,7 +2091,7 @@ checksum = "89abe853221fa6f14ad4066affb9abda241a03d65622887d5794e1422d0bd75a" dependencies = [ "libc", "mshv-bindings 0.3.2", - "thiserror 2.0.15", + "thiserror 2.0.16", "vmm-sys-util 0.15.0", ] @@ -2213,7 +2213,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.15", + "thiserror 2.0.16", "tracing", ] @@ -2243,7 +2243,7 @@ dependencies = [ "opentelemetry_sdk", "prost", "reqwest", - "thiserror 2.0.15", + "thiserror 2.0.16", ] [[package]] @@ -2277,7 +2277,7 @@ dependencies = [ "percent-encoding", "rand", "serde_json", - "thiserror 2.0.15", + "thiserror 2.0.16", "tokio", "tokio-stream", ] @@ -2400,7 +2400,7 @@ checksum = "97f6fccfd2d9d2df765ca23ff85fe5cc437fb0e6d3e164e4d3cbe09d14780c93" dependencies = [ "arrayvec", "bitflags 2.9.2", - "thiserror 2.0.15", + "thiserror 2.0.16", "zerocopy 0.8.26", "zerocopy-derive 0.8.26", ] @@ -2840,7 +2840,7 @@ checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.15", + "thiserror 2.0.16", ] [[package]] @@ -3387,11 +3387,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.15" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d76d3f064b981389ecb4b6b7f45a0bf9fdac1d5b9204c7bd6714fecc302850" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ - "thiserror-impl 2.0.15", + "thiserror-impl 2.0.16", ] [[package]] @@ -3407,9 +3407,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.15" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d29feb33e986b6ea906bd9c3559a856983f92371b3eaa5e83782a351623de0" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" dependencies = [ "proc-macro2", "quote", @@ -3656,7 +3656,7 @@ dependencies = [ "chrono", "serde", "smallvec", - "thiserror 2.0.15", + "thiserror 2.0.16", "tracing", "tracing-subscriber", "uuid", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index a9e6717db..bfcbfb145 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -42,7 +42,7 @@ hyperlight-common = { workspace = true, default-features = true, features = [ "s hyperlight-guest-tracing = { workspace = true, default-features = true, optional = true } vmm-sys-util = "0.15.0" crossbeam-channel = "0.5.15" -thiserror = "2.0.15" +thiserror = "2.0.16" chrono = { version = "0.4", optional = true } anyhow = "1.0" metrics = "0.24.2" From 711449191aea164c1622e0a7aaf84953d01a4225 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 23 Aug 2025 04:04:49 +0000 Subject: [PATCH 119/271] Bump wasmparser from 0.236.1 to 0.237.0 (#815) Bumps [wasmparser](https://github.com/bytecodealliance/wasm-tools) from 0.236.1 to 0.237.0. - [Release notes](https://github.com/bytecodealliance/wasm-tools/releases) - [Commits](https://github.com/bytecodealliance/wasm-tools/commits) --- updated-dependencies: - dependency-name: wasmparser dependency-version: 0.237.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bbadd32e8..1280b8e70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4045,9 +4045,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.236.1" +version = "0.237.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9b1e81f3eb254cf7404a82cee6926a4a3ccc5aad80cc3d43608a070c67aa1d7" +checksum = "7d2a40ca0d2bdf4b0bf36c13a737d0b2c58e4c8aaefe1c57f336dd75369ca250" dependencies = [ "bitflags 2.9.2", "hashbrown", diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index 25bb65dbf..3e363022c 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -16,7 +16,7 @@ name = "hyperlight_component_macro" proc-macro = true [dependencies] -wasmparser = { version = "0.236.1" } +wasmparser = { version = "0.237.0" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index 598e495c9..0cad80969 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -15,7 +15,7 @@ Shared implementation for the procedural macros that generate Hyperlight host an name = "hyperlight_component_util" [dependencies] -wasmparser = { version = "0.236.1" } +wasmparser = { version = "0.237.0" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } From 2bcc2ea6b05901dccda106dede32ba63e0efdfff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 09:54:27 -0700 Subject: [PATCH 120/271] Bump bitflags from 2.9.2 to 2.9.3 (#821) Bumps [bitflags](https://github.com/bitflags/bitflags) from 2.9.2 to 2.9.3. - [Release notes](https://github.com/bitflags/bitflags/releases) - [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md) - [Commits](https://github.com/bitflags/bitflags/compare/2.9.2...2.9.3) --- updated-dependencies: - dependency-name: bitflags dependency-version: 2.9.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 44 +++++++++++++++++----------------- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1280b8e70..cb3b65836 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -202,7 +202,7 @@ version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "cexpr", "clang-sys", "itertools 0.13.0", @@ -239,9 +239,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.2" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" +checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" [[package]] name = "blake3" @@ -318,7 +318,7 @@ version = "0.20.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e3bd0f4e25afa9cabc157908d14eeef9067d6448c49414d17b3fb55f0eadd0" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "cairo-sys-rs", "glib", "libc", @@ -515,7 +515,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "core-foundation", "core-graphics-types", "foreign-types", @@ -528,7 +528,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "core-foundation", "libc", ] @@ -839,7 +839,7 @@ version = "25.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1045398c1bfd89168b5fd3f1fc11f6e70b34f6f66300c87d44d3de849463abf1" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "rustc_version", ] @@ -1010,7 +1010,7 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b686b198dfaa4109ebd0443d2841bc521e4b4b2915f1d84b3bb50332a8cdc1ae" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "cfg-if", "log", "managed", @@ -1127,7 +1127,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "libc", "libgit2-sys", "log", @@ -1140,7 +1140,7 @@ version = "0.20.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffc4b6e352d4716d84d7dde562dd9aee2a7d48beb872dd9ece7f2d1515b2d683" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "futures-channel", "futures-core", "futures-executor", @@ -1431,7 +1431,7 @@ name = "hyperlight-host" version = "0.8.0" dependencies = [ "anyhow", - "bitflags 2.9.2", + "bitflags 2.9.3", "blake3", "built", "cfg-if", @@ -1675,7 +1675,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "cfg-if", "libc", ] @@ -1796,7 +1796,7 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e00243d27a20feb05cf001ae52ddc79831ac70c020f215ba1153ff9270b650a" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "kvm-bindings", "libc", "vmm-sys-util 0.14.0", @@ -1863,7 +1863,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "libc", ] @@ -2399,7 +2399,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97f6fccfd2d9d2df765ca23ff85fe5cc437fb0e6d3e164e4d3cbe09d14780c93" dependencies = [ "arrayvec", - "bitflags 2.9.2", + "bitflags 2.9.3", "thiserror 2.0.16", "zerocopy 0.8.26", "zerocopy-derive 0.8.26", @@ -2666,7 +2666,7 @@ checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.9.2", + "bitflags 2.9.3", "lazy_static", "num-traits", "rand", @@ -2800,7 +2800,7 @@ version = "11.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", ] [[package]] @@ -2829,7 +2829,7 @@ version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", ] [[package]] @@ -2984,7 +2984,7 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "errno", "libc", "linux-raw-sys", @@ -3570,7 +3570,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "bytes", "futures-util", "http", @@ -4049,7 +4049,7 @@ version = "0.237.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d2a40ca0d2bdf4b0bf36c13a737d0b2c58e4c8aaefe1c57f336dd75369ca250" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "hashbrown", "indexmap", "semver", @@ -4406,7 +4406,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", ] [[package]] diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index bfcbfb145..94c26e369 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -33,7 +33,7 @@ fallible-iterator = { version = "0.3.0", optional = true } blake3 = "1.8.2" page_size = "0.6.0" termcolor = "1.2.0" -bitflags = "2.9.2" +bitflags = "2.9.3" log = "0.4.27" tracing = { version = "0.1.41", features = ["log"] } tracing-log = "0.2.0" From 00d620be4dd6fed9d26b29bceb37eb4f1adf6b56 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 11:33:26 -0700 Subject: [PATCH 121/271] Bump cc from 1.2.33 to 1.2.34 (#820) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.33 to 1.2.34. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.33...cc-v1.2.34) --- updated-dependencies: - dependency-name: cc dependency-version: 1.2.34 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cb3b65836..7ae85a17d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,9 +362,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.33" +version = "1.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f" +checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" dependencies = [ "jobserver", "libc", From 85b45106f41089410fe3a18ae370198375bec53b Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Mon, 25 Aug 2025 12:20:41 -0700 Subject: [PATCH 122/271] Optimize function call serializing (#778) * Add FunctionCall serialization benchmarks and a c+rust sample workload benchmark Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Avoid intermediary iterator for vecbytes parametervalue Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Add util for estimating capacity needed for flatbuffer-encoding functioncall Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Make serializing a FunctionCall return a &[u8] instead of Vec. This should save memory allocations, but require that a FlatBufferBuilder is passed in. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * pr feedback: permalink in comment Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Add some notes about not reusing builder after calling FunctionCall::encode Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --------- Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- Cargo.lock | 1 + .../src/flatbuffer_wrappers/function_call.rs | 266 ++++++------- .../src/flatbuffer_wrappers/function_types.rs | 2 +- .../src/flatbuffer_wrappers/util.rs | 348 ++++++++++++++++++ src/hyperlight_guest/Cargo.toml | 1 + .../src/guest_handle/host_comm.rs | 14 +- src/hyperlight_guest/src/guest_handle/io.rs | 5 +- .../src/guest_function/call.rs | 2 +- src/hyperlight_host/benches/benchmarks.rs | 90 ++++- .../src/sandbox/initialized_multi_use.rs | 13 +- src/tests/c_guests/c_simpleguest/main.c | 11 + .../rust_guests/callbackguest/Cargo.lock | 1 + src/tests/rust_guests/dummyguest/Cargo.lock | 1 + src/tests/rust_guests/simpleguest/Cargo.lock | 1 + src/tests/rust_guests/simpleguest/src/main.rs | 21 ++ src/tests/rust_guests/witguest/Cargo.lock | 1 + 16 files changed, 617 insertions(+), 161 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ae85a17d..751c2a3bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1388,6 +1388,7 @@ name = "hyperlight-guest" version = "0.8.0" dependencies = [ "anyhow", + "flatbuffers", "hyperlight-common", "hyperlight-guest-tracing", "serde_json", diff --git a/src/hyperlight_common/src/flatbuffer_wrappers/function_call.rs b/src/hyperlight_common/src/flatbuffer_wrappers/function_call.rs index 67998fbbe..056ced8e0 100644 --- a/src/hyperlight_common/src/flatbuffer_wrappers/function_call.rs +++ b/src/hyperlight_common/src/flatbuffer_wrappers/function_call.rs @@ -18,7 +18,7 @@ use alloc::string::{String, ToString}; use alloc::vec::Vec; use anyhow::{Error, Result, bail}; -use flatbuffers::{WIPOffset, size_prefixed_root}; +use flatbuffers::{FlatBufferBuilder, WIPOffset, size_prefixed_root}; #[cfg(feature = "tracing")] use tracing::{Span, instrument}; @@ -72,214 +72,136 @@ impl FunctionCall { pub fn function_call_type(&self) -> FunctionCallType { self.function_call_type.clone() } -} - -#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))] -pub fn validate_guest_function_call_buffer(function_call_buffer: &[u8]) -> Result<()> { - let guest_function_call_fb = size_prefixed_root::(function_call_buffer) - .map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?; - match guest_function_call_fb.function_call_type() { - FbFunctionCallType::guest => Ok(()), - other => { - bail!("Invalid function call type: {:?}", other); - } - } -} - -#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))] -pub fn validate_host_function_call_buffer(function_call_buffer: &[u8]) -> Result<()> { - let host_function_call_fb = size_prefixed_root::(function_call_buffer) - .map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?; - match host_function_call_fb.function_call_type() { - FbFunctionCallType::host => Ok(()), - other => { - bail!("Invalid function call type: {:?}", other); - } - } -} - -impl TryFrom<&[u8]> for FunctionCall { - type Error = Error; - #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))] - fn try_from(value: &[u8]) -> Result { - let function_call_fb = size_prefixed_root::(value) - .map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?; - let function_name = function_call_fb.function_name(); - let function_call_type = match function_call_fb.function_call_type() { - FbFunctionCallType::guest => FunctionCallType::Guest, - FbFunctionCallType::host => FunctionCallType::Host, - other => { - bail!("Invalid function call type: {:?}", other); - } - }; - let expected_return_type = function_call_fb.expected_return_type().try_into()?; - let parameters = function_call_fb - .parameters() - .map(|v| { - v.iter() - .map(|p| p.try_into()) - .collect::>>() - }) - .transpose()?; + /// Encodes self into the given builder and returns the encoded data. + /// + /// # Notes + /// + /// The builder should not be reused after a call to encode, since this function + /// does not reset the state of the builder. If you want to reuse the builder, + /// you'll need to reset it first. + pub fn encode<'a>(&self, builder: &'a mut FlatBufferBuilder) -> &'a [u8] { + let function_name = builder.create_string(&self.function_name); - Ok(Self { - function_name: function_name.to_string(), - parameters, - function_call_type, - expected_return_type, - }) - } -} - -impl TryFrom for Vec { - type Error = Error; - #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))] - fn try_from(value: FunctionCall) -> Result> { - let mut builder = flatbuffers::FlatBufferBuilder::new(); - let function_name = builder.create_string(&value.function_name); - - let function_call_type = match value.function_call_type { + let function_call_type = match self.function_call_type { FunctionCallType::Guest => FbFunctionCallType::guest, FunctionCallType::Host => FbFunctionCallType::host, }; - let expected_return_type = value.expected_return_type.into(); - - let parameters = match &value.parameters { - Some(p) => { - let num_items = p.len(); - let mut parameters: Vec> = Vec::with_capacity(num_items); + let expected_return_type = self.expected_return_type.into(); - for param in p { - match param { + let parameters = match &self.parameters { + Some(p) if !p.is_empty() => { + let parameter_offsets: Vec> = p + .iter() + .map(|param| match param { ParameterValue::Int(i) => { - let hlint = hlint::create(&mut builder, &hlintArgs { value: *i }); - let parameter = Parameter::create( - &mut builder, + let hlint = hlint::create(builder, &hlintArgs { value: *i }); + Parameter::create( + builder, &ParameterArgs { value_type: FbParameterValue::hlint, value: Some(hlint.as_union_value()), }, - ); - parameters.push(parameter); + ) } ParameterValue::UInt(ui) => { - let hluint = hluint::create(&mut builder, &hluintArgs { value: *ui }); - let parameter = Parameter::create( - &mut builder, + let hluint = hluint::create(builder, &hluintArgs { value: *ui }); + Parameter::create( + builder, &ParameterArgs { value_type: FbParameterValue::hluint, value: Some(hluint.as_union_value()), }, - ); - parameters.push(parameter); + ) } ParameterValue::Long(l) => { - let hllong = hllong::create(&mut builder, &hllongArgs { value: *l }); - let parameter = Parameter::create( - &mut builder, + let hllong = hllong::create(builder, &hllongArgs { value: *l }); + Parameter::create( + builder, &ParameterArgs { value_type: FbParameterValue::hllong, value: Some(hllong.as_union_value()), }, - ); - parameters.push(parameter); + ) } ParameterValue::ULong(ul) => { - let hlulong = - hlulong::create(&mut builder, &hlulongArgs { value: *ul }); - let parameter = Parameter::create( - &mut builder, + let hlulong = hlulong::create(builder, &hlulongArgs { value: *ul }); + Parameter::create( + builder, &ParameterArgs { value_type: FbParameterValue::hlulong, value: Some(hlulong.as_union_value()), }, - ); - parameters.push(parameter); + ) } ParameterValue::Float(f) => { - let hlfloat = hlfloat::create(&mut builder, &hlfloatArgs { value: *f }); - let parameter = Parameter::create( - &mut builder, + let hlfloat = hlfloat::create(builder, &hlfloatArgs { value: *f }); + Parameter::create( + builder, &ParameterArgs { value_type: FbParameterValue::hlfloat, value: Some(hlfloat.as_union_value()), }, - ); - parameters.push(parameter); + ) } ParameterValue::Double(d) => { - let hldouble = - hldouble::create(&mut builder, &hldoubleArgs { value: *d }); - let parameter = Parameter::create( - &mut builder, + let hldouble = hldouble::create(builder, &hldoubleArgs { value: *d }); + Parameter::create( + builder, &ParameterArgs { value_type: FbParameterValue::hldouble, value: Some(hldouble.as_union_value()), }, - ); - parameters.push(parameter); + ) } ParameterValue::Bool(b) => { - let hlbool: WIPOffset> = - hlbool::create(&mut builder, &hlboolArgs { value: *b }); - let parameter = Parameter::create( - &mut builder, + let hlbool = hlbool::create(builder, &hlboolArgs { value: *b }); + Parameter::create( + builder, &ParameterArgs { value_type: FbParameterValue::hlbool, value: Some(hlbool.as_union_value()), }, - ); - parameters.push(parameter); + ) } ParameterValue::String(s) => { - let hlstring = { - let val = builder.create_string(s.as_str()); - hlstring::create(&mut builder, &hlstringArgs { value: Some(val) }) - }; - let parameter = Parameter::create( - &mut builder, + let val = builder.create_string(s.as_str()); + let hlstring = + hlstring::create(builder, &hlstringArgs { value: Some(val) }); + Parameter::create( + builder, &ParameterArgs { value_type: FbParameterValue::hlstring, value: Some(hlstring.as_union_value()), }, - ); - parameters.push(parameter); + ) } ParameterValue::VecBytes(v) => { let vec_bytes = builder.create_vector(v); - let hlvecbytes = hlvecbytes::create( - &mut builder, + builder, &hlvecbytesArgs { value: Some(vec_bytes), }, ); - let parameter = Parameter::create( - &mut builder, + Parameter::create( + builder, &ParameterArgs { value_type: FbParameterValue::hlvecbytes, value: Some(hlvecbytes.as_union_value()), }, - ); - parameters.push(parameter); + ) } - } - } - parameters + }) + .collect(); + Some(builder.create_vector(¶meter_offsets)) } - None => Vec::new(), - }; - - let parameters = if !parameters.is_empty() { - Some(builder.create_vector(¶meters)) - } else { - None + _ => None, }; let function_call = FbFunctionCall::create( - &mut builder, + builder, &FbFunctionCallArgs { function_name: Some(function_name), parameters, @@ -288,9 +210,65 @@ impl TryFrom for Vec { }, ); builder.finish_size_prefixed(function_call, None); - let res = builder.finished_data().to_vec(); + builder.finished_data() + } +} - Ok(res) +#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))] +pub fn validate_guest_function_call_buffer(function_call_buffer: &[u8]) -> Result<()> { + let guest_function_call_fb = size_prefixed_root::(function_call_buffer) + .map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?; + match guest_function_call_fb.function_call_type() { + FbFunctionCallType::guest => Ok(()), + other => { + bail!("Invalid function call type: {:?}", other); + } + } +} + +#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))] +pub fn validate_host_function_call_buffer(function_call_buffer: &[u8]) -> Result<()> { + let host_function_call_fb = size_prefixed_root::(function_call_buffer) + .map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?; + match host_function_call_fb.function_call_type() { + FbFunctionCallType::host => Ok(()), + other => { + bail!("Invalid function call type: {:?}", other); + } + } +} + +impl TryFrom<&[u8]> for FunctionCall { + type Error = Error; + #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))] + fn try_from(value: &[u8]) -> Result { + let function_call_fb = size_prefixed_root::(value) + .map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?; + let function_name = function_call_fb.function_name(); + let function_call_type = match function_call_fb.function_call_type() { + FbFunctionCallType::guest => FunctionCallType::Guest, + FbFunctionCallType::host => FunctionCallType::Host, + other => { + bail!("Invalid function call type: {:?}", other); + } + }; + let expected_return_type = function_call_fb.expected_return_type().try_into()?; + + let parameters = function_call_fb + .parameters() + .map(|v| { + v.iter() + .map(|p| p.try_into()) + .collect::>>() + }) + .transpose()?; + + Ok(Self { + function_name: function_name.to_string(), + parameters, + function_call_type, + expected_return_type, + }) } } @@ -303,7 +281,8 @@ mod tests { #[test] fn read_from_flatbuffer() -> Result<()> { - let test_data: Vec = FunctionCall::new( + let mut builder = FlatBufferBuilder::new(); + let test_data = FunctionCall::new( "PrintTwelveArgs".to_string(), Some(vec![ ParameterValue::String("1".to_string()), @@ -322,10 +301,9 @@ mod tests { FunctionCallType::Guest, ReturnType::Int, ) - .try_into() - .unwrap(); + .encode(&mut builder); - let function_call = FunctionCall::try_from(test_data.as_slice())?; + let function_call = FunctionCall::try_from(test_data)?; assert_eq!(function_call.function_name, "PrintTwelveArgs"); assert!(function_call.parameters.is_some()); let parameters = function_call.parameters.unwrap(); diff --git a/src/hyperlight_common/src/flatbuffer_wrappers/function_types.rs b/src/hyperlight_common/src/flatbuffer_wrappers/function_types.rs index b381da592..16bd91bc0 100644 --- a/src/hyperlight_common/src/flatbuffer_wrappers/function_types.rs +++ b/src/hyperlight_common/src/flatbuffer_wrappers/function_types.rs @@ -181,7 +181,7 @@ impl TryFrom> for ParameterValue { ParameterValue::String(hlstring.value().unwrap_or_default().to_string()) }), FbParameterValue::hlvecbytes => param.value_as_hlvecbytes().map(|hlvecbytes| { - ParameterValue::VecBytes(hlvecbytes.value().unwrap_or_default().iter().collect()) + ParameterValue::VecBytes(hlvecbytes.value().unwrap_or_default().bytes().to_vec()) }), other => { bail!("Unexpected flatbuffer parameter value type: {:?}", other); diff --git a/src/hyperlight_common/src/flatbuffer_wrappers/util.rs b/src/hyperlight_common/src/flatbuffer_wrappers/util.rs index ba3645b94..96ab16f1e 100644 --- a/src/hyperlight_common/src/flatbuffer_wrappers/util.rs +++ b/src/hyperlight_common/src/flatbuffer_wrappers/util.rs @@ -18,6 +18,7 @@ use alloc::vec::Vec; use flatbuffers::FlatBufferBuilder; +use crate::flatbuffer_wrappers::function_types::ParameterValue; use crate::flatbuffers::hyperlight::generated::{ FunctionCallResult as FbFunctionCallResult, FunctionCallResultArgs as FbFunctionCallResultArgs, ReturnValue as FbReturnValue, hlbool as Fbhlbool, hlboolArgs as FbhlboolArgs, @@ -169,3 +170,350 @@ impl FlatbufferSerializable for bool { } } } + +/// Estimates the required buffer capacity for encoding a FunctionCall with the given parameters. +/// This helps avoid reallocation during FlatBuffer encoding when passing large slices and strings. +/// +/// The function aims to be lightweight and fast and run in O(1) as long as the number of parameters is limited +/// (which it is since hyperlight only currently supports up to 12). +/// +/// Note: This estimates the capacity needed for the inner vec inside a FlatBufferBuilder. It does not +/// necessarily match the size of the final encoded buffer. The estimation always rounds up to the +/// nearest power of two to match FlatBufferBuilder's allocation strategy. +/// +/// The estimations are numbers used are empirically derived based on the tests below and vaguely based +/// on https://flatbuffers.dev/internals/ and https://github.com/dvidelabs/flatcc/blob/f064cefb2034d1e7407407ce32a6085c322212a7/doc/binary-format.md#flatbuffers-binary-format +#[inline] // allow cross-crate inlining (for hyperlight-host calls) +pub fn estimate_flatbuffer_capacity(function_name: &str, args: &[ParameterValue]) -> usize { + let mut estimated_capacity = 20; + + // Function name overhead + estimated_capacity += function_name.len() + 12; + + // Parameters vector overhead + estimated_capacity += 12 + args.len() * 6; + + // Per-parameter overhead + for arg in args { + estimated_capacity += 16; // Base parameter structure + estimated_capacity += match arg { + ParameterValue::String(s) => s.len() + 20, + ParameterValue::VecBytes(v) => v.len() + 20, + ParameterValue::Int(_) | ParameterValue::UInt(_) => 16, + ParameterValue::Long(_) | ParameterValue::ULong(_) => 20, + ParameterValue::Float(_) => 16, + ParameterValue::Double(_) => 20, + ParameterValue::Bool(_) => 12, + }; + } + + // match how vec grows + estimated_capacity.next_power_of_two() +} + +#[cfg(test)] +mod tests { + use alloc::string::ToString; + use alloc::vec; + use alloc::vec::Vec; + + use super::*; + use crate::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType}; + use crate::flatbuffer_wrappers::function_types::{ParameterValue, ReturnType}; + + /// Helper function to check that estimation is within reasonable bounds (±25%) + fn assert_estimation_accuracy( + function_name: &str, + args: Vec, + call_type: FunctionCallType, + return_type: ReturnType, + ) { + let estimated = estimate_flatbuffer_capacity(function_name, &args); + + let fc = FunctionCall::new( + function_name.to_string(), + Some(args), + call_type.clone(), + return_type, + ); + // Important that this FlatBufferBuilder is created with capacity 0 so it grows to its needed capacity + let mut builder = FlatBufferBuilder::new(); + let _buffer = fc.encode(&mut builder); + let actual = builder.collapse().0.capacity(); + + let lower_bound = (actual as f64 * 0.75) as usize; + let upper_bound = (actual as f64 * 1.25) as usize; + + assert!( + estimated >= lower_bound && estimated <= upper_bound, + "Estimation {} outside bounds [{}, {}] for actual size {} (function: {}, call_type: {:?}, return_type: {:?})", + estimated, + lower_bound, + upper_bound, + actual, + function_name, + call_type, + return_type + ); + } + + #[test] + fn test_estimate_no_parameters() { + assert_estimation_accuracy( + "simple_function", + vec![], + FunctionCallType::Guest, + ReturnType::Void, + ); + } + + #[test] + fn test_estimate_single_int_parameter() { + assert_estimation_accuracy( + "add_one", + vec![ParameterValue::Int(42)], + FunctionCallType::Guest, + ReturnType::Int, + ); + } + + #[test] + fn test_estimate_multiple_scalar_parameters() { + assert_estimation_accuracy( + "calculate", + vec![ + ParameterValue::Int(10), + ParameterValue::UInt(20), + ParameterValue::Long(30), + ParameterValue::ULong(40), + ParameterValue::Float(1.5), + ParameterValue::Double(2.5), + ParameterValue::Bool(true), + ], + FunctionCallType::Guest, + ReturnType::Double, + ); + } + + #[test] + fn test_estimate_string_parameters() { + assert_estimation_accuracy( + "process_strings", + vec![ + ParameterValue::String("hello".to_string()), + ParameterValue::String("world".to_string()), + ParameterValue::String("this is a longer string for testing".to_string()), + ], + FunctionCallType::Host, + ReturnType::String, + ); + } + + #[test] + fn test_estimate_very_long_string() { + let long_string = "a".repeat(1000); + assert_estimation_accuracy( + "process_long_string", + vec![ParameterValue::String(long_string)], + FunctionCallType::Guest, + ReturnType::String, + ); + } + + #[test] + fn test_estimate_vector_parameters() { + assert_estimation_accuracy( + "process_vectors", + vec![ + ParameterValue::VecBytes(vec![1, 2, 3, 4, 5]), + ParameterValue::VecBytes(vec![]), + ParameterValue::VecBytes(vec![0; 100]), + ], + FunctionCallType::Host, + ReturnType::VecBytes, + ); + } + + #[test] + fn test_estimate_mixed_parameters() { + assert_estimation_accuracy( + "complex_function", + vec![ + ParameterValue::String("test".to_string()), + ParameterValue::Int(42), + ParameterValue::VecBytes(vec![1, 2, 3, 4, 5]), + ParameterValue::Bool(true), + ParameterValue::Double(553.14159), + ParameterValue::String("another string".to_string()), + ParameterValue::Long(9223372036854775807), + ], + FunctionCallType::Guest, + ReturnType::VecBytes, + ); + } + + #[test] + fn test_estimate_large_function_name() { + let long_name = "very_long_function_name_that_exceeds_normal_lengths_for_testing_purposes"; + assert_estimation_accuracy( + long_name, + vec![ParameterValue::Int(1)], + FunctionCallType::Host, + ReturnType::Long, + ); + } + + #[test] + fn test_estimate_large_vector() { + let large_vector = vec![42u8; 10000]; + assert_estimation_accuracy( + "process_large_data", + vec![ParameterValue::VecBytes(large_vector)], + FunctionCallType::Guest, + ReturnType::Bool, + ); + } + + #[test] + fn test_estimate_all_parameter_types() { + assert_estimation_accuracy( + "comprehensive_test", + vec![ + ParameterValue::Int(i32::MIN), + ParameterValue::UInt(u32::MAX), + ParameterValue::Long(i64::MIN), + ParameterValue::ULong(u64::MAX), + ParameterValue::Float(f32::MIN), + ParameterValue::Double(f64::MAX), + ParameterValue::Bool(false), + ParameterValue::String("test string".to_string()), + ParameterValue::VecBytes(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + ], + FunctionCallType::Host, + ReturnType::ULong, + ); + } + + #[test] + fn test_different_function_call_types() { + assert_estimation_accuracy( + "guest_function", + vec![ParameterValue::String("guest call".to_string())], + FunctionCallType::Guest, + ReturnType::String, + ); + + assert_estimation_accuracy( + "host_function", + vec![ParameterValue::String("host call".to_string())], + FunctionCallType::Host, + ReturnType::String, + ); + } + + #[test] + fn test_different_return_types() { + let args = vec![ + ParameterValue::Int(42), + ParameterValue::String("test".to_string()), + ]; + + let void_est = estimate_flatbuffer_capacity("test_void", &args); + let int_est = estimate_flatbuffer_capacity("test_int", &args); + let string_est = estimate_flatbuffer_capacity("test_string", &args); + + assert!((void_est as i32 - int_est as i32).abs() < 10); + assert!((int_est as i32 - string_est as i32).abs() < 10); + + assert_estimation_accuracy( + "test_void", + args.clone(), + FunctionCallType::Guest, + ReturnType::Void, + ); + assert_estimation_accuracy( + "test_int", + args.clone(), + FunctionCallType::Guest, + ReturnType::Int, + ); + assert_estimation_accuracy( + "test_string", + args, + FunctionCallType::Guest, + ReturnType::String, + ); + } + + #[test] + fn test_estimate_many_large_vectors_and_strings() { + assert_estimation_accuracy( + "process_bulk_data", + vec![ + ParameterValue::String("Large string data: ".to_string() + &"x".repeat(2000)), + ParameterValue::VecBytes(vec![1u8; 5000]), + ParameterValue::String( + "Another large string with lots of content ".to_string() + &"y".repeat(3000), + ), + ParameterValue::VecBytes(vec![255u8; 7500]), + ParameterValue::String( + "Third massive string parameter ".to_string() + &"z".repeat(1500), + ), + ParameterValue::VecBytes(vec![128u8; 10000]), + ParameterValue::Int(42), + ParameterValue::String("Final large string ".to_string() + &"a".repeat(4000)), + ParameterValue::VecBytes(vec![64u8; 2500]), + ParameterValue::Bool(true), + ], + FunctionCallType::Host, + ReturnType::VecBytes, + ); + } + + #[test] + fn test_estimate_twenty_parameters() { + assert_estimation_accuracy( + "function_with_many_parameters", + vec![ + ParameterValue::Int(1), + ParameterValue::String("param2".to_string()), + ParameterValue::Bool(true), + ParameterValue::Float(3213.14), + ParameterValue::VecBytes(vec![1, 2, 3]), + ParameterValue::Long(1000000), + ParameterValue::Double(322.718), + ParameterValue::UInt(42), + ParameterValue::String("param9".to_string()), + ParameterValue::Bool(false), + ParameterValue::ULong(9999999999), + ParameterValue::VecBytes(vec![4, 5, 6, 7, 8]), + ParameterValue::Int(-100), + ParameterValue::Float(1.414), + ParameterValue::String("param15".to_string()), + ParameterValue::Double(1.732), + ParameterValue::Bool(true), + ParameterValue::VecBytes(vec![9, 10]), + ParameterValue::Long(-5000000), + ParameterValue::UInt(12345), + ], + FunctionCallType::Guest, + ReturnType::Int, + ); + } + + #[test] + fn test_estimate_megabyte_parameters() { + assert_estimation_accuracy( + "process_megabyte_data", + vec![ + ParameterValue::String("MB String 1: ".to_string() + &"x".repeat(1_048_576)), // 1MB string + ParameterValue::VecBytes(vec![42u8; 2_097_152]), // 2MB vector + ParameterValue::String("MB String 2: ".to_string() + &"y".repeat(1_572_864)), // 1.5MB string + ParameterValue::VecBytes(vec![128u8; 3_145_728]), // 3MB vector + ParameterValue::String("MB String 3: ".to_string() + &"z".repeat(2_097_152)), // 2MB string + ], + FunctionCallType::Host, + ReturnType::VecBytes, + ); + } +} diff --git a/src/hyperlight_guest/Cargo.toml b/src/hyperlight_guest/Cargo.toml index 73a669862..ecc516241 100644 --- a/src/hyperlight_guest/Cargo.toml +++ b/src/hyperlight_guest/Cargo.toml @@ -16,6 +16,7 @@ anyhow = { version = "1.0.99", default-features = false } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } hyperlight-common = { workspace = true } hyperlight-guest-tracing = { workspace = true, default-features = false } +flatbuffers = { version= "25.2.10", default-features = false } [features] default = [] diff --git a/src/hyperlight_guest/src/guest_handle/host_comm.rs b/src/hyperlight_guest/src/guest_handle/host_comm.rs index 5719417ab..17b5300e5 100644 --- a/src/hyperlight_guest/src/guest_handle/host_comm.rs +++ b/src/hyperlight_guest/src/guest_handle/host_comm.rs @@ -19,6 +19,7 @@ use alloc::string::ToString; use alloc::vec::Vec; use core::slice::from_raw_parts; +use flatbuffers::FlatBufferBuilder; use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType}; use hyperlight_common::flatbuffer_wrappers::function_types::{ ParameterValue, ReturnType, ReturnValue, @@ -27,6 +28,7 @@ use hyperlight_common::flatbuffer_wrappers::guest_error::{ErrorCode, GuestError} use hyperlight_common::flatbuffer_wrappers::guest_log_data::GuestLogData; use hyperlight_common::flatbuffer_wrappers::guest_log_level::LogLevel; use hyperlight_common::flatbuffer_wrappers::host_function_details::HostFunctionDetails; +use hyperlight_common::flatbuffer_wrappers::util::estimate_flatbuffer_capacity; use hyperlight_common::outb::OutBAction; use super::handle::GuestHandle; @@ -92,6 +94,9 @@ impl GuestHandle { parameters: Option>, return_type: ReturnType, ) -> Result<()> { + let estimated_capacity = + estimate_flatbuffer_capacity(function_name, parameters.as_deref().unwrap_or(&[])); + let host_function_call = FunctionCall::new( function_name.to_string(), parameters, @@ -99,10 +104,9 @@ impl GuestHandle { return_type, ); - let host_function_call_buffer: Vec = host_function_call - .try_into() - .expect("Unable to serialize host function call"); + let mut builder = FlatBufferBuilder::with_capacity(estimated_capacity); + let host_function_call_buffer = host_function_call.encode(&mut builder); self.push_shared_output_data(host_function_call_buffer)?; unsafe { @@ -155,7 +159,7 @@ impl GuestHandle { .try_into() .expect("Invalid guest_error_buffer, could not be converted to a Vec"); - if let Err(e) = self.push_shared_output_data(guest_error_buffer) { + if let Err(e) = self.push_shared_output_data(&guest_error_buffer) { panic!("Unable to push guest error to shared output data: {:#?}", e); } } @@ -184,7 +188,7 @@ impl GuestHandle { .try_into() .expect("Failed to convert GuestLogData to bytes"); - self.push_shared_output_data(bytes) + self.push_shared_output_data(&bytes) .expect("Unable to push log data to shared output data"); unsafe { diff --git a/src/hyperlight_guest/src/guest_handle/io.rs b/src/hyperlight_guest/src/guest_handle/io.rs index 759c88880..d8219b270 100644 --- a/src/hyperlight_guest/src/guest_handle/io.rs +++ b/src/hyperlight_guest/src/guest_handle/io.rs @@ -16,7 +16,6 @@ limitations under the License. use alloc::format; use alloc::string::ToString; -use alloc::vec::Vec; use core::any::type_name; use core::slice::from_raw_parts_mut; @@ -93,7 +92,7 @@ impl GuestHandle { /// Pushes the given data onto the shared output data buffer. #[hyperlight_guest_tracing::trace_function] - pub fn push_shared_output_data(&self, data: Vec) -> Result<()> { + pub fn push_shared_output_data(&self, data: &[u8]) -> Result<()> { let peb_ptr = self.peb().unwrap(); let output_stack_size = unsafe { (*peb_ptr).output_stack.size as usize }; let output_stack_ptr = unsafe { (*peb_ptr).output_stack.ptr as *mut u8 }; @@ -139,7 +138,7 @@ impl GuestHandle { // write the actual data hyperlight_guest_tracing::trace!("copy data", { - odb[stack_ptr_rel as usize..stack_ptr_rel as usize + data.len()].copy_from_slice(&data); + odb[stack_ptr_rel as usize..stack_ptr_rel as usize + data.len()].copy_from_slice(data); }); // write the offset to the newly written data, to the top of the stack diff --git a/src/hyperlight_guest_bin/src/guest_function/call.rs b/src/hyperlight_guest_bin/src/guest_function/call.rs index 3d55a9f5e..7eabdeb29 100644 --- a/src/hyperlight_guest_bin/src/guest_function/call.rs +++ b/src/hyperlight_guest_bin/src/guest_function/call.rs @@ -98,7 +98,7 @@ fn internal_dispatch_function() -> Result<()> { handle.write_error(e.kind, Some(e.message.as_str())); })?; - handle.push_shared_output_data(result_vec) + handle.push_shared_output_data(&result_vec) } // This is implemented as a separate function to make sure that epilogue in the internal_dispatch_function is called before the halt() diff --git a/src/hyperlight_host/benches/benchmarks.rs b/src/hyperlight_host/benches/benchmarks.rs index 4896d9e14..3ed91820f 100644 --- a/src/hyperlight_host/benches/benchmarks.rs +++ b/src/hyperlight_host/benches/benchmarks.rs @@ -15,9 +15,13 @@ limitations under the License. */ use criterion::{Criterion, criterion_group, criterion_main}; +use flatbuffers::FlatBufferBuilder; +use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType}; +use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnType}; +use hyperlight_common::flatbuffer_wrappers::util::estimate_flatbuffer_capacity; use hyperlight_host::GuestBinary; use hyperlight_host::sandbox::{MultiUseSandbox, SandboxConfiguration, UninitializedSandbox}; -use hyperlight_testing::simple_guest_as_string; +use hyperlight_testing::{c_simple_guest_as_string, simple_guest_as_string}; fn create_uninit_sandbox() -> UninitializedSandbox { let path = simple_guest_as_string().unwrap(); @@ -133,9 +137,91 @@ fn sandbox_benchmark(c: &mut Criterion) { group.finish(); } +fn function_call_serialization_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("function_call_serialization"); + + let function_call = FunctionCall::new( + "TestFunction".to_string(), + Some(vec![ + ParameterValue::VecBytes(vec![1; 10 * 1024 * 1024]), + ParameterValue::String(String::from_utf8(vec![2; 10 * 1024 * 1024]).unwrap()), + ParameterValue::Int(42), + ParameterValue::UInt(100), + ParameterValue::Long(1000), + ParameterValue::ULong(2000), + ParameterValue::Float(521521.53), + ParameterValue::Double(432.53), + ParameterValue::Bool(true), + ParameterValue::VecBytes(vec![1; 10 * 1024 * 1024]), + ParameterValue::String(String::from_utf8(vec![2; 10 * 1024 * 1024]).unwrap()), + ]), + FunctionCallType::Guest, + ReturnType::Int, + ); + + group.bench_function("serialize_function_call", |b| { + b.iter(|| { + // We specifically want to include the time to estimate the capacity in this benchmark + let estimated_capacity = estimate_flatbuffer_capacity( + function_call.function_name.as_str(), + function_call.parameters.as_deref().unwrap_or(&[]), + ); + let mut builder = FlatBufferBuilder::with_capacity(estimated_capacity); + let serialized: &[u8] = function_call.encode(&mut builder); + std::hint::black_box(serialized); + }); + }); + + group.bench_function("deserialize_function_call", |b| { + let mut builder = FlatBufferBuilder::new(); + let bytes = function_call.clone().encode(&mut builder); + + b.iter(|| { + let deserialized: FunctionCall = bytes.try_into().unwrap(); + std::hint::black_box(deserialized); + }); + }); + + group.finish(); +} + +#[allow(clippy::disallowed_macros)] +fn sample_workloads_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("sample_workloads"); + + fn bench_24k_in_8k_out(b: &mut criterion::Bencher, guest_path: String) { + let mut cfg = SandboxConfiguration::default(); + cfg.set_input_data_size(25 * 1024); + + let mut sandbox = UninitializedSandbox::new(GuestBinary::FilePath(guest_path), Some(cfg)) + .unwrap() + .evolve() + .unwrap(); + + b.iter_with_setup( + || vec![1; 24 * 1024], + |input| { + let ret: Vec = sandbox.call("24K_in_8K_out", (input,)).unwrap(); + assert_eq!(ret.len(), 8 * 1024, "Expected output length to be 8K"); + std::hint::black_box(ret); + }, + ); + } + + group.bench_function("24K_in_8K_out_c", |b| { + bench_24k_in_8k_out(b, c_simple_guest_as_string().unwrap()); + }); + + group.bench_function("24K_in_8K_out_rust", |b| { + bench_24k_in_8k_out(b, simple_guest_as_string().unwrap()); + }); + + group.finish(); +} + criterion_group! { name = benches; config = Criterion::default(); - targets = guest_call_benchmark, sandbox_benchmark, guest_call_benchmark_large_param + targets = guest_call_benchmark, sandbox_benchmark, guest_call_benchmark_large_param, function_call_serialization_benchmark, sample_workloads_benchmark } criterion_main!(benches); diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 671dbe7db..ecc650c99 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -23,10 +23,12 @@ use std::path::Path; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::{Arc, Mutex}; +use flatbuffers::FlatBufferBuilder; use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType}; use hyperlight_common::flatbuffer_wrappers::function_types::{ ParameterValue, ReturnType, ReturnValue, }; +use hyperlight_common::flatbuffer_wrappers::util::estimate_flatbuffer_capacity; use tracing::{Span, instrument}; use super::host_funcs::FunctionRegistry; @@ -44,7 +46,7 @@ use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::RawPtr; use crate::mem::shared_mem::HostSharedMemory; use crate::metrics::maybe_time_and_emit_guest_call; -use crate::{HyperlightError, Result, log_then_return}; +use crate::{Result, log_then_return}; /// Global counter for assigning unique IDs to sandboxes static SANDBOX_ID_COUNTER: AtomicU64 = AtomicU64::new(0); @@ -392,6 +394,8 @@ impl MultiUseSandbox { args: Vec, ) -> Result { let res = (|| { + let estimated_capacity = estimate_flatbuffer_capacity(function_name, &args); + let fc = FunctionCall::new( function_name.to_string(), Some(args), @@ -399,13 +403,12 @@ impl MultiUseSandbox { return_type, ); - let buffer: Vec = fc.try_into().map_err(|_| { - HyperlightError::Error("Failed to serialize FunctionCall".to_string()) - })?; + let mut builder = FlatBufferBuilder::with_capacity(estimated_capacity); + let buffer = fc.encode(&mut builder); self.get_mgr_wrapper_mut() .as_mut() - .write_guest_function_call(&buffer)?; + .write_guest_function_call(buffer)?; self.vm.dispatch_call_from_host( self.dispatch_ptr.clone(), diff --git a/src/tests/c_guests/c_simpleguest/main.c b/src/tests/c_guests/c_simpleguest/main.c index 664b8441d..b7a9a596f 100644 --- a/src/tests/c_guests/c_simpleguest/main.c +++ b/src/tests/c_guests/c_simpleguest/main.c @@ -4,6 +4,7 @@ #include "stdint.h" #include "string.h" #include "stdlib.h" +#include "assert.h" // Included from hyperlight_guest_bin/third_party/printf #include "printf.h" @@ -232,6 +233,12 @@ int log_message(const char *message, int64_t level) { return -1; } +hl_Vec *twenty_four_k_in_eight_k_out(const hl_FunctionCall* params) { + hl_Vec input = params->parameters[0].value.VecBytes; + assert(input.len == 24 * 1024); + return hl_flatbuffer_result_from_Bytes(input.data, 8 * 1024); +} + HYPERLIGHT_WRAP_FUNCTION(echo, String, 1, String) // HYPERLIGHT_WRAP_FUNCTION(set_byte_array_to_zero, 1, VecBytes) is not valid for functions that return VecBytes HYPERLIGHT_WRAP_FUNCTION(print_output, Int, 1, String) @@ -260,6 +267,7 @@ HYPERLIGHT_WRAP_FUNCTION(guest_abort_with_msg, Int, 2, Int, String) HYPERLIGHT_WRAP_FUNCTION(guest_abort_with_code, Int, 1, Int) HYPERLIGHT_WRAP_FUNCTION(execute_on_stack, Int, 0) HYPERLIGHT_WRAP_FUNCTION(log_message, Int, 2, String, Long) +// HYPERLIGHT_WRAP_FUNCTION(twenty_four_k_in_eight_k_out, VecBytes, 1, VecBytes) is not valid for functions that return VecBytes void hyperlight_main(void) { @@ -295,6 +303,9 @@ void hyperlight_main(void) HYPERLIGHT_REGISTER_FUNCTION("GuestAbortWithMessage", guest_abort_with_msg); HYPERLIGHT_REGISTER_FUNCTION("ExecuteOnStack", execute_on_stack); HYPERLIGHT_REGISTER_FUNCTION("LogMessage", log_message); + // HYPERLIGHT_REGISTER_FUNCTION macro does not work for functions that return VecBytes, + // so we use hl_register_function_definition directly + hl_register_function_definition("24K_in_8K_out", twenty_four_k_in_eight_k_out, 1, (hl_ParameterType[]){hl_ParameterType_VecBytes}, hl_ReturnType_VecBytes); } // This dispatch function is only used when the host dispatches a guest function diff --git a/src/tests/rust_guests/callbackguest/Cargo.lock b/src/tests/rust_guests/callbackguest/Cargo.lock index f0fdb7982..9edddc50f 100644 --- a/src/tests/rust_guests/callbackguest/Cargo.lock +++ b/src/tests/rust_guests/callbackguest/Cargo.lock @@ -85,6 +85,7 @@ name = "hyperlight-guest" version = "0.8.0" dependencies = [ "anyhow", + "flatbuffers", "hyperlight-common", "hyperlight-guest-tracing", "serde_json", diff --git a/src/tests/rust_guests/dummyguest/Cargo.lock b/src/tests/rust_guests/dummyguest/Cargo.lock index f1c9d9e55..43bc55918 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.lock +++ b/src/tests/rust_guests/dummyguest/Cargo.lock @@ -83,6 +83,7 @@ name = "hyperlight-guest" version = "0.7.0" dependencies = [ "anyhow", + "flatbuffers", "hyperlight-common", "hyperlight-guest-tracing", "serde_json", diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index 2b323048d..ddc53b202 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -75,6 +75,7 @@ name = "hyperlight-guest" version = "0.8.0" dependencies = [ "anyhow", + "flatbuffers", "hyperlight-common", "hyperlight-guest-tracing", "serde_json", diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index 5b5fe4dcf..c3b17ad58 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -725,6 +725,19 @@ fn add_to_static_and_fail(_: &FunctionCall) -> Result> { )) } +#[hyperlight_guest_tracing::trace_function] +fn twenty_four_k_in_eight_k_out(function_call: &FunctionCall) -> Result> { + if let ParameterValue::VecBytes(input) = &function_call.parameters.as_ref().unwrap()[0] { + assert!(input.len() == 24 * 1024, "Input must be 24K bytes"); + Ok(get_flatbuffer_result(&input[..8 * 1024])) + } else { + Err(HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + "Invalid parameters passed to 24K_in_8K_out".to_string(), + )) + } +} + #[hyperlight_guest_tracing::trace_function] fn violate_seccomp_filters(function_call: &FunctionCall) -> Result> { if function_call.parameters.is_none() { @@ -901,6 +914,14 @@ fn exec_mapped_buffer(function_call: &FunctionCall) -> Result> { #[no_mangle] #[hyperlight_guest_tracing::trace_function] pub extern "C" fn hyperlight_main() { + let twenty_four_k_in_def = GuestFunctionDefinition::new( + "24K_in_8K_out".to_string(), + Vec::from(&[ParameterType::VecBytes]), + ReturnType::VecBytes, + twenty_four_k_in_eight_k_out as usize, + ); + register_function(twenty_four_k_in_def); + let read_from_user_memory_def = GuestFunctionDefinition::new( "ReadFromUserMemory".to_string(), Vec::from(&[ParameterType::ULong, ParameterType::VecBytes]), diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index 2ecd6119f..4f0f9e057 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -218,6 +218,7 @@ name = "hyperlight-guest" version = "0.7.0" dependencies = [ "anyhow", + "flatbuffers", "hyperlight-common", "hyperlight-guest-tracing", "serde_json", From 2e29377a0f256b2daac37aa1ec42e2b25ffd8fe5 Mon Sep 17 00:00:00 2001 From: Tomasz Andrzejak Date: Mon, 25 Aug 2025 21:30:11 +0200 Subject: [PATCH 123/271] fix(guest-bin): align user memory allocations (#753) * fix(guest-bin): align user memory allocations The guest allocation wrapper aligned only the total memory block but did not guarantee that the pointer returned to the user was itself properly aligned. This patch attempts to fix that. It also adds alloc_aligned function which would be tricky to implement outside the guest but will make implementing other posix like allocation API much easier. Signed-off-by: Tomasz Andrzejak * Add comment on alloc_helper invariants Signed-off-by: Tomasz Andrzejak --------- Signed-off-by: Tomasz Andrzejak --- src/hyperlight_guest_bin/src/memory.rs | 108 ++++++++++++++++--------- 1 file changed, 72 insertions(+), 36 deletions(-) diff --git a/src/hyperlight_guest_bin/src/memory.rs b/src/hyperlight_guest_bin/src/memory.rs index 48eb4f602..5cc72c8ab 100644 --- a/src/hyperlight_guest_bin/src/memory.rs +++ b/src/hyperlight_guest_bin/src/memory.rs @@ -40,36 +40,51 @@ use hyperlight_guest::exit::abort_with_code; */ // We assume the maximum alignment for any value is the alignment of u128. -const MAX_ALIGN: usize = align_of::(); +const DEFAULT_ALIGN: usize = align_of::(); +const HEADER_LEN: usize = size_of::
(); + +#[repr(transparent)] +// A header that stores the layout information for the allocated memory block. +struct Header(Layout); /// Allocates a block of memory with the given size. The memory is only guaranteed to be initialized to 0s if `zero` is true, otherwise /// it may or may not be initialized. /// +/// # Invariants +/// `alignment` must be non-zero and a power of two +/// /// # Safety /// The returned pointer must be freed with `memory::free` when it is no longer needed, otherwise memory will leak. -unsafe fn alloc_helper(size: usize, zero: bool) -> *mut c_void { +unsafe fn alloc_helper(size: usize, alignment: usize, zero: bool) -> *mut c_void { if size == 0 { return ptr::null_mut(); } - // Allocate a block that includes space for both layout information and data - let total_size = size - .checked_add(size_of::()) - .expect("data and layout size should not overflow in alloc"); - let layout = Layout::from_size_align(total_size, MAX_ALIGN).expect("Invalid layout"); + let actual_align = alignment.max(align_of::
()); + let data_offset = HEADER_LEN.next_multiple_of(actual_align); + + let Some(total_size) = data_offset.checked_add(size) else { + abort_with_code(&[ErrorCode::MallocFailed as u8]); + }; + + // Create layout for entire allocation + let layout = + Layout::from_size_align(total_size, actual_align).expect("Invalid layout parameters"); unsafe { let raw_ptr = match zero { true => alloc::alloc::alloc_zeroed(layout), false => alloc::alloc::alloc(layout), }; + if raw_ptr.is_null() { abort_with_code(&[ErrorCode::MallocFailed as u8]); - } else { - let layout_ptr = raw_ptr as *mut Layout; - layout_ptr.write(layout); - layout_ptr.add(1) as *mut c_void } + + // Place Header immediately before the user data region + let header_ptr = raw_ptr.add(data_offset - HEADER_LEN).cast::
(); + header_ptr.write(Header(layout)); + raw_ptr.add(data_offset) as *mut c_void } } @@ -80,7 +95,7 @@ unsafe fn alloc_helper(size: usize, zero: bool) -> *mut c_void { /// The returned pointer must be freed with `memory::free` when it is no longer needed, otherwise memory will leak. #[unsafe(no_mangle)] pub unsafe extern "C" fn malloc(size: usize) -> *mut c_void { - unsafe { alloc_helper(size, false) } + unsafe { alloc_helper(size, DEFAULT_ALIGN, false) } } /// Allocates a block of memory for an array of `nmemb` elements, each of `size` bytes. @@ -95,22 +110,45 @@ pub unsafe extern "C" fn calloc(nmemb: usize, size: usize) -> *mut c_void { .checked_mul(size) .expect("nmemb * size should not overflow in calloc"); - alloc_helper(total_size, true) + alloc_helper(total_size, DEFAULT_ALIGN, true) } } +/// Allocates aligned memory. +/// +/// # Safety +/// The returned pointer must be freed with `free` when it is no longer needed. +#[unsafe(no_mangle)] +pub unsafe extern "C" fn aligned_alloc(alignment: usize, size: usize) -> *mut c_void { + // Validate alignment + if alignment == 0 || (alignment & (alignment - 1)) != 0 { + return ptr::null_mut(); + } + + unsafe { alloc_helper(size, alignment, false) } +} + /// Frees the memory block pointed to by `ptr`. /// /// # Safety /// `ptr` must be a pointer to a memory block previously allocated by `memory::malloc`, `memory::calloc`, or `memory::realloc`. #[unsafe(no_mangle)] pub unsafe extern "C" fn free(ptr: *mut c_void) { - if !ptr.is_null() { - unsafe { - let block_start = (ptr as *const Layout).sub(1); - let layout = block_start.read(); - alloc::alloc::dealloc(block_start as *mut u8, layout) - } + if ptr.is_null() { + return; + } + + let user_ptr = ptr as *const u8; + + unsafe { + // Read the Header just before the user data + let header_ptr = user_ptr.sub(HEADER_LEN).cast::
(); + let layout = header_ptr.read().0; + + // Deallocate from the original base pointer + let offset = HEADER_LEN.next_multiple_of(layout.align()); + let raw_ptr = user_ptr.sub(offset) as *mut u8; + alloc::alloc::dealloc(raw_ptr, layout); } } @@ -134,26 +172,24 @@ pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void { return ptr::null_mut(); } - let total_new_size = size - .checked_add(size_of::()) - .expect("data and layout size should not overflow in realloc"); + let user_ptr = ptr as *const u8; - let block_start = unsafe { (ptr as *const Layout).sub(1) }; - let old_layout = unsafe { block_start.read() }; - let new_layout = Layout::from_size_align(total_new_size, MAX_ALIGN).unwrap(); + unsafe { + let header_ptr = user_ptr.sub(HEADER_LEN).cast::
(); - let new_block_start = - unsafe { alloc::alloc::realloc(block_start as *mut u8, old_layout, total_new_size) } - as *mut Layout; + let old_layout = header_ptr.read().0; + let old_offset = HEADER_LEN.next_multiple_of(old_layout.align()); + let old_user_size = old_layout.size() - old_offset; - if new_block_start.is_null() { - // Realloc failed - abort_with_code(&[ErrorCode::MallocFailed as u8]); - } else { - // Update the stored Layout, then return ptr to memory right after the Layout. - unsafe { - new_block_start.write(new_layout); - new_block_start.add(1) as *mut c_void + let new_ptr = alloc_helper(size, old_layout.align(), false); + if new_ptr.is_null() { + return ptr::null_mut(); } + + let copy_size = old_user_size.min(size); + ptr::copy_nonoverlapping(user_ptr, new_ptr as *mut u8, copy_size); + + free(ptr); + new_ptr } } From 45c43b0e2e5f74f738108831151d3941b25e10c8 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Mon, 25 Aug 2025 13:48:11 -0700 Subject: [PATCH 124/271] Build c guests as required by benchmarks (#822) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- .github/workflows/Benchmarks.yml | 20 +++++++++++++------ .../workflows/dep_build_guest_binaries.yml | 17 ++++++++++++---- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/.github/workflows/Benchmarks.yml b/.github/workflows/Benchmarks.yml index 88b628e1e..45b782025 100644 --- a/.github/workflows/Benchmarks.yml +++ b/.github/workflows/Benchmarks.yml @@ -34,17 +34,25 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Download Guest Binaries + - name: Download Rust Guest Binaries uses: actions/download-artifact@v5 with: - name: guest-binaries-release - path: ./downloaded-guest-binaries-release + name: rust-guest-binaries-release + path: ./downloaded-rust-guest-binaries-release + + - name: Download C Guest Binaries + uses: actions/download-artifact@v5 + with: + name: c-guest-binaries-release + path: ./downloaded-c-guest-binaries-release - name: Copy Guest Binaries run: | - cp ./downloaded-guest-binaries-release/callbackguest ./src/tests/rust_guests/bin/release/callbackguest - cp ./downloaded-guest-binaries-release/simpleguest ./src/tests/rust_guests/bin/release/simpleguest - cp ./downloaded-guest-binaries-release/dummyguest ./src/tests/rust_guests/bin/release/dummyguest + cp ./downloaded-rust-guest-binaries-release/callbackguest ./src/tests/rust_guests/bin/release/callbackguest + cp ./downloaded-rust-guest-binaries-release/simpleguest ./src/tests/rust_guests/bin/release/simpleguest + cp ./downloaded-rust-guest-binaries-release/dummyguest ./src/tests/rust_guests/bin/release/dummyguest + cp ./downloaded-c-guest-binaries-release/callbackguest ./src/tests/c_guests/bin/release/callbackguest + cp ./downloaded-c-guest-binaries-release/simpleguest ./src/tests/c_guests/bin/release/simpleguest ### Benchmarks ### - name: Fetch tags diff --git a/.github/workflows/dep_build_guest_binaries.yml b/.github/workflows/dep_build_guest_binaries.yml index 8cc6d1089..89ebf4dca 100644 --- a/.github/workflows/dep_build_guest_binaries.yml +++ b/.github/workflows/dep_build_guest_binaries.yml @@ -37,15 +37,24 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Build and move Rust guests - run: just build-and-move-rust-guests + - name: Build and move Rust and C guests + run: just guests - - name: Upload Binary Artifacts + - name: Upload Rust Guest Artifacts uses: actions/upload-artifact@v4 with: - name: guest-binaries-${{ matrix.config }} + name: rust-guest-binaries-${{ matrix.config }} path: | src\tests\rust_guests\bin\${{ matrix.config }}\callbackguest src\tests\rust_guests\bin\${{ matrix.config }}\dummyguest src\tests\rust_guests\bin\${{ matrix.config }}\simpleguest if-no-files-found: error + + - name: Upload C Guest Artifacts + uses: actions/upload-artifact@v4 + with: + name: c-guest-binaries-${{ matrix.config }} + path: | + src\tests\c_guests\bin\${{ matrix.config }}\callbackguest + src\tests\c_guests\bin\${{ matrix.config }}\simpleguest + if-no-files-found: error From 2700f47f38149c9fb176298439082f18d45ba501 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 22:23:06 -0700 Subject: [PATCH 125/271] Bump kvm-bindings from 0.13.0 to 0.14.0 (#801) * Bump kvm-bindings from 0.13.0 to 0.14.0 Bumps [kvm-bindings](https://github.com/rust-vmm/kvm) from 0.13.0 to 0.14.0. - [Release notes](https://github.com/rust-vmm/kvm/releases) - [Commits](https://github.com/rust-vmm/kvm/compare/kvm-bindings-v0.13.0...kvm-bindings-v0.14.0) --- updated-dependencies: - dependency-name: kvm-bindings dependency-version: 0.14.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Upgrade KVM bindings and map error type directly Signed-off-by: James Sturtevant --------- Signed-off-by: dependabot[bot] Signed-off-by: James Sturtevant Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: James Sturtevant --- Cargo.lock | 32 +++++++------------ src/hyperlight_host/Cargo.toml | 4 +-- src/hyperlight_host/src/error.rs | 2 +- .../src/signal_handlers/mod.rs | 6 ++-- 4 files changed, 18 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 751c2a3bc..409635181 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1495,7 +1495,7 @@ dependencies = [ "tracing-subscriber", "tracing-tracy", "uuid", - "vmm-sys-util 0.15.0", + "vmm-sys-util", "windows", "windows-result", "windows-sys 0.60.2", @@ -1784,23 +1784,23 @@ dependencies = [ [[package]] name = "kvm-bindings" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3432d9f609fbede9f624d1dbefcce77985a9322de1d0e6d460ec05502b7fd0" +checksum = "4b3c06ff73c7ce03e780887ec2389d62d2a2a9ddf471ab05c2ff69207cd3f3b4" dependencies = [ - "vmm-sys-util 0.14.0", + "vmm-sys-util", ] [[package]] name = "kvm-ioctls" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e00243d27a20feb05cf001ae52ddc79831ac70c020f215ba1153ff9270b650a" +checksum = "333f77a20344a448f3f70664918135fddeb804e938f28a99d685bd92926e0b19" dependencies = [ "bitflags 2.9.3", "kvm-bindings", "libc", - "vmm-sys-util 0.14.0", + "vmm-sys-util", ] [[package]] @@ -2056,7 +2056,7 @@ checksum = "f416b4432174e5a3f956a7887f4c1a4acea9511d81def67fcb8473293630ab9e" dependencies = [ "libc", "num_enum", - "vmm-sys-util 0.15.0", + "vmm-sys-util", "zerocopy 0.7.35", ] @@ -2068,7 +2068,7 @@ checksum = "1e0cb5031f3243a7459b7c13d960d25420980874eebda816db24ce6077e21d43" dependencies = [ "libc", "num_enum", - "vmm-sys-util 0.15.0", + "vmm-sys-util", "zerocopy 0.8.26", ] @@ -2081,7 +2081,7 @@ dependencies = [ "libc", "mshv-bindings 0.2.1", "thiserror 1.0.69", - "vmm-sys-util 0.15.0", + "vmm-sys-util", ] [[package]] @@ -2093,7 +2093,7 @@ dependencies = [ "libc", "mshv-bindings 0.3.2", "thiserror 2.0.16", - "vmm-sys-util 0.15.0", + "vmm-sys-util", ] [[package]] @@ -3910,16 +3910,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "vmm-sys-util" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d21f366bf22bfba3e868349978766a965cbe628c323d58e026be80b8357ab789" -dependencies = [ - "bitflags 1.3.2", - "libc", -] - [[package]] name = "vmm-sys-util" version = "0.15.0" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 94c26e369..b3b608d21 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -74,8 +74,8 @@ lazy_static = "1.4.0" [target.'cfg(unix)'.dependencies] seccompiler = { version = "0.5.0", optional = true } -kvm-bindings = { version = "0.13", features = ["fam-wrappers"], optional = true } -kvm-ioctls = { version = "0.23", optional = true } +kvm-bindings = { version = "0.14", features = ["fam-wrappers"], optional = true } +kvm-ioctls = { version = "0.24", optional = true } mshv-bindings2 = { package="mshv-bindings", version = "=0.2.1", optional = true } mshv-ioctls2 = { package="mshv-ioctls", version = "=0.2.1", optional = true} mshv-bindings3 = { package="mshv-bindings", version = "=0.3.2", optional = true } diff --git a/src/hyperlight_host/src/error.rs b/src/hyperlight_host/src/error.rs index c07f9857f..d2fb382a0 100644 --- a/src/hyperlight_host/src/error.rs +++ b/src/hyperlight_host/src/error.rs @@ -268,7 +268,7 @@ pub enum HyperlightError { /// vmm sys Error Occurred #[error("vmm sys Error {0:?}")] #[cfg(target_os = "linux")] - VmmSysError(#[from] vmm_sys_util::errno::Error), + VmmSysError(vmm_sys_util::errno::Error), /// Windows Error #[cfg(target_os = "windows")] diff --git a/src/hyperlight_host/src/signal_handlers/mod.rs b/src/hyperlight_host/src/signal_handlers/mod.rs index bf35d499d..db52035d5 100644 --- a/src/hyperlight_host/src/signal_handlers/mod.rs +++ b/src/hyperlight_host/src/signal_handlers/mod.rs @@ -32,7 +32,8 @@ pub(crate) fn setup_signal_handlers(config: &SandboxConfiguration) -> crate::Res vmm_sys_util::signal::register_signal_handler( libc::SIGSYS, sigsys_signal_handler::handle_sigsys, - )?; + ) + .map_err(crate::HyperlightError::VmmSysError)?; let original_hook = std::panic::take_hook(); // Set a custom panic hook that checks for "DisallowedSyscall" @@ -52,7 +53,8 @@ pub(crate) fn setup_signal_handlers(config: &SandboxConfiguration) -> crate::Res vmm_sys_util::signal::register_signal_handler( libc::SIGRTMIN() + config.get_interrupt_vcpu_sigrtmin_offset() as c_int, vm_kill_signal, - )?; + ) + .map_err(crate::HyperlightError::VmmSysError)?; // Note: For libraries registering signal handlers, it's important to keep in mind that // the user of the library could have their own signal handlers that we don't want to From bddee657aaa3e9ede44553365875070fcce9a868 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Aug 2025 14:35:11 -0700 Subject: [PATCH 126/271] Bump wasmparser from 0.237.0 to 0.238.0 (#825) Bumps [wasmparser](https://github.com/bytecodealliance/wasm-tools) from 0.237.0 to 0.238.0. - [Release notes](https://github.com/bytecodealliance/wasm-tools/releases) - [Commits](https://github.com/bytecodealliance/wasm-tools/commits) --- updated-dependencies: - dependency-name: wasmparser dependency-version: 0.238.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 409635181..413d88dc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4036,9 +4036,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.237.0" +version = "0.238.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d2a40ca0d2bdf4b0bf36c13a737d0b2c58e4c8aaefe1c57f336dd75369ca250" +checksum = "c0ad4ca2ecb86b79ea410cd970985665de1d05774b7107b214bc5852b1bcbad7" dependencies = [ "bitflags 2.9.3", "hashbrown", diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index 3e363022c..665053c8a 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -16,7 +16,7 @@ name = "hyperlight_component_macro" proc-macro = true [dependencies] -wasmparser = { version = "0.237.0" } +wasmparser = { version = "0.238.0" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index 0cad80969..9d0b3ffdd 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -15,7 +15,7 @@ Shared implementation for the procedural macros that generate Hyperlight host an name = "hyperlight_component_util" [dependencies] -wasmparser = { version = "0.237.0" } +wasmparser = { version = "0.238.0" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } From a9a5f1c93e86afc9b7d214d309f8901502fb7b6d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Aug 2025 09:24:33 +0000 Subject: [PATCH 127/271] Bump slab from 0.4.10 to 0.4.11 (#828) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 413d88dc0..8329ccd27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3245,9 +3245,9 @@ checksum = "c1e9a774a6c28142ac54bb25d25562e6bcf957493a184f15ad4eebccb23e410a" [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" From 852f0ff73ddb4c36e3b2847188ff04beafa57b3f Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 28 Aug 2025 12:22:34 +0100 Subject: [PATCH 128/271] Ran cargo update, updated dependabot to run against workspace excluded members (#830) Signed-off-by: Simon Davies --- .github/dependabot.yml | 37 +++ Cargo.lock | 237 +++++++++--------- .../rust_guests/callbackguest/Cargo.lock | 32 +-- src/tests/rust_guests/dummyguest/Cargo.lock | 42 ++-- src/tests/rust_guests/simpleguest/Cargo.lock | 32 +-- src/tests/rust_guests/witguest/Cargo.lock | 157 ++++++------ 6 files changed, 286 insertions(+), 251 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8dd50eea7..088efd8a8 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -21,3 +21,40 @@ updates: - dependency-name: "mshv-bindings" versions: [ ">=0.2.1" ] open-pull-requests-limit: 20 + # Excluded workspace members - guests with custom linker flags + - package-ecosystem: "cargo" + directory: "/src/tests/rust_guests/callbackguest" + schedule: + interval: "daily" + time: "03:00" + labels: + - "kind/dependencies" + - "area/guest" + open-pull-requests-limit: 5 + - package-ecosystem: "cargo" + directory: "/src/tests/rust_guests/dummyguest" + schedule: + interval: "daily" + time: "03:00" + labels: + - "kind/dependencies" + - "area/guest" + open-pull-requests-limit: 5 + - package-ecosystem: "cargo" + directory: "/src/tests/rust_guests/simpleguest" + schedule: + interval: "daily" + time: "03:00" + labels: + - "kind/dependencies" + - "area/guest" + open-pull-requests-limit: 5 + - package-ecosystem: "cargo" + directory: "/src/tests/rust_guests/witguest" + schedule: + interval: "daily" + time: "03:00" + labels: + - "kind/dependencies" + - "area/guest" + open-pull-requests-limit: 5 diff --git a/Cargo.lock b/Cargo.lock index 8329ccd27..0bd280065 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "9acbfca36652500c911ddb767ed433e3ed99b032b5d935be73c6923662db1d43" dependencies = [ "cpp_demangle", "fallible-iterator", - "gimli 0.32.0", + "gimli 0.32.2", "memmap2", - "object 0.37.1", + "object 0.37.3", "rustc-demangle", "smallvec", "typed-arena", @@ -77,9 +77,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.19" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", @@ -107,22 +107,22 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.9" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -160,15 +160,21 @@ checksum = "b993cd767a2bc7307dd87622311ca22c44329cc7a21366206bfa0896827b2bad" [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.5.0" @@ -382,9 +388,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d0390889d58f934f01cd49736275b4c2da15bcfc328c78ff2349907e6cabf22" +checksum = "c8d458d63f0f0f482c8da9b7c8b76c21bd885a02056cc94c6404d861ca2b8206" dependencies = [ "smallvec", "target-lexicon", @@ -456,18 +462,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.40" +version = "4.5.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" +checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.40" +version = "4.5.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" +checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41" dependencies = [ "anstream", "anstyle", @@ -565,9 +571,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -666,9 +672,9 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", @@ -719,9 +725,9 @@ dependencies = [ [[package]] name = "dwrote" -version = "0.11.3" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe1f192fcce01590bd8d839aca53ce0d11d803bf291b2a6c4ad925a8f0024be" +checksum = "20c93d234bac0cdd0e2ac08bc8a5133f8df2169e95b262dfcea5e5cb7855672f" dependencies = [ "lazy_static", "libc", @@ -894,9 +900,9 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -910,7 +916,7 @@ dependencies = [ "arrayvec", "cfg-if", "fallible-iterator", - "gimli 0.32.0", + "gimli 0.32.2", "macho-unwind-info", "pe-unwind-info", ] @@ -1030,9 +1036,9 @@ dependencies = [ [[package]] name = "generator" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d18470a76cb7f8ff746cf1f7470914f900252ec36bbc40b569d74b1258446827" +checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" dependencies = [ "cc", "cfg-if", @@ -1083,9 +1089,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "gimli" -version = "0.32.0" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93563d740bc9ef04104f9ed6f86f1e3275c2cdafb95664e26584b9ca807a8ffe" +checksum = "cc6298e594375a7fead9efd5568f0a46e6a154fb6a9bdcbe3c06946ffd81a5f6" dependencies = [ "fallible-iterator", "stable_deref_trait", @@ -1193,8 +1199,8 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", + "regex-automata 0.4.10", + "regex-syntax 0.8.6", ] [[package]] @@ -1231,9 +1237,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "foldhash", "serde", @@ -1293,18 +1299,20 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "hyper" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", + "futures-core", "http", "http-body", "httparse", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -1312,9 +1320,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" +checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" dependencies = [ "base64", "bytes", @@ -1328,7 +1336,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2", "tokio", "tower-service", "tracing", @@ -1640,9 +1648,9 @@ dependencies = [ [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -1661,9 +1669,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" dependencies = [ "equivalent", "hashbrown", @@ -1672,9 +1680,9 @@ dependencies = [ [[package]] name = "io-uring" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" dependencies = [ "bitflags 2.9.3", "cfg-if", @@ -1753,9 +1761,9 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ "getrandom 0.3.3", "libc", @@ -1844,7 +1852,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.2", + "windows-targets 0.53.3", ] [[package]] @@ -1860,9 +1868,9 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.4" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" +checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" dependencies = [ "bitflags 2.9.3", "libc", @@ -1970,9 +1978,9 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" dependencies = [ "libc", ] @@ -2177,9 +2185,9 @@ dependencies = [ [[package]] name = "object" -version = "0.37.1" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "flate2", "memchr", @@ -2408,9 +2416,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "piet" @@ -2673,7 +2681,7 @@ dependencies = [ "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.5", + "regex-syntax 0.8.6", "rusty-fork", "tempfile", "unarray", @@ -2806,9 +2814,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -2816,9 +2824,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -2826,18 +2834,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ "bitflags 2.9.3", ] [[package]] name = "redox_users" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", @@ -2846,14 +2854,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", + "regex-automata 0.4.10", + "regex-syntax 0.8.6", ] [[package]] @@ -2867,13 +2875,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.5", + "regex-syntax 0.8.6", ] [[package]] @@ -2884,15 +2892,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "reqwest" -version = "0.12.22" +version = "0.12.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" dependencies = [ "base64", "bytes", @@ -2960,9 +2968,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" @@ -2981,22 +2989,22 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ "bitflags 2.9.3", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rusty-fork" @@ -3036,9 +3044,9 @@ dependencies = [ [[package]] name = "scc" -version = "2.3.4" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22b2d775fb28f245817589471dd49c5edf64237f4a19d10ce9a92ff4651a27f4" +checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" dependencies = [ "sdd", ] @@ -3077,9 +3085,9 @@ dependencies = [ [[package]] name = "sdd" -version = "3.0.8" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21" +checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" [[package]] name = "seccompiler" @@ -3255,16 +3263,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.0" @@ -3461,7 +3459,7 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "slab", - "socket2 0.6.0", + "socket2", "tokio-macros", "windows-sys 0.59.0", ] @@ -3744,9 +3742,9 @@ dependencies = [ [[package]] name = "tracy-client-sys" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9612d9503675b07b244922ea6f6f3cdd88c43add1b3498084613fc88cdf69d" +checksum = "319c70195101a93f56db4c74733e272d720768e13471f400c78406a326b172b0" dependencies = [ "cc", "windows-targets 0.52.6", @@ -3847,13 +3845,14 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -4085,11 +4084,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -4200,15 +4199,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.59.0" @@ -4224,7 +4214,7 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.2", + "windows-targets 0.53.3", ] [[package]] @@ -4245,10 +4235,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.2" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ + "windows-link", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -4375,9 +4366,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] @@ -4511,9 +4502,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", diff --git a/src/tests/rust_guests/callbackguest/Cargo.lock b/src/tests/rust_guests/callbackguest/Cargo.lock index 9edddc50f..1d537c09c 100644 --- a/src/tests/rust_guests/callbackguest/Cargo.lock +++ b/src/tests/rust_guests/callbackguest/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "autocfg" @@ -16,9 +16,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" [[package]] name = "buddy_system_allocator" @@ -41,18 +41,18 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.30" +version = "1.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" dependencies = [ "shlex", ] [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "flatbuffers" @@ -66,9 +66,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hyperlight-common" @@ -154,9 +154,9 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -219,9 +219,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.141" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ "itoa", "memchr", @@ -255,9 +255,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", diff --git a/src/tests/rust_guests/dummyguest/Cargo.lock b/src/tests/rust_guests/dummyguest/Cargo.lock index 43bc55918..77734d32c 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.lock +++ b/src/tests/rust_guests/dummyguest/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "autocfg" @@ -16,9 +16,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" [[package]] name = "buddy_system_allocator" @@ -31,18 +31,18 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.29" +version = "1.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" +checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" dependencies = [ "shlex", ] [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "dummyguest" @@ -64,13 +64,13 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hyperlight-common" -version = "0.7.0" +version = "0.8.0" dependencies = [ "anyhow", "flatbuffers", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.7.0" +version = "0.8.0" dependencies = [ "anyhow", "flatbuffers", @@ -91,7 +91,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.7.0" +version = "0.8.0" dependencies = [ "buddy_system_allocator", "cc", @@ -106,7 +106,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing" -version = "0.7.0" +version = "0.8.0" dependencies = [ "hyperlight-common", "hyperlight-guest-tracing-macro", @@ -115,7 +115,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing-macro" -version = "0.7.0" +version = "0.8.0" dependencies = [ "proc-macro2", "quote", @@ -152,9 +152,9 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -217,9 +217,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ "itoa", "memchr", @@ -253,9 +253,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index ddc53b202..9a9f82278 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "autocfg" @@ -16,9 +16,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" [[package]] name = "buddy_system_allocator" @@ -31,18 +31,18 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.30" +version = "1.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" dependencies = [ "shlex", ] [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "flatbuffers" @@ -56,9 +56,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hyperlight-common" @@ -144,9 +144,9 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -209,9 +209,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.141" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ "itoa", "memchr", @@ -256,9 +256,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index 4f0f9e057..9d018920a 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.19" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", @@ -43,18 +43,18 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.9" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", @@ -63,21 +63,21 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" [[package]] name = "buddy_system_allocator" @@ -90,18 +90,18 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.25" +version = "1.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" +checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" dependencies = [ "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "colorchoice" @@ -162,15 +162,15 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "foldhash", "serde", @@ -178,7 +178,7 @@ dependencies = [ [[package]] name = "hyperlight-common" -version = "0.7.0" +version = "0.8.0" dependencies = [ "anyhow", "flatbuffers", @@ -188,7 +188,7 @@ dependencies = [ [[package]] name = "hyperlight-component-macro" -version = "0.7.0" +version = "0.8.0" dependencies = [ "env_logger", "hyperlight-component-util", @@ -202,7 +202,7 @@ dependencies = [ [[package]] name = "hyperlight-component-util" -version = "0.7.0" +version = "0.8.0" dependencies = [ "itertools", "log", @@ -215,7 +215,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.7.0" +version = "0.8.0" dependencies = [ "anyhow", "flatbuffers", @@ -226,7 +226,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.7.0" +version = "0.8.0" dependencies = [ "buddy_system_allocator", "cc", @@ -241,7 +241,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing" -version = "0.7.0" +version = "0.8.0" dependencies = [ "hyperlight-common", "hyperlight-guest-tracing-macro", @@ -250,7 +250,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing-macro" -version = "0.7.0" +version = "0.8.0" dependencies = [ "proc-macro2", "quote", @@ -259,9 +259,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" dependencies = [ "equivalent", "hashbrown", @@ -291,9 +291,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" dependencies = [ "jiff-static", "log", @@ -304,9 +304,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", @@ -315,9 +315,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -331,9 +331,9 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "once_cell_polyfill" @@ -343,9 +343,9 @@ checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "portable-atomic" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "portable-atomic-util" @@ -358,9 +358,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.36" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", "syn", @@ -368,9 +368,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -386,9 +386,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick", "memchr", @@ -398,9 +398,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", @@ -409,9 +409,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "rustc_version" @@ -462,9 +462,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ "itoa", "memchr", @@ -498,9 +498,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -521,9 +521,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "wasmparser" -version = "0.236.0" +version = "0.238.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d1eee846a705f6f3cb9d7b9f79b54583810f1fb57a1e3aea76d1742db2e3d2" +checksum = "c0ad4ca2ecb86b79ea410cd970985665de1d05774b7107b214bc5852b1bcbad7" dependencies = [ "bitflags", "hashbrown", @@ -532,21 +532,28 @@ dependencies = [ "serde", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.52.6" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ + "windows-link", "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", @@ -559,51 +566,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" [[package]] name = "windows_aarch64_msvc" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[package]] name = "windows_i686_gnu" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" [[package]] name = "windows_i686_gnullvm" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" [[package]] name = "windows_i686_msvc" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" [[package]] name = "windows_x86_64_gnu" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" [[package]] name = "windows_x86_64_msvc" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "witguest" From 285e440635a477253fd5a0bbf0063544974e2254 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 28 Aug 2025 12:52:11 +0000 Subject: [PATCH 129/271] Remove DbgMemAccessHandlerCaller trait and DbgMemAccessHandlerWrapper (#824) Signed-off-by: Simon Davies Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- src/hyperlight_host/src/hypervisor/gdb/mod.rs | 19 +++-- .../src/hypervisor/handlers.rs | 39 ---------- .../src/hypervisor/hyperv_linux.rs | 24 +++--- .../src/hypervisor/hyperv_windows.rs | 22 +++--- src/hyperlight_host/src/hypervisor/kvm.rs | 22 +++--- src/hyperlight_host/src/hypervisor/mod.rs | 24 +++--- .../src/sandbox/initialized_multi_use.rs | 9 +-- src/hyperlight_host/src/sandbox/mem_access.rs | 78 ------------------- src/hyperlight_host/src/sandbox/mod.rs | 3 - .../src/sandbox/uninitialized_evolve.rs | 6 +- 10 files changed, 55 insertions(+), 191 deletions(-) delete mode 100644 src/hyperlight_host/src/hypervisor/handlers.rs delete mode 100644 src/hyperlight_host/src/sandbox/mem_access.rs diff --git a/src/hyperlight_host/src/hypervisor/gdb/mod.rs b/src/hyperlight_host/src/hypervisor/gdb/mod.rs index 3cc8ecd7c..118246d3c 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/mod.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/mod.rs @@ -46,8 +46,9 @@ use thiserror::Error; use x86_64_target::HyperlightSandboxTarget; use super::InterruptHandle; -use crate::hypervisor::handlers::DbgMemAccessHandlerCaller; use crate::mem::layout::SandboxMemoryLayout; +use crate::mem::shared_mem::HostSharedMemory; +use crate::sandbox::mem_mgr::MemMgrWrapper; use crate::{HyperlightError, new_error}; #[derive(Debug, Error)] @@ -209,7 +210,7 @@ pub(super) trait GuestDebug { &mut self, vcpu_fd: &Self::Vcpu, addr: u64, - dbg_mem_access_fn: Arc>, + dbg_mem_access_fn: Arc>>, ) -> crate::Result<()> { let addr = self.translate_gva(vcpu_fd, addr)?; @@ -234,7 +235,7 @@ pub(super) trait GuestDebug { vcpu_fd: &Self::Vcpu, mut gva: u64, mut data: &mut [u8], - dbg_mem_access_fn: Arc>, + dbg_mem_access_fn: Arc>>, ) -> crate::Result<()> { let data_len = data.len(); log::debug!("Read addr: {:X} len: {:X}", gva, data_len); @@ -258,7 +259,9 @@ pub(super) trait GuestDebug { dbg_mem_access_fn .try_lock() .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .read(offset, &mut data[..read_len])?; + .unwrap_mgr_mut() + .get_shared_mem_mut() + .copy_to_slice(&mut data[..read_len], offset)?; data = &mut data[read_len..]; gva += read_len as u64; @@ -282,7 +285,7 @@ pub(super) trait GuestDebug { &mut self, vcpu_fd: &Self::Vcpu, addr: u64, - dbg_mem_access_fn: Arc>, + dbg_mem_access_fn: Arc>>, ) -> crate::Result<()> { let addr = self.translate_gva(vcpu_fd, addr)?; @@ -306,7 +309,7 @@ pub(super) trait GuestDebug { vcpu_fd: &Self::Vcpu, mut gva: u64, mut data: &[u8], - dbg_mem_access_fn: Arc>, + dbg_mem_access_fn: Arc>>, ) -> crate::Result<()> { let data_len = data.len(); log::debug!("Write addr: {:X} len: {:X}", gva, data_len); @@ -330,7 +333,9 @@ pub(super) trait GuestDebug { dbg_mem_access_fn .try_lock() .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .write(offset, data)?; + .unwrap_mgr_mut() + .get_shared_mem_mut() + .copy_from_slice(&data[..write_len], offset)?; data = &data[write_len..]; gva += write_len as u64; diff --git a/src/hyperlight_host/src/hypervisor/handlers.rs b/src/hyperlight_host/src/hypervisor/handlers.rs deleted file mode 100644 index 842b44a37..000000000 --- a/src/hyperlight_host/src/hypervisor/handlers.rs +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -use std::sync::{Arc, Mutex}; - -use crate::Result; - -/// The trait representing custom logic to handle the case when -/// a Hypervisor's virtual CPU (vCPU) informs Hyperlight a debug memory access -/// has been requested. -pub trait DbgMemAccessHandlerCaller: Send { - /// Function that gets called when a read is requested. - fn read(&mut self, addr: usize, data: &mut [u8]) -> Result<()>; - - /// Function that gets called when a write is requested. - fn write(&mut self, addr: usize, data: &[u8]) -> Result<()>; - - /// Function that gets called for a request to get guest code offset. - fn get_code_offset(&mut self) -> Result; -} - -/// A convenient type representing an implementer of `DbgMemAccessHandlerCaller` -/// -/// Note: This needs to be wrapped in a Mutex to be able to grab a mutable -/// reference to the underlying data -pub type DbgMemAccessHandlerWrapper = Arc>; diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index cc7528610..1907d8e0b 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -65,8 +65,6 @@ use super::fpu::{FP_CONTROL_WORD_DEFAULT, FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT}; use super::gdb::{ DebugCommChannel, DebugMsg, DebugResponse, GuestDebug, MshvDebug, VcpuStopReason, }; -#[cfg(gdb)] -use super::handlers::DbgMemAccessHandlerWrapper; #[cfg(feature = "init-paging")] use super::{ CR0_AM, CR0_ET, CR0_MP, CR0_NE, CR0_PE, CR0_PG, CR0_WP, CR4_OSFXSR, CR4_OSXMMEXCPT, CR4_PAE, @@ -96,7 +94,8 @@ mod debug { use super::mshv_bindings::hv_x64_exception_intercept_message; use super::{HypervLinuxDriver, *}; use crate::hypervisor::gdb::{DebugMsg, DebugResponse, VcpuStopReason, X86_64Regs}; - use crate::hypervisor::handlers::DbgMemAccessHandlerCaller; + use crate::mem::shared_mem::HostSharedMemory; + use crate::sandbox::mem_mgr::MemMgrWrapper; use crate::{Result, new_error}; impl HypervLinuxDriver { @@ -127,7 +126,7 @@ mod debug { pub(crate) fn process_dbg_request( &mut self, req: DebugMsg, - dbg_mem_access_fn: Arc>, + dbg_mem_access_fn: Arc>>, ) -> Result { if let Some(debug) = self.debug.as_mut() { match req { @@ -175,12 +174,9 @@ mod debug { .map_err(|e| { new_error!("Error locking at {}:{}: {}", file!(), line!(), e) })? - .get_code_offset() - .map_err(|e| { - log::error!("Failed to get code offset: {:?}", e); - - e - })?; + .unwrap_mgr() + .layout + .get_guest_code_address(); Ok(DebugResponse::GetCodeSectionOffset(offset as u64)) } @@ -591,7 +587,7 @@ impl Hypervisor for HypervLinuxDriver { mem_mgr: MemMgrWrapper, host_funcs: Arc>, max_guest_log_level: Option, - #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()> { self.mem_mgr = Some(mem_mgr); self.host_funcs = Some(host_funcs); @@ -663,7 +659,7 @@ impl Hypervisor for HypervLinuxDriver { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()> { // Reset general purpose registers, then set RIP and RSP let regs = StandardRegisters { @@ -1025,9 +1021,7 @@ impl Hypervisor for HypervLinuxDriver { #[cfg(gdb)] fn handle_debug( &mut self, - dbg_mem_access_fn: std::sync::Arc< - std::sync::Mutex, - >, + dbg_mem_access_fn: Arc>>, stop_reason: VcpuStopReason, ) -> Result<()> { if self.debug.is_none() { diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index 0fc701a13..f8b4727d1 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -38,9 +38,7 @@ use { super::gdb::{ DebugCommChannel, DebugMsg, DebugResponse, GuestDebug, HypervDebug, VcpuStopReason, }, - super::handlers::DbgMemAccessHandlerWrapper, crate::HyperlightError, - crate::hypervisor::handlers::DbgMemAccessHandlerCaller, }; #[cfg(feature = "trace_guest")] @@ -80,7 +78,8 @@ mod debug { use super::{HypervWindowsDriver, *}; use crate::Result; use crate::hypervisor::gdb::{DebugMsg, DebugResponse, VcpuStopReason, X86_64Regs}; - use crate::hypervisor::handlers::DbgMemAccessHandlerCaller; + use crate::mem::shared_mem::HostSharedMemory; + use crate::sandbox::mem_mgr::MemMgrWrapper; impl HypervWindowsDriver { /// Resets the debug information to disable debugging @@ -110,7 +109,7 @@ mod debug { pub(crate) fn process_dbg_request( &mut self, req: DebugMsg, - dbg_mem_access_fn: Arc>, + dbg_mem_access_fn: Arc>>, ) -> Result { if let Some(debug) = self.debug.as_mut() { match req { @@ -158,12 +157,9 @@ mod debug { .map_err(|e| { new_error!("Error locking at {}:{}: {}", file!(), line!(), e) })? - .get_code_offset() - .map_err(|e| { - log::error!("Failed to get code offset: {:?}", e); - - e - })?; + .unwrap_mgr() + .layout + .get_guest_code_address(); Ok(DebugResponse::GetCodeSectionOffset(offset as u64)) } @@ -606,7 +602,7 @@ impl Hypervisor for HypervWindowsDriver { mem_mgr: MemMgrWrapper, host_funcs: Arc>, max_guest_log_level: Option, - #[cfg(gdb)] dbg_mem_access_hdl: DbgMemAccessHandlerWrapper, + #[cfg(gdb)] dbg_mem_access_hdl: Arc>>, ) -> Result<()> { self.mem_mgr = Some(mem_mgr); self.host_funcs = Some(host_funcs); @@ -656,7 +652,7 @@ impl Hypervisor for HypervWindowsDriver { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - #[cfg(gdb)] dbg_mem_access_hdl: DbgMemAccessHandlerWrapper, + #[cfg(gdb)] dbg_mem_access_hdl: Arc>>, ) -> Result<()> { // Reset general purpose registers, then set RIP and RSP let regs = WHvGeneralRegisters { @@ -959,7 +955,7 @@ impl Hypervisor for HypervWindowsDriver { #[cfg(gdb)] fn handle_debug( &mut self, - dbg_mem_access_fn: Arc>, + dbg_mem_access_fn: Arc>>, stop_reason: super::gdb::VcpuStopReason, ) -> Result<()> { if self.debug.is_none() { diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index 26eae3e25..be76129fb 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -32,8 +32,6 @@ use super::TraceRegister; use super::fpu::{FP_CONTROL_WORD_DEFAULT, FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT}; #[cfg(gdb)] use super::gdb::{DebugCommChannel, DebugMsg, DebugResponse, GuestDebug, KvmDebug, VcpuStopReason}; -#[cfg(gdb)] -use super::handlers::DbgMemAccessHandlerWrapper; #[cfg(feature = "init-paging")] use super::{ CR0_AM, CR0_ET, CR0_MP, CR0_NE, CR0_PE, CR0_PG, CR0_WP, CR4_OSFXSR, CR4_OSXMMEXCPT, CR4_PAE, @@ -88,7 +86,8 @@ mod debug { use crate::hypervisor::gdb::{ DebugMsg, DebugResponse, GuestDebug, KvmDebug, VcpuStopReason, X86_64Regs, }; - use crate::hypervisor::handlers::DbgMemAccessHandlerCaller; + use crate::mem::shared_mem::HostSharedMemory; + use crate::sandbox::mem_mgr::MemMgrWrapper; use crate::{Result, new_error}; impl KVMDriver { @@ -119,7 +118,7 @@ mod debug { pub(crate) fn process_dbg_request( &mut self, req: DebugMsg, - dbg_mem_access_fn: Arc>, + dbg_mem_access_fn: Arc>>, ) -> Result { if let Some(debug) = self.debug.as_mut() { match req { @@ -167,12 +166,9 @@ mod debug { .map_err(|e| { new_error!("Error locking at {}:{}: {}", file!(), line!(), e) })? - .get_code_offset() - .map_err(|e| { - log::error!("Failed to get code offset: {:?}", e); - - e - })?; + .unwrap_mgr() + .layout + .get_guest_code_address(); Ok(DebugResponse::GetCodeSectionOffset(offset as u64)) } @@ -479,7 +475,7 @@ impl Hypervisor for KVMDriver { mem_mgr: MemMgrWrapper, host_funcs: Arc>, max_guest_log_level: Option, - #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()> { self.mem_mgr = Some(mem_mgr); self.host_funcs = Some(host_funcs); @@ -574,7 +570,7 @@ impl Hypervisor for KVMDriver { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()> { // Reset general purpose registers, then set RIP and RSP let regs = kvm_regs { @@ -902,7 +898,7 @@ impl Hypervisor for KVMDriver { #[cfg(gdb)] fn handle_debug( &mut self, - dbg_mem_access_fn: Arc>, + dbg_mem_access_fn: Arc>>, stop_reason: VcpuStopReason, ) -> Result<()> { if self.debug.is_none() { diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index 53b721c7c..4e55e7ac5 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -17,6 +17,7 @@ limitations under the License. use log::LevelFilter; use tracing::{Span, instrument}; +use crate::HyperlightError::StackOverflow; use crate::error::HyperlightError::ExecutionCanceledByHost; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::metrics::METRIC_GUEST_CANCELLATION; @@ -27,9 +28,7 @@ use crate::{HyperlightError, Result, log_then_return}; /// Util for handling x87 fpu state #[cfg(any(kvm, mshv, target_os = "windows"))] pub mod fpu; -/// Handlers for Hypervisor custom logic -#[cfg(gdb)] -pub mod handlers; + /// HyperV-on-linux functionality #[cfg(mshv)] pub mod hyperv_linux; @@ -71,12 +70,9 @@ use std::time::Duration; #[cfg(gdb)] use gdb::VcpuStopReason; -#[cfg(gdb)] -use self::handlers::{DbgMemAccessHandlerCaller, DbgMemAccessHandlerWrapper}; use crate::mem::ptr::RawPtr; use crate::mem::shared_mem::HostSharedMemory; use crate::sandbox::host_funcs::FunctionRegistry; -use crate::sandbox::mem_access::handle_mem_access; use crate::sandbox::mem_mgr::MemMgrWrapper; cfg_if::cfg_if! { @@ -148,7 +144,7 @@ pub(crate) trait Hypervisor: Debug + Send { mem_mgr: MemMgrWrapper, host_funcs: Arc>, guest_max_log_level: Option, - #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()>; /// Map a region of host memory into the sandbox. @@ -175,7 +171,7 @@ pub(crate) trait Hypervisor: Debug + Send { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()>; /// Handle an IO exit from the internally stored vCPU. @@ -240,7 +236,7 @@ pub(crate) trait Hypervisor: Debug + Send { /// handles the cases when the vCPU stops due to a Debug event fn handle_debug( &mut self, - _dbg_mem_access_fn: Arc>, + _dbg_mem_access_fn: Arc>>, _stop_reason: VcpuStopReason, ) -> Result<()> { unimplemented!() @@ -293,7 +289,7 @@ impl VirtualCPU { #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] pub(crate) fn run( hv: &mut dyn Hypervisor, - #[cfg(gdb)] dbg_mem_access_fn: Arc>, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()> { loop { match hv.run() { @@ -314,7 +310,9 @@ impl VirtualCPU { #[cfg(crashdump)] crashdump::generate_crashdump(hv)?; - handle_mem_access(hv)?; + if !hv.check_stack_guard()? { + log_then_return!(StackOverflow()); + } log_then_return!("MMIO access address {:#x}", addr); } @@ -544,8 +542,6 @@ pub(crate) mod tests { use crate::mem::ptr::RawPtr; use crate::sandbox::host_funcs::FunctionRegistry; - #[cfg(gdb)] - use crate::sandbox::mem_access::dbg_mem_access_handler_wrapper; let filename = dummy_guest_as_string().map_err(|e| new_error!("{}", e))?; @@ -571,7 +567,7 @@ pub(crate) mod tests { let guest_max_log_level = Some(log::LevelFilter::Error); #[cfg(gdb)] - let dbg_mem_access_fn = dbg_mem_access_handler_wrapper(mem_mgr.clone()); + let dbg_mem_access_fn = Arc::new(Mutex::new(mem_mgr.clone())); // Test the initialise method vm.initialise( diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index ecc650c99..40464e328 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -33,12 +33,10 @@ use tracing::{Span, instrument}; use super::host_funcs::FunctionRegistry; use super::snapshot::Snapshot; -use super::{Callable, MemMgrWrapper, WrapperGetter}; +use super::{Callable, WrapperGetter}; use crate::HyperlightError::SnapshotSandboxMismatch; use crate::func::guest_err::check_for_guest_error; use crate::func::{ParameterTuple, SupportedReturnType}; -#[cfg(gdb)] -use crate::hypervisor::handlers::DbgMemAccessHandlerWrapper; use crate::hypervisor::{Hypervisor, InterruptHandle}; #[cfg(unix)] use crate::mem::memory_region::MemoryRegionType; @@ -46,6 +44,7 @@ use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::RawPtr; use crate::mem::shared_mem::HostSharedMemory; use crate::metrics::maybe_time_and_emit_guest_call; +use crate::sandbox::mem_mgr::MemMgrWrapper; use crate::{Result, log_then_return}; /// Global counter for assigning unique IDs to sandboxes @@ -64,7 +63,7 @@ pub struct MultiUseSandbox { vm: Box, dispatch_ptr: RawPtr, #[cfg(gdb)] - dbg_mem_access_fn: DbgMemAccessHandlerWrapper, + dbg_mem_access_fn: Arc>>, /// If the current state of the sandbox has been captured in a snapshot, /// that snapshot is stored here. snapshot: Option, @@ -82,7 +81,7 @@ impl MultiUseSandbox { mgr: MemMgrWrapper, vm: Box, dispatch_ptr: RawPtr, - #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> MultiUseSandbox { Self { id: SANDBOX_ID_COUNTER.fetch_add(1, Ordering::Relaxed), diff --git a/src/hyperlight_host/src/sandbox/mem_access.rs b/src/hyperlight_host/src/sandbox/mem_access.rs deleted file mode 100644 index e9de96e99..000000000 --- a/src/hyperlight_host/src/sandbox/mem_access.rs +++ /dev/null @@ -1,78 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -#[cfg(gdb)] -use std::sync::{Arc, Mutex}; - -use tracing::{Span, instrument}; - -#[cfg(gdb)] -use super::mem_mgr::MemMgrWrapper; -use crate::error::HyperlightError::StackOverflow; -use crate::hypervisor::Hypervisor; -#[cfg(gdb)] -use crate::hypervisor::handlers::{DbgMemAccessHandlerCaller, DbgMemAccessHandlerWrapper}; -#[cfg(gdb)] -use crate::mem::shared_mem::HostSharedMemory; -use crate::{Result, log_then_return}; - -#[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] -pub(crate) fn handle_mem_access(hv: &dyn Hypervisor) -> Result<()> { - if !hv.check_stack_guard()? { - log_then_return!(StackOverflow()); - } - - Ok(()) -} - -#[cfg(gdb)] -struct DbgMemAccessContainer { - wrapper: MemMgrWrapper, -} - -#[cfg(gdb)] -impl DbgMemAccessHandlerCaller for DbgMemAccessContainer { - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - fn read(&mut self, addr: usize, data: &mut [u8]) -> Result<()> { - self.wrapper - .unwrap_mgr_mut() - .get_shared_mem_mut() - .copy_to_slice(data, addr) - } - - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - fn write(&mut self, addr: usize, data: &[u8]) -> Result<()> { - self.wrapper - .unwrap_mgr_mut() - .get_shared_mem_mut() - .copy_from_slice(data, addr) - } - - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - fn get_code_offset(&mut self) -> Result { - Ok(self.wrapper.unwrap_mgr().layout.get_guest_code_address()) - } -} - -#[cfg(gdb)] -#[instrument(skip_all, parent = Span::current(), level= "Trace")] -pub(crate) fn dbg_mem_access_handler_wrapper( - wrapper: MemMgrWrapper, -) -> DbgMemAccessHandlerWrapper { - let container = DbgMemAccessContainer { wrapper }; - - Arc::new(Mutex::new(container)) -} diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index 5b367cb6f..b3f54e738 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -23,9 +23,6 @@ pub(crate) mod hypervisor; /// Functionality for dealing with initialized sandboxes that can /// call 0 or more guest functions pub mod initialized_multi_use; -/// Functionality for dealing with memory access from the VM guest -/// executable -pub(crate) mod mem_access; /// Functionality for interacting with a sandbox's internally-stored /// `SandboxMemoryManager` pub(crate) mod mem_mgr; diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index 5db2722ef..dc84c97a3 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -21,8 +21,6 @@ use tracing::{Span, instrument}; use super::SandboxConfiguration; use super::hypervisor::{HypervisorType, get_available_hypervisor}; -#[cfg(gdb)] -use super::mem_access::dbg_mem_access_handler_wrapper; #[cfg(any(crashdump, gdb))] use super::uninitialized::SandboxRuntimeConfig; use crate::HyperlightError::NoHypervisorFound; @@ -90,7 +88,7 @@ where let page_size = u32::try_from(page_size::get())?; #[cfg(gdb)] - let dbg_mem_access_hdl = dbg_mem_access_handler_wrapper(hshm.clone()); + let dbg_mem_access_hdl = Arc::new(Mutex::new(hshm.clone())); #[cfg(target_os = "linux")] setup_signal_handlers(&u_sbox.config)?; @@ -123,7 +121,7 @@ where pub(super) fn evolve_impl_multi_use(u_sbox: UninitializedSandbox) -> Result { evolve_impl(u_sbox, |hf, hshm, vm, dispatch_ptr| { #[cfg(gdb)] - let dbg_mem_wrapper = dbg_mem_access_handler_wrapper(hshm.clone()); + let dbg_mem_wrapper = Arc::new(Mutex::new(hshm.clone())); Ok(MultiUseSandbox::from_uninit( hf, hshm, From 058a4de40035d19111683e2230d9e02f5ca3c547 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Thu, 28 Aug 2025 09:42:34 -0700 Subject: [PATCH 130/271] Fix panic hook leaking after each new sandbox (#827) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- .../src/signal_handlers/mod.rs | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/hyperlight_host/src/signal_handlers/mod.rs b/src/hyperlight_host/src/signal_handlers/mod.rs index db52035d5..1644a7206 100644 --- a/src/hyperlight_host/src/signal_handlers/mod.rs +++ b/src/hyperlight_host/src/signal_handlers/mod.rs @@ -29,26 +29,31 @@ pub(crate) fn setup_signal_handlers(config: &SandboxConfiguration) -> crate::Res // should be safe to call. #[cfg(feature = "seccomp")] { + use std::sync::Once; + vmm_sys_util::signal::register_signal_handler( libc::SIGSYS, sigsys_signal_handler::handle_sigsys, ) .map_err(crate::HyperlightError::VmmSysError)?; - let original_hook = std::panic::take_hook(); - // Set a custom panic hook that checks for "DisallowedSyscall" - std::panic::set_hook(Box::new(move |panic_info| { - // Check if the panic payload matches "DisallowedSyscall" - if let Some(crate::HyperlightError::DisallowedSyscall) = panic_info - .payload() - .downcast_ref::( - ) { - // Do nothing to avoid superfluous syscalls - return; - } - // If not "DisallowedSyscall", use the original hook - original_hook(panic_info); - })); + static PANIC_HOOK_INIT: Once = Once::new(); + PANIC_HOOK_INIT.call_once(|| { + let original_hook = std::panic::take_hook(); + // Set a custom panic hook that checks for "DisallowedSyscall" + std::panic::set_hook(Box::new(move |panic_info| { + // Check if the panic payload matches "DisallowedSyscall" + if let Some(crate::HyperlightError::DisallowedSyscall) = panic_info + .payload() + .downcast_ref::( + ) { + // Do nothing to avoid superfluous syscalls + return; + } + // If not "DisallowedSyscall", use the original hook + original_hook(panic_info); + })); + }); } vmm_sys_util::signal::register_signal_handler( libc::SIGRTMIN() + config.get_interrupt_vcpu_sigrtmin_offset() as c_int, From 16fabd4e2c29ed4dc405483a1f77c9d22bc7e3c9 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 28 Aug 2025 21:12:01 +0100 Subject: [PATCH 131/271] Update the like-ci recipe (#837) Signed-off-by: Simon Davies --- Justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Justfile b/Justfile index c364937e7..216dc30d3 100644 --- a/Justfile +++ b/Justfile @@ -140,7 +140,7 @@ like-ci config=default-target hypervisor="kvm": {{ if os() == "linux" { "just test-rust-tracing " + config + " " + if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } } else { "" } }} @# Run benchmarks - just bench-ci main {{config}} {{ if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } }} + {{ if config == "release" { "just bench-ci main " + config + " " + if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } } else { "" } }} # runs all tests test target=default-target features="": (test-unit target features) (test-isolated target features) (test-integration "rust" target features) (test-integration "c" target features) (test-seccomp target features) (test-doc target features) From a835ef587bb4d9e201fab0b2e8726f2109d3af52 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Thu, 28 Aug 2025 15:02:37 -0700 Subject: [PATCH 132/271] Fix fuzz_host_call target by (#840) 1. Setting sandbox snapshot to none in call_type_erased_guest_function_by_name 2. Restoring to an initial snapshot on each fuzzing iteration to avoid hitting a known memory leak. Signed-off-by: adamperlin --- fuzz/fuzz_targets/host_call.rs | 33 ++++++++++++++++--- .../src/sandbox/initialized_multi_use.rs | 2 ++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/fuzz/fuzz_targets/host_call.rs b/fuzz/fuzz_targets/host_call.rs index 5c72a98e5..8011c7314 100644 --- a/fuzz/fuzz_targets/host_call.rs +++ b/fuzz/fuzz_targets/host_call.rs @@ -19,34 +19,57 @@ limitations under the License. use std::sync::{Mutex, OnceLock}; use hyperlight_host::func::{ParameterValue, ReturnType}; +use hyperlight_host::sandbox::SandboxConfiguration; +use hyperlight_host::sandbox::snapshot::Snapshot; use hyperlight_host::sandbox::uninitialized::GuestBinary; use hyperlight_host::{HyperlightError, MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::simple_guest_for_fuzzing_as_string; use libfuzzer_sys::fuzz_target; + +// TODO: this SNAPSHOT is needed because of the memory leak in: https://github.com/hyperlight-dev/hyperlight/issues/826 +// This should be removed once the leak is fixed +static SNAPSHOT: OnceLock> = OnceLock::new(); static SANDBOX: OnceLock> = OnceLock::new(); // This fuzz target tests all combinations of ReturnType and Parameters for `call_guest_function_by_name`. // For fuzzing efficiency, we create one Sandbox and reuse it for all fuzzing iterations. fuzz_target!( init: { + let mut cfg = SandboxConfiguration::default(); + cfg.set_output_data_size(64 * 1024); // 64 KB output buffer + cfg.set_input_data_size(64 * 1024); // 64 KB input buffer let u_sbox = UninitializedSandbox::new( GuestBinary::FilePath(simple_guest_for_fuzzing_as_string().expect("Guest Binary Missing")), - None + Some(cfg) ) .unwrap(); - let mu_sbox: MultiUseSandbox = u_sbox.evolve().unwrap(); + let mut mu_sbox: MultiUseSandbox = u_sbox.evolve().unwrap(); + let snapshot = mu_sbox.snapshot().unwrap(); SANDBOX.set(Mutex::new(mu_sbox)).unwrap(); + SNAPSHOT.set(Mutex::new(snapshot)).map_err(|_| "Snapshot already set").unwrap(); }, |data: (String, ReturnType, Vec)| { let (host_func_name, host_func_return, mut host_func_params) = data; let mut sandbox = SANDBOX.get().unwrap().lock().unwrap(); + let snapshot = SNAPSHOT.get().unwrap().lock().unwrap(); + sandbox.restore(&snapshot).unwrap(); + host_func_params.insert(0, ParameterValue::String(host_func_name)); match sandbox.call_type_erased_guest_function_by_name("FuzzHostFunc", host_func_return, host_func_params) { - Err(HyperlightError::GuestAborted(_, message)) if !message.contains("Host Function Not Found") => { - // We don't allow GuestAborted errors, except for the "Host Function Not Found" case - panic!("Guest Aborted: {}", message); + Err(e) => { + match e { + // the following are expected errors and occur frequently since + // we are randomly generating the function name and parameters + // to call with. + HyperlightError::HostFunctionNotFound(_) => {} + HyperlightError::UnexpectedNoOfArguments(_, _) => {}, + HyperlightError::ParameterValueConversionFailure(_, _) => {}, + + // any other error should be reported + _ => panic!("Guest Aborted with Unexpected Error: {:?}", e), + } } _ => {} } diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 40464e328..82a920158 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -381,6 +381,8 @@ impl MultiUseSandbox { ret_type: ReturnType, args: Vec, ) -> Result { + // Reset snapshot since we are mutating the sandbox state + self.snapshot = None; maybe_time_and_emit_guest_call(func_name, || { self.call_guest_function_by_name_no_reset(func_name, ret_type, args) }) From 828a529a054ae865efb7a5f480c897bb32cf800d Mon Sep 17 00:00:00 2001 From: syntactically <168595099+syntactically@users.noreply.github.com> Date: Thu, 28 Aug 2025 23:03:03 +0100 Subject: [PATCH 133/271] Make the component macros support passing host resources to guests (#839) --- Justfile | 2 +- flake.nix | 5 ++ src/hyperlight_component_util/src/emit.rs | 57 +++++++++++++-- src/hyperlight_component_util/src/guest.rs | 11 +-- src/hyperlight_component_util/src/hl.rs | 78 +++++++++++++++------ src/hyperlight_component_util/src/host.rs | 12 +++- src/hyperlight_component_util/src/rtypes.rs | 19 +++-- src/hyperlight_host/tests/wit_test.rs | 46 +++++++++--- src/tests/rust_guests/witguest/Cargo.lock | 1 + src/tests/rust_guests/witguest/Cargo.toml | 1 + src/tests/rust_guests/witguest/guest.wit | 10 ++- src/tests/rust_guests/witguest/src/main.rs | 44 ++++++++++-- 12 files changed, 226 insertions(+), 60 deletions(-) diff --git a/Justfile b/Justfile index 216dc30d3..aed82725d 100644 --- a/Justfile +++ b/Justfile @@ -140,7 +140,7 @@ like-ci config=default-target hypervisor="kvm": {{ if os() == "linux" { "just test-rust-tracing " + config + " " + if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } } else { "" } }} @# Run benchmarks - {{ if config == "release" { "just bench-ci main " + config + " " + if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } } else { "" } }} + {{ if config == "release" { "just bench-ci main " + if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } } else { "" } }} # runs all tests test target=default-target features="": (test-unit target features) (test-isolated target features) (test-integration "rust" target features) (test-integration "c" target features) (test-seccomp target features) (test-doc target features) diff --git a/flake.nix b/flake.nix index 47cd32fcb..fb6de20dd 100644 --- a/flake.nix +++ b/flake.nix @@ -59,6 +59,11 @@ channel = "stable"; sha256 = "sha256-AJ6LX/Q/Er9kS15bn9iflkUwcgYqRQxiOIL2ToVAXaU="; }; + "1.86" = { + date = "2025-04-03"; + channel = "stable"; + sha256 = "sha256-X/4ZBHO3iW0fOenQ3foEvscgAPJYl2abspaBThDOukI="; + }; }; rust-platform = makeRustPlatform { diff --git a/src/hyperlight_component_util/src/emit.rs b/src/hyperlight_component_util/src/emit.rs index d075f973b..2cd14c9df 100644 --- a/src/hyperlight_component_util/src/emit.rs +++ b/src/hyperlight_component_util/src/emit.rs @@ -196,6 +196,28 @@ impl Mod { } } +/// Unlike [`tv::ResolvedTyvar`], which is mostly concerned with free +/// variables and leaves bound variables alone, this tells us the most +/// information that we have at codegen time for a top level bound +/// variable. +pub enum ResolvedBoundVar<'a> { + Definite { + /// The final variable offset (relative to s.var_offset) that + /// we followed to get to this definite type, used + /// occasionally to name things. + final_bound_var: u32, + /// The actual definite type that this resolved to + ty: Defined<'a>, + }, + Resource { + /// A resource-type index. Currently a resource-type index is + /// the same as the de Bruijn index of the tyvar that + /// introduced the resource type, but is never affected by + /// e.g. s.var_offset. + rtidx: u32, + }, +} + /// A whole grab-bag of useful state to have while emitting Rust #[derive(Debug)] pub struct State<'a, 'b> { @@ -260,6 +282,8 @@ pub struct State<'a, 'b> { /// wasmtime guest emit. When that is refactored to use the host /// guest emit, this can go away. pub is_wasmtime_guest: bool, + /// Are we working on an export or an import of the component type? + pub is_export: bool, } /// Create a State with all of its &mut references pointing to @@ -311,6 +335,7 @@ impl<'a, 'b> State<'a, 'b> { root_component_name: None, is_guest, is_wasmtime_guest, + is_export: false, } } pub fn clone<'c>(&'c mut self) -> State<'c, 'b> { @@ -331,6 +356,7 @@ impl<'a, 'b> State<'a, 'b> { root_component_name: self.root_component_name.clone(), is_guest: self.is_guest, is_wasmtime_guest: self.is_wasmtime_guest, + is_export: self.is_export, } } /// Obtain a reference to the [`Mod`] that we are currently @@ -508,9 +534,17 @@ impl<'a, 'b> State<'a, 'b> { } /// Add an import/export to [`State::origin`], reflecting that we are now /// looking at code underneath it - pub fn push_origin<'c>(&'c mut self, is_export: bool, name: &'b str) -> State<'c, 'b> { + /// + /// origin_was_export differs from s.is_export in that s.is_export + /// keeps track of whether the item overall was imported or exported + /// from the root component (taking into account positivity), whereas + /// origin_was_export just checks if this particular extern_decl was + /// imported or exported from its parent instance (and so e.g. an + /// export of an instance that is imported by the root component has + /// !s.is_export && origin_was_export) + pub fn push_origin<'c>(&'c mut self, origin_was_export: bool, name: &'b str) -> State<'c, 'b> { let mut s = self.clone(); - s.origin.push(if is_export { + s.origin.push(if origin_was_export { ImportExport::Export(name) } else { ImportExport::Import(name) @@ -588,15 +622,24 @@ impl<'a, 'b> State<'a, 'b> { /// up with a definition, in which case, let's get that, or it /// ends up with a resource type, in which case we return the /// resource index - pub fn resolve_tv(&self, n: u32) -> (u32, Option>) { - match &self.bound_vars[self.var_offset + n as usize].bound { + /// + /// Distinct from [`Ctx::resolve_tv`], which is mostly concerned + /// with free variables, because this is concerned entirely with + /// bound variables. + pub fn resolve_bound_var(&self, n: u32) -> ResolvedBoundVar<'b> { + let noff = self.var_offset as u32 + n; + match &self.bound_vars[noff as usize].bound { TypeBound::Eq(Defined::Handleable(Handleable::Var(Tyvar::Bound(nn)))) => { - self.resolve_tv(n + 1 + nn) + self.resolve_bound_var(n + 1 + nn) } - TypeBound::Eq(t) => (n, Some(t.clone())), - TypeBound::SubResource => (n, None), + TypeBound::Eq(t) => ResolvedBoundVar::Definite { + final_bound_var: n, + ty: t.clone(), + }, + TypeBound::SubResource => ResolvedBoundVar::Resource { rtidx: noff }, } } + /// Construct a namespace path referring to the resource trait for /// a resource with the given name pub fn resource_trait_path(&self, r: Ident) -> Vec { diff --git a/src/hyperlight_component_util/src/guest.rs b/src/hyperlight_component_util/src/guest.rs index 864f9cd0f..09e909034 100644 --- a/src/hyperlight_component_util/src/guest.rs +++ b/src/hyperlight_component_util/src/guest.rs @@ -18,8 +18,9 @@ use proc_macro2::TokenStream; use quote::{format_ident, quote}; use crate::emit::{ - FnName, ResourceItemName, State, WitName, kebab_to_exports_name, kebab_to_fn, kebab_to_getter, - kebab_to_imports_name, kebab_to_namespace, kebab_to_type, kebab_to_var, split_wit_name, + FnName, ResolvedBoundVar, ResourceItemName, State, WitName, kebab_to_exports_name, kebab_to_fn, + kebab_to_getter, kebab_to_imports_name, kebab_to_namespace, kebab_to_type, kebab_to_var, + split_wit_name, }; use crate::etypes::{Component, Defined, ExternDecl, ExternDesc, Handleable, Instance, Tyvar}; use crate::hl::{ @@ -98,10 +99,10 @@ fn emit_import_extern_decl<'a, 'b, 'c>( ExternDesc::Type(t) => match t { Defined::Handleable(Handleable::Var(Tyvar::Bound(b))) => { // only resources need something emitted - let (b, None) = s.resolve_tv(*b) else { + let ResolvedBoundVar::Resource { rtidx } = s.resolve_bound_var(*b) else { return quote! {}; }; - let rtid = format_ident!("HostResource{}", s.var_offset + b as usize); + let rtid = format_ident!("HostResource{}", rtidx as usize); let path = s.resource_trait_path(kebab_to_type(ed.kebab_name)); s.root_mod .r#impl(path, format_ident!("Host")) @@ -314,6 +315,8 @@ fn emit_component<'a, 'b, 'c>( s.var_offset = 0; + s.is_export = true; + let exports = ct .instance .unqualified diff --git a/src/hyperlight_component_util/src/hl.rs b/src/hyperlight_component_util/src/hl.rs index 719262f6e..d58eb7aaf 100644 --- a/src/hyperlight_component_util/src/hl.rs +++ b/src/hyperlight_component_util/src/hl.rs @@ -18,8 +18,8 @@ use itertools::Itertools; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; -use crate::emit::{State, kebab_to_cons, kebab_to_var}; -use crate::etypes::{self, Defined, Handleable, TypeBound, Tyvar, Value}; +use crate::emit::{ResolvedBoundVar, State, kebab_to_cons, kebab_to_var}; +use crate::etypes::{self, Defined, Handleable, Tyvar, Value}; use crate::rtypes; /// Construct a string that can be used "on the wire" to identify a @@ -151,25 +151,16 @@ pub fn emit_hl_unmarshal_toplevel_value( } } -/// Find the resource index that the given type variable refers to. -/// -/// Precondition: this type variable does refer to a resource type -fn resolve_tyvar_to_resource(s: &mut State, v: u32) -> u32 { - match s.bound_vars[v as usize].bound { - TypeBound::SubResource => v, - TypeBound::Eq(Defined::Handleable(Handleable::Var(Tyvar::Bound(vv)))) => { - resolve_tyvar_to_resource(s, v + vv + 1) - } - _ => panic!("impossible: resource var is not resource"), - } -} /// Find the resource index that the given Handleable refers to. /// /// Precondition: this type variable does refer to a resource type pub fn resolve_handleable_to_resource(s: &mut State, ht: &Handleable) -> u32 { match ht { Handleable::Var(Tyvar::Bound(vi)) => { - resolve_tyvar_to_resource(s, s.var_offset as u32 + *vi) + let ResolvedBoundVar::Resource { rtidx } = s.resolve_bound_var(*vi) else { + panic!("impossible: resource var is not resource"); + }; + rtidx } _ => panic!("impossible handleable in type"), } @@ -338,9 +329,29 @@ pub fn emit_hl_unmarshal_value(s: &mut State, id: Ident, vt: &Value) -> TokenStr log::debug!("resolved ht to r (2) {:?} {:?}", ht, vi); if s.is_guest { let rid = format_ident!("HostResource{}", vi); - quote! { - let i = u32::from_ne_bytes(#id[0..4].try_into().unwrap()); - (::wasmtime::component::Resource::<#rid>::new_borrow(i), 4) + if s.is_wasmtime_guest { + quote! { + let i = u32::from_ne_bytes(#id[0..4].try_into().unwrap()); + (::wasmtime::component::Resource::<#rid>::new_borrow(i), 4) + } + } else { + // TODO: When we add the Drop impl (#810), we need + // to make sure it does not get called here + // + // If we tried to actually return a reference + // here, rustc would get mad about the temporary + // constructed here not living long enough, so + // instead we return the temporary and construct + // the reference elsewhere. It might be a bit more + // principled to have a separate + // HostResourceXXBorrow struct that implements + // AsRef or something in the + // future... + quote! { + let i = u32::from_ne_bytes(#id[0..4].try_into().unwrap()); + + (#rid { rep: i }, 4) + } } } else { let rid = format_ident!("resource{}", vi); @@ -358,7 +369,11 @@ pub fn emit_hl_unmarshal_value(s: &mut State, id: Ident, vt: &Value) -> TokenStr let Some(Tyvar::Bound(n)) = tv else { panic!("impossible tyvar") }; - let (n, Some(Defined::Value(vt))) = s.resolve_tv(*n) else { + let ResolvedBoundVar::Definite { + final_bound_var: n, + ty: Defined::Value(vt), + } = s.resolve_bound_var(*n) + else { panic!("unresolvable tyvar (2)"); }; let vt = vt.clone(); @@ -644,7 +659,9 @@ pub fn emit_hl_marshal_value(s: &mut State, id: Ident, vt: &Value) -> TokenStrea let rid = format_ident!("resource{}", vi); quote! { let i = rts.#rid.len(); - rts.#rid.push_back(::hyperlight_common::resource::ResourceEntry::lend(#id)); + let (lrg, re) = ::hyperlight_common::resource::ResourceEntry::lend(#id); + to_cleanup.push(Box::new(lrg)); + rts.#rid.push_back(re); alloc::vec::Vec::from(u32::to_ne_bytes(i as u32)) } } @@ -653,7 +670,11 @@ pub fn emit_hl_marshal_value(s: &mut State, id: Ident, vt: &Value) -> TokenStrea let Some(Tyvar::Bound(n)) = tv else { panic!("impossible tyvar") }; - let (n, Some(Defined::Value(vt))) = s.resolve_tv(*n) else { + let ResolvedBoundVar::Definite { + final_bound_var: n, + ty: Defined::Value(vt), + } = s.resolve_bound_var(*n) + else { panic!("unresolvable tyvar (2)"); }; let vt = vt.clone(); @@ -668,7 +689,20 @@ pub fn emit_hl_marshal_value(s: &mut State, id: Ident, vt: &Value) -> TokenStrea /// [`crate::rtypes`] module) of the given value type. pub fn emit_hl_unmarshal_param(s: &mut State, id: Ident, pt: &Value) -> TokenStream { let toks = emit_hl_unmarshal_value(s, id, pt); - quote! { { #toks }.0 } + // Slight hack to avoid rust complaints about deserialised + // resource borrow lifetimes. + fn is_borrow(vt: &Value) -> bool { + match vt { + Value::Borrow(_) => true, + Value::Var(_, vt) => is_borrow(vt), + _ => false, + } + } + if s.is_guest && !s.is_wasmtime_guest && is_borrow(pt) { + quote! { &({ #toks }.0) } + } else { + quote! { { #toks }.0 } + } } /// Emit code to unmarshal the result of a function with result type diff --git a/src/hyperlight_component_util/src/host.rs b/src/hyperlight_component_util/src/host.rs index b8a194dd2..0f6bca65b 100644 --- a/src/hyperlight_component_util/src/host.rs +++ b/src/hyperlight_component_util/src/host.rs @@ -56,12 +56,20 @@ fn emit_export_extern_decl<'a, 'b, 'c>( let unmarshal = emit_hl_unmarshal_result(s, ret.clone(), &ft.result); quote! { fn #n(&mut self, #(#param_decls),*) -> #result_decl { + let mut to_cleanup = Vec::>::new(); + let marshalled = { + let mut rts = self.rt.lock().unwrap(); + #[allow(clippy::unused_unit)] + (#(#marshal,)*) + }; let #ret = ::hyperlight_host::sandbox::Callable::call::<::std::vec::Vec::>(&mut self.sb, #hln, - (#(#marshal,)*) + marshalled, ); let ::std::result::Result::Ok(#ret) = #ret else { panic!("bad return from guest {:?}", #ret) }; #[allow(clippy::unused_unit)] + let mut rts = self.rt.lock().unwrap(); + #[allow(clippy::unused_unit)] #unmarshal } } @@ -333,6 +341,8 @@ fn emit_component<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, ct: &'c Com s.root_component_name = Some((ns.clone(), wn.name)); s.cur_trait = Some(export_trait.clone()); s.import_param_var = Some(format_ident!("I")); + s.is_export = true; + let exports = ct .instance .unqualified diff --git a/src/hyperlight_component_util/src/rtypes.rs b/src/hyperlight_component_util/src/rtypes.rs index e9b8ded61..18665db31 100644 --- a/src/hyperlight_component_util/src/rtypes.rs +++ b/src/hyperlight_component_util/src/rtypes.rs @@ -345,7 +345,11 @@ pub fn emit_value(s: &mut State, vt: &Value) -> TokenStream { } } else { let vr = emit_var_ref(s, tv); - quote! { ::hyperlight_common::resource::BorrowedResourceGuard<#vr> } + if s.is_export { + quote! { &#vr } + } else { + quote! { ::hyperlight_common::resource::BorrowedResourceGuard<#vr> } + } } } }, @@ -607,8 +611,11 @@ fn emit_type_alias TokenStream>( /// Emit (via returning) a Rust trait item corresponding to this /// extern decl +/// +/// See note on emit.rs push_origin for the difference between +/// origin_was_export and s.is_export. fn emit_extern_decl<'a, 'b, 'c>( - is_export: bool, + origin_was_export: bool, s: &'c mut State<'a, 'b>, ed: &'c ExternDecl<'b>, ) -> TokenStream { @@ -616,7 +623,7 @@ fn emit_extern_decl<'a, 'b, 'c>( match &ed.desc { ExternDesc::CoreModule(_) => panic!("core module (im/ex)ports are not supported"), ExternDesc::Func(ft) => { - let mut s = s.push_origin(is_export, ed.kebab_name); + let mut s = s.push_origin(origin_was_export, ed.kebab_name); match kebab_to_fn(ed.kebab_name) { FnName::Plain(n) => { let params = ft @@ -681,7 +688,7 @@ fn emit_extern_decl<'a, 'b, 'c>( TokenStream::new() } let edn: &'b str = ed.kebab_name; - let mut s: State<'_, 'b> = s.push_origin(is_export, edn); + let mut s: State<'_, 'b> = s.push_origin(origin_was_export, edn); if let Some((n, bound)) = s.is_var_defn(t) { match bound { TypeBound::Eq(t) => { @@ -708,7 +715,7 @@ fn emit_extern_decl<'a, 'b, 'c>( } } ExternDesc::Instance(it) => { - let mut s = s.push_origin(is_export, ed.kebab_name); + let mut s = s.push_origin(origin_was_export, ed.kebab_name); let wn = split_wit_name(ed.kebab_name); emit_instance(&mut s, wn.clone(), it); @@ -831,8 +838,8 @@ fn emit_component<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, ct: &'c Com s.cur_trait().items.extend(quote! { #(#imports)* }); s.adjust_vars(ct.instance.evars.len() as u32); - s.import_param_var = Some(format_ident!("I")); + s.is_export = true; let export_name = kebab_to_exports_name(wn.name); *s.bound_vars = ct diff --git a/src/hyperlight_host/tests/wit_test.rs b/src/hyperlight_host/tests/wit_test.rs index 8a12e1433..e47faf6da 100644 --- a/src/hyperlight_host/tests/wit_test.rs +++ b/src/hyperlight_host/tests/wit_test.rs @@ -206,12 +206,21 @@ struct TestResource { x: String, last: char, } +impl TestResource { + fn new(x: String, last: char) -> Arc> { + Arc::new(Mutex::new(TestResource { + n_calls: 0, + x, + last, + })) + } +} use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering::Relaxed; -// We only have 1 test that uses this, and it isn't a proptest or -// anything, so it should only run once. If multiple tests using this -// could run in parallel, there would be problems. +// We use some care below in the tests that use HAS_BEEN_DROPPED to +// synchronise on this mutex to avoid them stepping on each other +static SERIALIZE_TEST_RESOURCE_TESTS: Mutex<()> = Mutex::new(()); static HAS_BEEN_DROPPED: AtomicBool = AtomicBool::new(false); impl Drop for TestResource { @@ -225,11 +234,7 @@ impl Drop for TestResource { impl test::wit::host_resource::Testresource for Host { type T = Arc>; fn new(&mut self, x: String, last: char) -> Self::T { - Arc::new(Mutex::new(TestResource { - n_calls: 0, - x, - last, - })) + TestResource::new(x, last) } fn append_char(&mut self, self_: BorrowedResourceGuard<'_, Self::T>, c: char) { let mut self_ = self_.lock().unwrap(); @@ -393,12 +398,31 @@ mod wit_test { sb().roundtrip().roundtrip_no_result(42); } + use std::sync::atomic::Ordering::Relaxed; + + #[test] + fn test_host_resource_uses_locally() { + let guard = crate::SERIALIZE_TEST_RESOURCE_TESTS.lock(); + crate::HAS_BEEN_DROPPED.store(false, Relaxed); + { + sb().test_host_resource().test_uses_locally(); + } + assert!(crate::HAS_BEEN_DROPPED.load(Relaxed)); + drop(guard); + } #[test] - fn test_host_resource() { + fn test_host_resource_passed_in_out() { + let guard = crate::SERIALIZE_TEST_RESOURCE_TESTS.lock(); + crate::HAS_BEEN_DROPPED.store(false, Relaxed); { - sb().test_host_resource().test(); + let mut sb = sb(); + let inst = sb.test_host_resource(); + let r = inst.test_makes(); + inst.test_accepts_borrow(&r); + inst.test_accepts_own(r); + inst.test_returns(); } - use std::sync::atomic::Ordering::Relaxed; assert!(crate::HAS_BEEN_DROPPED.load(Relaxed)); + drop(guard); } } diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index 9d018920a..5687337e0 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -620,4 +620,5 @@ dependencies = [ "hyperlight-component-macro", "hyperlight-guest", "hyperlight-guest-bin", + "spin 0.10.0", ] diff --git a/src/tests/rust_guests/witguest/Cargo.toml b/src/tests/rust_guests/witguest/Cargo.toml index 611b96b29..65762e639 100644 --- a/src/tests/rust_guests/witguest/Cargo.toml +++ b/src/tests/rust_guests/witguest/Cargo.toml @@ -8,6 +8,7 @@ hyperlight-guest = { path = "../../../hyperlight_guest" } hyperlight-guest-bin = { path = "../../../hyperlight_guest_bin" } hyperlight-common = { path = "../../../hyperlight_common", default-features = false } hyperlight-component-macro = { path = "../../../hyperlight_component_macro" } +spin = "0.10.0" [features] default = [] diff --git a/src/tests/rust_guests/witguest/guest.wit b/src/tests/rust_guests/witguest/guest.wit index d8f4c4a5f..9ed164b80 100644 --- a/src/tests/rust_guests/witguest/guest.wit +++ b/src/tests/rust_guests/witguest/guest.wit @@ -80,5 +80,13 @@ interface host-resource { } interface test-host-resource { - test: func() -> bool; + use host-resource.{testresource}; + + test-uses-locally: func() -> bool; + + test-makes: func() -> own; + + test-accepts-borrow: func(x: borrow); + test-accepts-own: func(x: own); + test-returns: func() -> own; } \ No newline at end of file diff --git a/src/tests/rust_guests/witguest/src/main.rs b/src/tests/rust_guests/witguest/src/main.rs index cef36b65d..307d9cca6 100644 --- a/src/tests/rust_guests/witguest/src/main.rs +++ b/src/tests/rust_guests/witguest/src/main.rs @@ -20,12 +20,16 @@ limitations under the License. extern crate alloc; extern crate hyperlight_guest; -mod bindings; use alloc::string::String; +use spin::Mutex; + +mod bindings; use bindings::*; -struct Guest {} +struct Guest { + host_resource: Option<::T>, +} impl test::wit::Roundtrip for Guest { fn roundtrip_bool(&mut self, x: bool) -> bool { @@ -162,11 +166,12 @@ impl test::wit::Roundtrip for Guest { } } -impl test::wit::TestHostResource for Guest { - fn test(&mut self) -> bool { - use test::wit::host_resource::Testresource; +use alloc::string::ToString; + +use test::wit::host_resource::Testresource; +impl test::wit::TestHostResource<::T> for Guest { + fn test_uses_locally(&mut self) -> bool { let mut host = Host {}; - use alloc::string::ToString; let r = ::new(&mut host, "str".to_string(), 'z'); ::append_char(&mut host, &r, 'a'); ::append_char(&mut host, &r, 'b'); @@ -176,6 +181,27 @@ impl test::wit::TestHostResource for Guest { ::return_own(&mut host, r); true } + fn test_makes(&mut self) -> ::T { + let mut host = Host {}; + ::new(&mut host, "str".to_string(), 'z') + } + fn test_accepts_borrow(&mut self, r: &::T) { + let mut host = Host {}; + ::append_char(&mut host, r, 'a'); + } + fn test_accepts_own(&mut self, r: ::T) { + let mut host = Host {}; + // TODO: add test about the old contents of this being + // dropped, when #810 is fixed. + ::append_char(&mut host, &r, 'b'); + self.host_resource = Some(r); + } + fn test_returns(&mut self) -> ::T { + let mut host = Host {}; + let r = self.host_resource.take().unwrap(); + ::append_char(&mut host, &r, 'c'); + r + } } #[allow(refining_impl_trait)] @@ -190,9 +216,13 @@ impl test::wit::TestExports for Guest { } } +static GUEST_STATE: Mutex = Mutex::new(Guest { + host_resource: None, +}); + impl bindings::Guest for Guest { fn with_guest_state R>(f: F) -> R { - let mut g = Guest {}; + let mut g = GUEST_STATE.lock(); f(&mut g) } } From 67d0addbc8044e21b10e0660934a5b32f38104bc Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 28 Aug 2025 23:24:29 +0100 Subject: [PATCH 134/271] UPdate changelog for release (#842) Signed-off-by: Simon Davies --- CHANGELOG.md | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f3aa1682..a774369a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Prerelease] - Unreleased +## [v0.9.0] - 2025-08-28 + +### Fixed + +- fix release blocker so it only blocks on release branches by @simongdavies in https://github.com/hyperlight-dev/hyperlight/pull/777 +- Enforce release builds for benchmarks and simplify command interface by @Copilot in https://github.com/hyperlight-dev/hyperlight/pull/741 +- fix(guest-bin): align user memory allocations by @andreiltd in https://github.com/hyperlight-dev/hyperlight/pull/753 +- Fix unbounded growth of panic hook after each new sandbox by @ludfjig in https://github.com/hyperlight-dev/hyperlight/pull/827 +- Update the like-ci recipe by @simongdavies in https://github.com/hyperlight-dev/hyperlight/pull/837 +- Fixes to Host Call Fuzzing by @adamperlin in https://github.com/hyperlight-dev/hyperlight/pull/840 + +### Changed + +- Optimize function call serializing by @ludfjig in https://github.com/hyperlight-dev/hyperlight/pull/778 +- Make the component macros support passing host resources to guests by @syntactically in https://github.com/hyperlight-dev/hyperlight/pull/839 +- Build c guests as required by benchmarks by @ludfjig in https://github.com/hyperlight-dev/hyperlight/pull/822 + +### Removed +- Remove DbgMemAccessHandlerCaller trait and DbgMemAccessHandlerWrapper abstractions by @Copilot in https://github.com/hyperlight-dev/hyperlight/pull/824 + ## [v0.8.0] - 2025-08-08 :warning: `hyperlight_component_macro::host_bindgen` and `hyperlight_component_macro::guest_bindgen` used the `Callable` trait which no longer restores state after each function call and requires an explicit Snapshot Restore using the newly exposed Snapshot API. See https://github.com/hyperlight-dev/hyperlight/pull/697 and https://github.com/hyperlight-dev/hyperlight/pull/761 @@ -168,7 +188,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). The Initial Hyperlight Release 🎉 -[Prerelease]: +[Prerelease]: +[v0.9.0]: +[v0.8.0]: +[v0.7.0]: +[v0.6.1]: +[v0.6.0]: +[v0.5.1]: +[v0.5.0]: [v0.4.0]: [v0.3.0]: [v0.2.0]: From 1bd07e17c95426c551aef3cd050a95a14eac8dad Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Fri, 29 Aug 2025 00:21:13 +0100 Subject: [PATCH 135/271] Update to v0.9.0 (#841) * Update to v0.9.0 Signed-off-by: Simon Davies * update cargo.lock Signed-off-by: Simon Davies --------- Signed-off-by: Simon Davies --- Cargo.lock | 41 +++++++++---------- Cargo.toml | 18 ++++---- .../rust_guests/callbackguest/Cargo.toml | 2 +- src/tests/rust_guests/dummyguest/Cargo.toml | 4 +- src/tests/rust_guests/simpleguest/Cargo.toml | 2 +- src/tests/rust_guests/witguest/Cargo.toml | 2 +- src/trace_dump/Cargo.toml | 2 +- 7 files changed, 34 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0bd280065..9770b25e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1078,7 +1078,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasi 0.14.3+wasi-0.2.4", ] [[package]] @@ -1344,7 +1344,7 @@ dependencies = [ [[package]] name = "hyperlight-common" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "arbitrary", @@ -1357,7 +1357,7 @@ dependencies = [ [[package]] name = "hyperlight-component-macro" -version = "0.8.0" +version = "0.9.0" dependencies = [ "env_logger", "hyperlight-component-util", @@ -1371,7 +1371,7 @@ dependencies = [ [[package]] name = "hyperlight-component-util" -version = "0.8.0" +version = "0.9.0" dependencies = [ "itertools 0.14.0", "log", @@ -1393,7 +1393,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "flatbuffers", @@ -1404,7 +1404,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.8.0" +version = "0.9.0" dependencies = [ "buddy_system_allocator", "cc", @@ -1419,7 +1419,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing" -version = "0.8.0" +version = "0.9.0" dependencies = [ "hyperlight-common", "hyperlight-guest-tracing-macro", @@ -1428,7 +1428,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing-macro" -version = "0.8.0" +version = "0.9.0" dependencies = [ "proc-macro2", "quote", @@ -1437,7 +1437,7 @@ dependencies = [ [[package]] name = "hyperlight-host" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "bitflags 2.9.3", @@ -1527,7 +1527,7 @@ dependencies = [ [[package]] name = "hyperlight_guest_capi" -version = "0.8.0" +version = "0.9.0" dependencies = [ "cbindgen", "hyperlight-common", @@ -2609,9 +2609,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" dependencies = [ "zerovec", ] @@ -3595,7 +3595,7 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "trace_dump" -version = "0.0.0" +version = "0.9.0" dependencies = [ "addr2line 0.25.0", "blake3", @@ -3955,11 +3955,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.14.3+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] @@ -4383,13 +4383,10 @@ dependencies = [ ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.3", -] +checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" [[package]] name = "writeable" diff --git a/Cargo.toml b/Cargo.toml index 9a6508cc2..d5f9a4092 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ exclude = [ ] [workspace.package] -version = "0.8.0" +version = "0.9.0" edition = "2024" rust-version = "1.86" license = "Apache-2.0" @@ -37,15 +37,15 @@ repository = "https://github.com/hyperlight-dev/hyperlight" readme = "README.md" [workspace.dependencies] -hyperlight-common = { path = "src/hyperlight_common", version = "0.8.0", default-features = false } -hyperlight-host = { path = "src/hyperlight_host", version = "0.8.0", default-features = false } -hyperlight-guest = { path = "src/hyperlight_guest", version = "0.8.0", default-features = false } -hyperlight-guest-bin = { path = "src/hyperlight_guest_bin", version = "0.8.0", default-features = false } +hyperlight-common = { path = "src/hyperlight_common", version = "0.9.0", default-features = false } +hyperlight-host = { path = "src/hyperlight_host", version = "0.9.0", default-features = false } +hyperlight-guest = { path = "src/hyperlight_guest", version = "0.9.0", default-features = false } +hyperlight-guest-bin = { path = "src/hyperlight_guest_bin", version = "0.9.0", default-features = false } hyperlight-testing = { path = "src/hyperlight_testing", default-features = false } -hyperlight-guest-tracing = { path = "src/hyperlight_guest_tracing", version = "0.8.0", default-features = false } -hyperlight-guest-tracing-macro = { path = "src/hyperlight_guest_tracing_macro", version = "0.8.0", default-features = false } -hyperlight-component-util = { path = "src/hyperlight_component_util", version = "0.8.0", default-features = false } -hyperlight-component-macro = { path = "src/hyperlight_component_macro", version = "0.8.0", default-features = false } +hyperlight-guest-tracing = { path = "src/hyperlight_guest_tracing", version = "0.9.0", default-features = false } +hyperlight-guest-tracing-macro = { path = "src/hyperlight_guest_tracing_macro", version = "0.9.0", default-features = false } +hyperlight-component-util = { path = "src/hyperlight_component_util", version = "0.9.0", default-features = false } +hyperlight-component-macro = { path = "src/hyperlight_component_macro", version = "0.9.0", default-features = false } [workspace.lints.rust] unsafe_op_in_unsafe_fn = "deny" diff --git a/src/tests/rust_guests/callbackguest/Cargo.toml b/src/tests/rust_guests/callbackguest/Cargo.toml index b1040eb5d..fdb6ddbb2 100644 --- a/src/tests/rust_guests/callbackguest/Cargo.toml +++ b/src/tests/rust_guests/callbackguest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "callbackguest" -version = "0.1.0" +version = "0.9.0" edition = "2021" [dependencies] diff --git a/src/tests/rust_guests/dummyguest/Cargo.toml b/src/tests/rust_guests/dummyguest/Cargo.toml index 3de8389e9..9a35944ec 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.toml +++ b/src/tests/rust_guests/dummyguest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dummyguest" -version = "0.4.0" +version = "0.9.0" edition = "2021" @@ -12,4 +12,4 @@ hyperlight-common = { path = "../../../hyperlight_common", default-features = fa default = [] trace_guest = ["hyperlight-guest-bin/trace_guest"] unwind_guest = ["hyperlight-common/unwind_guest"] -mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] \ No newline at end of file +mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] diff --git a/src/tests/rust_guests/simpleguest/Cargo.toml b/src/tests/rust_guests/simpleguest/Cargo.toml index 8748bdc0b..34925b9fc 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.toml +++ b/src/tests/rust_guests/simpleguest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "simpleguest" -version = "0.4.0" +version = "0.9.0" edition = "2021" [dependencies] diff --git a/src/tests/rust_guests/witguest/Cargo.toml b/src/tests/rust_guests/witguest/Cargo.toml index 65762e639..82f87b9f5 100644 --- a/src/tests/rust_guests/witguest/Cargo.toml +++ b/src/tests/rust_guests/witguest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "witguest" -version = "0.1.0" +version = "0.9.0" edition = "2021" [dependencies] diff --git a/src/trace_dump/Cargo.toml b/src/trace_dump/Cargo.toml index 9f3b0cbe6..94f408430 100644 --- a/src/trace_dump/Cargo.toml +++ b/src/trace_dump/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "trace_dump" -version = "0.0.0" +version = "0.9.0" publish = false edition = "2021" From 600c0cf44726efb06ef10d01a869a20b173cee70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Aug 2025 11:59:01 +0300 Subject: [PATCH 136/271] Bump crate-ci/typos from 1.35.5 to 1.35.6 (#843) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.35.5 to 1.35.6. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.35.5...v1.35.6) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.35.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ValidatePullRequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index d3b2c00af..d3c628546 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -65,7 +65,7 @@ jobs: steps: - uses: actions/checkout@v5 - name: Spell Check Repo - uses: crate-ci/typos@v1.35.5 + uses: crate-ci/typos@v1.35.6 license-headers: name: check license headers From c97feb6d8b4e06eb5c4c8b8c31ed4e41348fe595 Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Mon, 1 Sep 2025 15:30:07 +0100 Subject: [PATCH 137/271] bump cargo lock files of rust_guests (#846) Signed-off-by: Jorge Prendes --- src/tests/rust_guests/callbackguest/Cargo.lock | 12 ++++++------ src/tests/rust_guests/dummyguest/Cargo.lock | 12 ++++++------ src/tests/rust_guests/simpleguest/Cargo.lock | 12 ++++++------ src/tests/rust_guests/witguest/Cargo.lock | 16 ++++++++-------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/tests/rust_guests/callbackguest/Cargo.lock b/src/tests/rust_guests/callbackguest/Cargo.lock index 1d537c09c..fa07b3e56 100644 --- a/src/tests/rust_guests/callbackguest/Cargo.lock +++ b/src/tests/rust_guests/callbackguest/Cargo.lock @@ -31,7 +31,7 @@ dependencies = [ [[package]] name = "callbackguest" -version = "0.1.0" +version = "0.9.0" dependencies = [ "hyperlight-common", "hyperlight-guest", @@ -72,7 +72,7 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hyperlight-common" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "flatbuffers", @@ -82,7 +82,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "flatbuffers", @@ -93,7 +93,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.8.0" +version = "0.9.0" dependencies = [ "buddy_system_allocator", "cc", @@ -108,7 +108,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing" -version = "0.8.0" +version = "0.9.0" dependencies = [ "hyperlight-common", "hyperlight-guest-tracing-macro", @@ -117,7 +117,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing-macro" -version = "0.8.0" +version = "0.9.0" dependencies = [ "proc-macro2", "quote", diff --git a/src/tests/rust_guests/dummyguest/Cargo.lock b/src/tests/rust_guests/dummyguest/Cargo.lock index 77734d32c..e93ad50ef 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.lock +++ b/src/tests/rust_guests/dummyguest/Cargo.lock @@ -46,7 +46,7 @@ checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "dummyguest" -version = "0.4.0" +version = "0.9.0" dependencies = [ "hyperlight-common", "hyperlight-guest-bin", @@ -70,7 +70,7 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hyperlight-common" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "flatbuffers", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "flatbuffers", @@ -91,7 +91,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.8.0" +version = "0.9.0" dependencies = [ "buddy_system_allocator", "cc", @@ -106,7 +106,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing" -version = "0.8.0" +version = "0.9.0" dependencies = [ "hyperlight-common", "hyperlight-guest-tracing-macro", @@ -115,7 +115,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing-macro" -version = "0.8.0" +version = "0.9.0" dependencies = [ "proc-macro2", "quote", diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index 9a9f82278..1900d8955 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -62,7 +62,7 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hyperlight-common" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "flatbuffers", @@ -72,7 +72,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "flatbuffers", @@ -83,7 +83,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.8.0" +version = "0.9.0" dependencies = [ "buddy_system_allocator", "cc", @@ -98,7 +98,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing" -version = "0.8.0" +version = "0.9.0" dependencies = [ "hyperlight-common", "hyperlight-guest-tracing-macro", @@ -107,7 +107,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing-macro" -version = "0.8.0" +version = "0.9.0" dependencies = [ "proc-macro2", "quote", @@ -227,7 +227,7 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "simpleguest" -version = "0.4.0" +version = "0.9.0" dependencies = [ "hyperlight-common", "hyperlight-guest", diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index 5687337e0..8bf176fa6 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -178,7 +178,7 @@ dependencies = [ [[package]] name = "hyperlight-common" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "flatbuffers", @@ -188,7 +188,7 @@ dependencies = [ [[package]] name = "hyperlight-component-macro" -version = "0.8.0" +version = "0.9.0" dependencies = [ "env_logger", "hyperlight-component-util", @@ -202,7 +202,7 @@ dependencies = [ [[package]] name = "hyperlight-component-util" -version = "0.8.0" +version = "0.9.0" dependencies = [ "itertools", "log", @@ -215,7 +215,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "flatbuffers", @@ -226,7 +226,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.8.0" +version = "0.9.0" dependencies = [ "buddy_system_allocator", "cc", @@ -241,7 +241,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing" -version = "0.8.0" +version = "0.9.0" dependencies = [ "hyperlight-common", "hyperlight-guest-tracing-macro", @@ -250,7 +250,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing-macro" -version = "0.8.0" +version = "0.9.0" dependencies = [ "proc-macro2", "quote", @@ -614,7 +614,7 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "witguest" -version = "0.1.0" +version = "0.9.0" dependencies = [ "hyperlight-common", "hyperlight-component-macro", From 36d37679ae2169cca58c26856993bde425f3bddc Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Sep 2025 11:17:13 -0700 Subject: [PATCH 138/271] Add automatic issue creation for scheduled fuzzing job failures with area/fuzzing label filtering (#823) * Initial plan * Add fuzzing failure notification system - Created dev/notify-fuzzing-failure.sh script to handle GitHub issue creation/updates - Modified Fuzzing.yml and dep_fuzzing.yml workflows to add failure notifications - Added proper permissions for issue creation and comments - Script checks for existing open fuzzing failure issues and either creates new ones or adds comments - Includes robust error handling and test mode for validation Co-authored-by: jsturtevant <648372+jsturtevant@users.noreply.github.com> * Move fuzzing failure notification from reusable workflow to scheduled workflow - Removed notification step and issues permission from dep_fuzzing.yml (reusable workflow) - Added separate notify-failure job to Fuzzing.yml (scheduled workflow) - This ensures issues are only created for scheduled cron job failures, not PR runs Co-authored-by: jsturtevant <648372+jsturtevant@users.noreply.github.com> * Add --repo parameter to gh commands for testing support - Added --repo "$REPO" to gh issue comment command (line 103) - Added --repo "$REPO" to gh issue create command (line 148) - This enables testing against specific repositories by setting the REPO variable Co-authored-by: jsturtevant <648372+jsturtevant@users.noreply.github.com> * Rebase and revert the code change from copilot Signed-off-by: James Sturtevant * Add kind/fuzzing label for better issue filtering and management Co-authored-by: jsturtevant <648372+jsturtevant@users.noreply.github.com> * Update fuzzing label from kind/fuzzing to area/fuzzing Co-authored-by: jsturtevant <648372+jsturtevant@users.noreply.github.com> * Rename variable names for clarity: testing_label and fuzzing_label Co-authored-by: jsturtevant <648372+jsturtevant@users.noreply.github.com> --------- Signed-off-by: James Sturtevant Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jsturtevant <648372+jsturtevant@users.noreply.github.com> Co-authored-by: James Sturtevant --- .github/workflows/Fuzzing.yml | 17 +++- dev/notify-fuzzing-failure.sh | 153 ++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 1 deletion(-) create mode 100755 dev/notify-fuzzing-failure.sh diff --git a/.github/workflows/Fuzzing.yml b/.github/workflows/Fuzzing.yml index 8bf437e8b..a3c19778a 100644 --- a/.github/workflows/Fuzzing.yml +++ b/.github/workflows/Fuzzing.yml @@ -15,4 +15,19 @@ jobs: with: targets: '["fuzz_host_print", "fuzz_guest_call", "fuzz_host_call"]' # Pass as a JSON array max_total_time: 18000 # 5 hours in seconds - secrets: inherit \ No newline at end of file + secrets: inherit + + notify-failure: + runs-on: ubuntu-latest + needs: fuzzing + if: always() && needs.fuzzing.result == 'failure' + permissions: + issues: write + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Notify Fuzzing Failure + run: ./dev/notify-fuzzing-failure.sh "fuzz_host_print,fuzz_guest_call,fuzz_host_call" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/dev/notify-fuzzing-failure.sh b/dev/notify-fuzzing-failure.sh new file mode 100755 index 000000000..f4a6ac04f --- /dev/null +++ b/dev/notify-fuzzing-failure.sh @@ -0,0 +1,153 @@ +#!/bin/bash +set -e +set -u +set -o pipefail + +## DESCRIPTION: +## +## This script creates or updates GitHub issues when fuzzing jobs fail. +## It checks for existing open fuzzing failure issues and either creates +## a new one or adds a comment to an existing one. +## +## PRE-REQS: +## +## This script assumes that the gh cli is installed and in the PATH +## and that there is a GitHub PAT in the GITHUB_TOKEN env var +## with the following permissions: +## - issues (read/write) +## or that the user is logged into the gh cli with an account with those permissions +## +## Run this script locally like: +## GITHUB_REPOSITORY="fork/hyperlight" GITHUB_RUN_ID=1 ./dev/notify-fuzzing-failure.sh "fuzz_host_print,fuzz_guest_call,fuzz_host_call" + +REPO="${GITHUB_REPOSITORY:-hyperlight-dev/hyperlight}" +WORKFLOW_RUN_URL="${GITHUB_SERVER_URL:-https://github.com}/${REPO}/actions/runs/${GITHUB_RUN_ID:-unknown}" +FUZZING_TARGETS="${1:-unknown}" + +# Check if running in test mode (handle both first and second arguments) +if [ "${1:-}" = "--test" ] || [ "${2:-}" = "--test" ]; then + echo "✅ Running in test mode - script structure is valid" + echo "Would check for fuzzing failure issues in $REPO" + echo "Would create issue or comment for fuzzing targets: ${1:-unknown}" + echo "Workflow URL would be: $WORKFLOW_RUN_URL" + exit 0 +fi + +echo "Checking for existing fuzzing failure issues in $REPO..." + +# Extract owner and repo name from the repository +OWNER=$(echo "$REPO" | cut -d'/' -f1) +REPO_NAME=$(echo "$REPO" | cut -d'/' -f2) + +# Define the issue title and labels +ISSUE_TITLE="Fuzzing Job Failure - $(date '+%Y-%m-%d')" +TESTING_LABEL="area/testing" +FAILURE_LABEL="kind/bug" +FUZZING_LABEL="area/fuzzing" +LIFECYCLE_LABEL="lifecycle/needs-review" + +# Search for existing open fuzzing failure issues +echo "Searching for existing open fuzzing failure issues..." +EXISTING_ISSUES=$(gh api graphql -f query=' + query($owner: String!, $repo: String!) { + repository(owner: $owner, name: $repo) { + issues(first: 10, states: OPEN, labels: ["area/fuzzing"]) { + totalCount + nodes { + number + title + url + labels(first: 20) { + nodes { + name + } + } + } + } + } + }' -f owner="$OWNER" -f repo="$REPO_NAME" --jq '.data.repository.issues') + +# Filter for fuzzing-related issues (now all results should be fuzzing issues due to label filter) +FUZZING_ISSUES=$(echo "$EXISTING_ISSUES" | jq '.nodes[]' 2>/dev/null || echo "") +FUZZING_ISSUE_COUNT=0 +if [ -n "$FUZZING_ISSUES" ]; then + FUZZING_ISSUE_COUNT=$(echo "$FUZZING_ISSUES" | jq -s 'length' 2>/dev/null || echo "0") +fi + +echo "Found $FUZZING_ISSUE_COUNT existing fuzzing failure issue(s)" + +if [ "$FUZZING_ISSUE_COUNT" -gt 0 ]; then + # Get the most recent fuzzing failure issue + ISSUE_NUMBER=$(echo "$FUZZING_ISSUES" | jq -r '.number' | head -1) + ISSUE_URL=$(echo "$FUZZING_ISSUES" | jq -r '.url' | head -1) + + if [ "$ISSUE_NUMBER" = "null" ] || [ -z "$ISSUE_NUMBER" ]; then + echo "⚠️ Could not parse issue number from fuzzing issues, creating new issue instead" + FUZZING_ISSUE_COUNT=0 + else + echo "Adding comment to existing issue #$ISSUE_NUMBER" + + # Create comment body + COMMENT_BODY="## Fuzzing Job Failed Again + +**Date:** $(date '+%Y-%m-%d %H:%M:%S UTC') +**Workflow Run:** [$WORKFLOW_RUN_URL]($WORKFLOW_RUN_URL) +**Fuzzing Targets:** $FUZZING_TARGETS + +The scheduled fuzzing job has failed again. Please check the workflow logs and artifacts for details." + + # Add comment to the existing issue + if gh issue comment "$ISSUE_NUMBER" --body "$COMMENT_BODY" --repo "$REPO"; then + echo "✅ Added comment to existing issue #$ISSUE_NUMBER: $ISSUE_URL" + else + echo "❌ Failed to add comment to existing issue. Creating new issue instead." + FUZZING_ISSUE_COUNT=0 + fi + fi +fi + +if [ "$FUZZING_ISSUE_COUNT" -eq 0 ]; then + echo "No existing fuzzing failure issues found. Creating new issue..." + + # Create issue body + ISSUE_BODY="## Fuzzing Job Failure Report + +**Date:** $(date '+%Y-%m-%d %H:%M:%S UTC') +**Workflow Run:** [$WORKFLOW_RUN_URL]($WORKFLOW_RUN_URL) +**Fuzzing Targets:** $FUZZING_TARGETS + +The scheduled fuzzing job has failed. This issue was automatically created to track the failure. + +### Details +The fuzzing workflow failed during execution. Please check the workflow logs and any uploaded artifacts for more details. + +### Next Steps +- [ ] Review the workflow logs for error details +- [ ] Download and analyze any crash artifacts if available +- [ ] Determine the root cause of the failure +- [ ] Fix the underlying issue + +### Related Documentation +- [Fuzzing README](https://github.com/$REPO/blob/main/fuzz/README.md) +- [Security Guidance](https://github.com/$REPO/blob/main/docs/security-guidance-for-developers.md) + +--- +*This issue was automatically created by the fuzzing failure notification system.*" + + # Create the new issue + if ISSUE_URL=$(gh issue create \ + --title "$ISSUE_TITLE" \ + --body "$ISSUE_BODY" \ + --label "$TESTING_LABEL" \ + --label "$FAILURE_LABEL" \ + --label "$FUZZING_LABEL" \ + --label "$LIFECYCLE_LABEL" \ + --repo "$REPO"); then + echo "✅ Created new fuzzing failure issue: $ISSUE_URL" + else + echo "❌ Failed to create new fuzzing failure issue" + exit 1 + fi +fi + +echo "Fuzzing failure notification completed successfully" \ No newline at end of file From ace32b1c4ed2fb14efcd211609c7f956b5d2b49f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 04:05:40 +0000 Subject: [PATCH 139/271] Bump uuid from 1.18.0 to 1.18.1 (#856) Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.18.0 to 1.18.1. - [Release notes](https://github.com/uuid-rs/uuid/releases) - [Commits](https://github.com/uuid-rs/uuid/compare/v1.18.0...v1.18.1) --- updated-dependencies: - dependency-name: uuid dependency-version: 1.18.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9770b25e7..f9e5f25b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3875,9 +3875,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.18.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "getrandom 0.3.3", "js-sys", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index b3b608d21..dc7e50119 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -48,7 +48,7 @@ anyhow = "1.0" metrics = "0.24.2" serde_json = "1.0" elfcore = "2.0" -uuid = { version = "1.18.0", features = ["v4"] } +uuid = { version = "1.18.1", features = ["v4"] } [target.'cfg(windows)'.dependencies] windows = { version = "0.61", features = [ @@ -82,7 +82,7 @@ mshv-bindings3 = { package="mshv-bindings", version = "=0.3.2", optional = true mshv-ioctls3 = { package="mshv-ioctls", version = "=0.3.2", optional = true} [dev-dependencies] -uuid = { version = "1.18.0", features = ["v4"] } +uuid = { version = "1.18.1", features = ["v4"] } signal-hook-registry = "1.4.6" envy = { version = "0.4.2" } serde = "1.0" From 9bd8cde0ec91b14fa186ff39a8e57717b4daa5b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 04:05:25 +0000 Subject: [PATCH 140/271] Bump wasmparser from 0.238.0 to 0.238.1 (#857) Bumps [wasmparser](https://github.com/bytecodealliance/wasm-tools) from 0.238.0 to 0.238.1. - [Release notes](https://github.com/bytecodealliance/wasm-tools/releases) - [Commits](https://github.com/bytecodealliance/wasm-tools/commits) --- updated-dependencies: - dependency-name: wasmparser dependency-version: 0.238.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9e5f25b8..1959deea2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4035,9 +4035,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.238.0" +version = "0.238.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ad4ca2ecb86b79ea410cd970985665de1d05774b7107b214bc5852b1bcbad7" +checksum = "3fa99c8328024423875ae4a55345cfde8f0371327fb2d0f33b0f52a06fc44408" dependencies = [ "bitflags 2.9.3", "hashbrown", diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index 665053c8a..559112b52 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -16,7 +16,7 @@ name = "hyperlight_component_macro" proc-macro = true [dependencies] -wasmparser = { version = "0.238.0" } +wasmparser = { version = "0.238.1" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index 9d0b3ffdd..de650651c 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -15,7 +15,7 @@ Shared implementation for the procedural macros that generate Hyperlight host an name = "hyperlight_component_util" [dependencies] -wasmparser = { version = "0.238.0" } +wasmparser = { version = "0.238.1" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } From 83a64d4eef2d6d501da8c6a589bc82c979684ef2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 08:28:51 +0000 Subject: [PATCH 141/271] Bump bitflags from 2.9.3 to 2.9.4 (#855) Bumps [bitflags](https://github.com/bitflags/bitflags) from 2.9.3 to 2.9.4. - [Release notes](https://github.com/bitflags/bitflags/releases) - [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md) - [Commits](https://github.com/bitflags/bitflags/compare/2.9.3...2.9.4) --- updated-dependencies: - dependency-name: bitflags dependency-version: 2.9.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 42 +++++++++++++++++----------------- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1959deea2..83dfeb708 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -208,7 +208,7 @@ version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "cexpr", "clang-sys", "itertools 0.13.0", @@ -245,9 +245,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.3" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "blake3" @@ -324,7 +324,7 @@ version = "0.20.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e3bd0f4e25afa9cabc157908d14eeef9067d6448c49414d17b3fb55f0eadd0" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "cairo-sys-rs", "glib", "libc", @@ -521,7 +521,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "core-foundation", "core-graphics-types", "foreign-types", @@ -534,7 +534,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "core-foundation", "libc", ] @@ -845,7 +845,7 @@ version = "25.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1045398c1bfd89168b5fd3f1fc11f6e70b34f6f66300c87d44d3de849463abf1" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "rustc_version", ] @@ -1016,7 +1016,7 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b686b198dfaa4109ebd0443d2841bc521e4b4b2915f1d84b3bb50332a8cdc1ae" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "cfg-if", "log", "managed", @@ -1133,7 +1133,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "libc", "libgit2-sys", "log", @@ -1146,7 +1146,7 @@ version = "0.20.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffc4b6e352d4716d84d7dde562dd9aee2a7d48beb872dd9ece7f2d1515b2d683" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "futures-channel", "futures-core", "futures-executor", @@ -1440,7 +1440,7 @@ name = "hyperlight-host" version = "0.9.0" dependencies = [ "anyhow", - "bitflags 2.9.3", + "bitflags 2.9.4", "blake3", "built", "cfg-if", @@ -1684,7 +1684,7 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "cfg-if", "libc", ] @@ -1805,7 +1805,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "333f77a20344a448f3f70664918135fddeb804e938f28a99d685bd92926e0b19" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "kvm-bindings", "libc", "vmm-sys-util", @@ -1872,7 +1872,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "libc", ] @@ -2408,7 +2408,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97f6fccfd2d9d2df765ca23ff85fe5cc437fb0e6d3e164e4d3cbe09d14780c93" dependencies = [ "arrayvec", - "bitflags 2.9.3", + "bitflags 2.9.4", "thiserror 2.0.16", "zerocopy 0.8.26", "zerocopy-derive 0.8.26", @@ -2675,7 +2675,7 @@ checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.9.3", + "bitflags 2.9.4", "lazy_static", "num-traits", "rand", @@ -2809,7 +2809,7 @@ version = "11.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", ] [[package]] @@ -2838,7 +2838,7 @@ version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", ] [[package]] @@ -2993,7 +2993,7 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys", @@ -3569,7 +3569,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "bytes", "futures-util", "http", @@ -4039,7 +4039,7 @@ version = "0.238.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fa99c8328024423875ae4a55345cfde8f0371327fb2d0f33b0f52a06fc44408" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "hashbrown", "indexmap", "semver", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index dc7e50119..77f729620 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -33,7 +33,7 @@ fallible-iterator = { version = "0.3.0", optional = true } blake3 = "1.8.2" page_size = "0.6.0" termcolor = "1.2.0" -bitflags = "2.9.3" +bitflags = "2.9.4" log = "0.4.27" tracing = { version = "0.1.41", features = ["log"] } tracing-log = "0.2.0" From 2d7b5fd70093b90e662dde8daba3dd399d2042b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 08:28:56 +0000 Subject: [PATCH 142/271] Bump tracing-subscriber from 0.3.19 to 0.3.20 (#854) Bumps [tracing-subscriber](https://github.com/tokio-rs/tracing) from 0.3.19 to 0.3.20. - [Release notes](https://github.com/tokio-rs/tracing/releases) - [Commits](https://github.com/tokio-rs/tracing/compare/tracing-subscriber-0.3.19...tracing-subscriber-0.3.20) --- updated-dependencies: - dependency-name: tracing-subscriber dependency-version: 0.3.20 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 61 +++++++++++++--------------------- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 25 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 83dfeb708..84ae42a6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1199,8 +1199,8 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.10", - "regex-syntax 0.8.6", + "regex-automata", + "regex-syntax", ] [[package]] @@ -1957,11 +1957,11 @@ checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" [[package]] name = "matchers" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "regex-automata 0.1.10", + "regex-automata", ] [[package]] @@ -2136,12 +2136,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.46.0" +version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" dependencies = [ - "overload", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -2306,12 +2305,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "page_size" version = "0.6.0" @@ -2681,7 +2674,7 @@ dependencies = [ "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.6", + "regex-syntax", "rusty-fork", "tempfile", "unarray", @@ -2860,17 +2853,8 @@ checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.10", - "regex-syntax 0.8.6", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", + "regex-automata", + "regex-syntax", ] [[package]] @@ -2881,15 +2865,9 @@ checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.6", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "regex-syntax" version = "0.8.6" @@ -3702,14 +3680,14 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" dependencies = [ "matchers", "nu-ansi-term", "once_cell", - "regex", + "regex-automata", "sharded-slab", "smallvec", "thread_local", @@ -4199,6 +4177,15 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.59.0" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 77f729620..0c2ae6e13 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -95,7 +95,7 @@ hyperlight-testing = { workspace = true } env_logger = "0.11.8" tracing-forest = { version = "0.2.0", features = ["uuid", "chrono", "smallvec", "serde", "env-filter"] } tracing = "0.1.41" -tracing-subscriber = {version = "0.3.19", features = ["std", "env-filter"]} +tracing-subscriber = {version = "0.3.20", features = ["std", "env-filter"]} tracing-opentelemetry = "0.31.0" opentelemetry = "0.30.0" opentelemetry-otlp = { version = "0.30.0", default-features = false, features = ["http-proto", "reqwest-blocking-client"] } From 16ca046f4f0149365127b6408e4a5baa0f005d83 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 08:30:00 +0000 Subject: [PATCH 143/271] Bump piet-common from 0.7.0 to 0.8.0 (#853) --- Cargo.lock | 74 +++++++++++++++++++-------------------- src/trace_dump/Cargo.toml | 2 +- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84ae42a6e..61ea7af01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -320,9 +320,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cairo-rs" -version = "0.20.12" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e3bd0f4e25afa9cabc157908d14eeef9067d6448c49414d17b3fb55f0eadd0" +checksum = "1158f326d7b755a9ae2b36c5b5391400e3431f3b77418cedb6d7130126628f10" dependencies = [ "bitflags 2.9.4", "cairo-sys-rs", @@ -332,9 +332,9 @@ dependencies = [ [[package]] name = "cairo-sys-rs" -version = "0.20.10" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "059cc746549898cbfd9a47754288e5a958756650ef4652bbb6c5f71a6bda4f8b" +checksum = "b963177900ec8e783927e5ed99e16c0ec1b723f1f125dff8992db28ef35c62c3" dependencies = [ "glib-sys", "libc", @@ -1099,9 +1099,9 @@ dependencies = [ [[package]] name = "gio" -version = "0.20.12" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e27e276e7b6b8d50f6376ee7769a71133e80d093bdc363bd0af71664228b831" +checksum = "52b5e3f390d01b79e30da451dd00e27cd1ac2de81658e3abf6c1fc3229b24c5f" dependencies = [ "futures-channel", "futures-core", @@ -1116,15 +1116,15 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.20.10" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521e93a7e56fc89e84aea9a52cfc9436816a4b363b030260b699950ff1336c83" +checksum = "a03f2234671e5a588cfe1f59c2b22c103f5772ea351be9cc824a9ce0d06d99fd" dependencies = [ "glib-sys", "gobject-sys", "libc", "system-deps", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1142,9 +1142,9 @@ dependencies = [ [[package]] name = "glib" -version = "0.20.12" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc4b6e352d4716d84d7dde562dd9aee2a7d48beb872dd9ece7f2d1515b2d683" +checksum = "60bdc26493257b5794ba9301f7cbaf7ab0d69a570bfbefa4d7d360e781cb5205" dependencies = [ "bitflags 2.9.4", "futures-channel", @@ -1163,9 +1163,9 @@ dependencies = [ [[package]] name = "glib-macros" -version = "0.20.12" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8084af62f09475a3f529b1629c10c429d7600ee1398ae12dd3bf175d74e7145" +checksum = "e772291ebea14c28eb11bb75741f62f4a4894f25e60ce80100797b6b010ef0f9" dependencies = [ "heck", "proc-macro-crate", @@ -1176,9 +1176,9 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.20.10" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ab79e1ed126803a8fb827e3de0e2ff95191912b8db65cee467edb56fc4cc215" +checksum = "dc7c43cff6a7dc43821e45ebf172399437acd6716fa2186b6852d2b397bf622d" dependencies = [ "libc", "system-deps", @@ -1205,9 +1205,9 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.20.10" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec9aca94bb73989e3cfdbf8f2e0f1f6da04db4d291c431f444838925c4c63eda" +checksum = "3e9a190eef2bce144a6aa8434e306974c6062c398e0a33a146d60238f9062d5c" dependencies = [ "glib-sys", "libc", @@ -2317,9 +2317,9 @@ dependencies = [ [[package]] name = "pango" -version = "0.20.12" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6576b311f6df659397043a5fa8a021da8f72e34af180b44f7d57348de691ab5c" +checksum = "ab47feb3403aa564edaeb68620c5b9159f8814733a7dd45f0b1a27d19de362fe" dependencies = [ "gio", "glib", @@ -2329,9 +2329,9 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.20.10" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186909673fc09be354555c302c0b3dcf753cd9fa08dcb8077fa663c80fb243fa" +checksum = "1f855bccb447644e149fae79086e1f81514c30fe5e9b8bd257d9d3c941116c86" dependencies = [ "glib-sys", "gobject-sys", @@ -2341,9 +2341,9 @@ dependencies = [ [[package]] name = "pangocairo" -version = "0.20.10" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58890dc451db9964ac2d8874f903a4370a4b3932aa5281ff0c8d9810937ad84f" +checksum = "bb23cf0052917cbf75f160d4913a46ce741567f566b514fadc09d761f41eb2fb" dependencies = [ "cairo-rs", "glib", @@ -2354,9 +2354,9 @@ dependencies = [ [[package]] name = "pangocairo-sys" -version = "0.20.10" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9952903f88aa93e2927e7bca2d1ebae64fc26545a9280b4ce6bddeda26b5c42" +checksum = "dcda09c0b17007d7eb6c5eb1643c5b40b067073c15f0cc5a809a6fc68b5d9be7" dependencies = [ "cairo-sys-rs", "glib-sys", @@ -2415,9 +2415,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "piet" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5139c7ec7de4cc21d108484af288b9c335b731194218023acf8b02874ed2b25e" +checksum = "31867aac026f5706ca679ee13e0089fe85be00646ff1de73dd5ca6a15ddb48e1" dependencies = [ "kurbo", "unic-bidi", @@ -2425,9 +2425,9 @@ dependencies = [ [[package]] name = "piet-cairo" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9612bb8fdcd109ba7ce490777c79ef1bcbdb7f046b4a0e7fe449a42e51cda3e1" +checksum = "ae84f3d22ce540ca5a598669c3fc95fe0cae45bdf733abc9796d20f4445017c1" dependencies = [ "cairo-rs", "pango", @@ -2439,9 +2439,9 @@ dependencies = [ [[package]] name = "piet-common" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ecd35fec05d4496878a0d9830a39b7031bb20dddd1a67dd36e8dda9b3111fd7" +checksum = "34c5f8f1bf281d40b08da00b90e20b14d3a68035eee1c12ba260c62b040172f3" dependencies = [ "cairo-rs", "cairo-sys-rs", @@ -2459,9 +2459,9 @@ dependencies = [ [[package]] name = "piet-coregraphics" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a71f2f06ad9048d617955763bb40856bee3dbb157c568d7d234280443cd6b5ae" +checksum = "75958f4ea4a36640178d2fb342fe29707e346dbc31b5983e31c8ef3bb78b7fce" dependencies = [ "associative-cache", "core-foundation", @@ -2474,9 +2474,9 @@ dependencies = [ [[package]] name = "piet-direct2d" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0cd070348a4b8fddc486071c9fee2d98254ce7a4b9fdbf360c5dfee950d5866" +checksum = "838ce5efd17a7911574e2047040dbae5d4b2633f50263673af6be4e65ae68f5c" dependencies = [ "associative-cache", "dwrote", @@ -2488,9 +2488,9 @@ dependencies = [ [[package]] name = "piet-web" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "471a2fe8003e860d6603fe32b47f77f0c3854f23a0068b47fe2d701b380b4d46" +checksum = "838f32f0ea82a258c767662c1751e9e35f34b6e3977e2d9c0b7bc207d9547628" dependencies = [ "js-sys", "piet", diff --git a/src/trace_dump/Cargo.toml b/src/trace_dump/Cargo.toml index 94f408430..52014a8f3 100644 --- a/src/trace_dump/Cargo.toml +++ b/src/trace_dump/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] addr2line = "0.25.0" -piet-common = { version = "0.7.0", features = [ "png" ] } +piet-common = { version = "0.8.0", features = [ "png" ] } blake3 = { version = "1.5.5" } [[bin]] From e7568fa6136b651d9af148e0273866426eeaeeeb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Sep 2025 04:05:39 +0000 Subject: [PATCH 144/271] Bump windows-version from 0.1.4 to 0.1.5 (#866) Bumps [windows-version](https://github.com/microsoft/windows-rs) from 0.1.4 to 0.1.5. - [Release notes](https://github.com/microsoft/windows-rs/releases) - [Commits](https://github.com/microsoft/windows-rs/commits) --- updated-dependencies: - dependency-name: windows-version dependency-version: 0.1.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 61ea7af01..430e66f59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -419,7 +419,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -4084,7 +4084,7 @@ dependencies = [ "windows-collections", "windows-core", "windows-future", - "windows-link", + "windows-link 0.1.3", "windows-numerics", ] @@ -4105,7 +4105,7 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", - "windows-link", + "windows-link 0.1.3", "windows-result", "windows-strings", ] @@ -4117,7 +4117,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ "windows-core", - "windows-link", + "windows-link 0.1.3", "windows-threading", ] @@ -4149,6 +4149,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + [[package]] name = "windows-numerics" version = "0.2.0" @@ -4156,7 +4162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ "windows-core", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -4165,7 +4171,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -4174,7 +4180,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -4226,7 +4232,7 @@ version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -4243,16 +4249,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] name = "windows-version" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04a5c6627e310a23ad2358483286c7df260c964eb2d003d8efd6d0f4e79265c" +checksum = "69e061eb0a22b4a1d778ad70f7575ec7845490abb35b08fa320df7895882cacb" dependencies = [ - "windows-link", + "windows-link 0.2.0", ] [[package]] From 99a575b64d7462e9ee67229010fdcb2fad54c14f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Sep 2025 04:05:49 +0000 Subject: [PATCH 145/271] Bump log from 0.4.27 to 0.4.28 (#859) Bumps [log](https://github.com/rust-lang/log) from 0.4.27 to 0.4.28. - [Release notes](https://github.com/rust-lang/log/releases) - [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/log/compare/0.4.27...0.4.28) --- updated-dependencies: - dependency-name: log dependency-version: 0.4.28 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_common/Cargo.toml | 2 +- src/hyperlight_host/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 430e66f59..44c32ff75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1912,9 +1912,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "loom" diff --git a/src/hyperlight_common/Cargo.toml b/src/hyperlight_common/Cargo.toml index b74dbb023..06f6b8472 100644 --- a/src/hyperlight_common/Cargo.toml +++ b/src/hyperlight_common/Cargo.toml @@ -17,7 +17,7 @@ workspace = true [dependencies] flatbuffers = { version = "25.2.10", default-features = false } anyhow = { version = "1.0.99", default-features = false } -log = "0.4.27" +log = "0.4.28" tracing = { version = "0.1.41", optional = true } arbitrary = {version = "1.4.2", optional = true, features = ["derive"]} spin = "0.10.0" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 0c2ae6e13..d36eba95b 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -34,7 +34,7 @@ blake3 = "1.8.2" page_size = "0.6.0" termcolor = "1.2.0" bitflags = "2.9.4" -log = "0.4.27" +log = "0.4.28" tracing = { version = "0.1.41", features = ["log"] } tracing-log = "0.2.0" tracing-core = "0.1.34" From 409fe95760e5ec3753a3b480f1b8583393b2da7f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Sep 2025 04:05:53 +0000 Subject: [PATCH 146/271] Bump cc from 1.2.34 to 1.2.35 (#852) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.34 to 1.2.35. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.34...cc-v1.2.35) --- updated-dependencies: - dependency-name: cc dependency-version: 1.2.35 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44c32ff75..2b696143e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -368,10 +368,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.34" +version = "1.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" +checksum = "590f9024a68a8c40351881787f1934dc11afd69090f5edb6831464694d836ea3" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -839,6 +840,12 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e178e4fba8a2726903f6ba98a6d221e76f9c12c650d5dc0e6afdc50677b49650" + [[package]] name = "flatbuffers" version = "25.2.10" From 1e5e541d2ff139b40877ad1285aab5fa41333dfb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Sep 2025 13:29:11 +0000 Subject: [PATCH 147/271] Bump actions/github-script from 7 to 8 (#861) --- .github/workflows/ValidatePullRequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index d3c628546..fa718e9f3 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -32,7 +32,7 @@ jobs: - '**/*.txt' all: - '**/*' - - uses: actions/github-script@v7 + - uses: actions/github-script@v8 id: docs-only with: script: | From 3ad7096d5fa4bebc426a41ac6c1d7f100a4e9abc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 6 Sep 2025 04:04:49 +0000 Subject: [PATCH 148/271] Bump windows-sys from 0.60.2 to 0.61.0 (#865) Bumps [windows-sys](https://github.com/microsoft/windows-rs) from 0.60.2 to 0.61.0. - [Release notes](https://github.com/microsoft/windows-rs/releases) - [Commits](https://github.com/microsoft/windows-rs/commits/0.61.0) --- updated-dependencies: - dependency-name: windows-sys dependency-version: 0.61.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 23 ++++++++++++++++------- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2b696143e..0cc901e43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -710,7 +710,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -807,7 +807,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -1131,7 +1131,7 @@ dependencies = [ "gobject-sys", "libc", "system-deps", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -1513,7 +1513,7 @@ dependencies = [ "vmm-sys-util", "windows", "windows-result", - "windows-sys 0.60.2", + "windows-sys 0.61.0", "windows-version", ] @@ -2982,7 +2982,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -3348,7 +3348,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -4073,7 +4073,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -4217,6 +4217,15 @@ dependencies = [ "windows-targets 0.53.3", ] +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-targets" version = "0.52.6" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index d36eba95b..6885ec098 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -65,7 +65,7 @@ windows = { version = "0.61", features = [ "Win32_System_JobObjects", "Win32_System_SystemServices", ] } -windows-sys = { version = "0.60", features = ["Win32"] } +windows-sys = { version = "0.61", features = ["Win32"] } windows-result = "0.3" rust-embed = { version = "8.7.2", features = ["debug-embed", "include-exclude", "interpolate-folder-path"] } sha256 = "1.6.0" From 179eff83d0d00d5ba8c3dde5fb225f1c4d9d3cc3 Mon Sep 17 00:00:00 2001 From: Shailesh Date: Sun, 7 Sep 2025 02:23:29 +0530 Subject: [PATCH 149/271] Change of Error Code for Exception enum TryFrom impl (#869) Signed-off-by: Shailesh Vashishth --- src/hyperlight_common/src/outb.rs | 2 +- src/tests/rust_guests/callbackguest/Cargo.lock | 4 ++-- src/tests/rust_guests/simpleguest/Cargo.lock | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hyperlight_common/src/outb.rs b/src/hyperlight_common/src/outb.rs index 54bba6f74..6211c8cf1 100644 --- a/src/hyperlight_common/src/outb.rs +++ b/src/hyperlight_common/src/outb.rs @@ -77,7 +77,7 @@ impl TryFrom for Exception { 19 => SIMDFloatingPointException, 20 => VirtualizationException, 30 => SecurityException, - 0x7F => NoException, + 0xFF => NoException, _ => return Err(anyhow!("Unknown exception code: {:#x}", value)), }; diff --git a/src/tests/rust_guests/callbackguest/Cargo.lock b/src/tests/rust_guests/callbackguest/Cargo.lock index fa07b3e56..c899d36c5 100644 --- a/src/tests/rust_guests/callbackguest/Cargo.lock +++ b/src/tests/rust_guests/callbackguest/Cargo.lock @@ -142,9 +142,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index 1900d8955..9081da46b 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -132,9 +132,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" From da8dc26e8531f885de5aba62ff680957f1b62f96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Sep 2025 04:05:40 +0000 Subject: [PATCH 150/271] Bump cc from 1.2.35 to 1.2.36 (#870) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.35 to 1.2.36. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.35...cc-v1.2.36) --- updated-dependencies: - dependency-name: cc dependency-version: 1.2.36 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0cc901e43..b23afe472 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -368,9 +368,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.35" +version = "1.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "590f9024a68a8c40351881787f1934dc11afd69090f5edb6831464694d836ea3" +checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" dependencies = [ "find-msvc-tools", "jobserver", @@ -710,7 +710,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] @@ -807,7 +807,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -842,9 +842,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e178e4fba8a2726903f6ba98a6d221e76f9c12c650d5dc0e6afdc50677b49650" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" [[package]] name = "flatbuffers" @@ -1131,7 +1131,7 @@ dependencies = [ "gobject-sys", "libc", "system-deps", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -2982,7 +2982,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -3348,7 +3348,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -4073,7 +4073,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] From bd80ab4bb607b138ad885042836c90a4370cae89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Sep 2025 09:26:24 +0000 Subject: [PATCH 151/271] Bump crate-ci/typos from 1.35.6 to 1.36.2 (#862) --- .github/workflows/ValidatePullRequest.yml | 2 +- src/hyperlight_guest_tracing/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index fa718e9f3..e6b07ddac 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -65,7 +65,7 @@ jobs: steps: - uses: actions/checkout@v5 - name: Spell Check Repo - uses: crate-ci/typos@v1.35.6 + uses: crate-ci/typos@v1.36.2 license-headers: name: check license headers diff --git a/src/hyperlight_guest_tracing/src/lib.rs b/src/hyperlight_guest_tracing/src/lib.rs index 92902e3da..b89f88e9b 100644 --- a/src/hyperlight_guest_tracing/src/lib.rs +++ b/src/hyperlight_guest_tracing/src/lib.rs @@ -326,7 +326,7 @@ mod trace { // Flush the buffer buffer.flush(); - // After flushing, the entryes should still be intact, we don't clear them + // After flushing, the entries should still be intact, we don't clear them assert_eq!(buffer.write_index, 0); assert_eq!(buffer.entries[0].msg_len, msg.len()); assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); From 87af189c86e776edd542db1cb1d382ac7f9e9e27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Sep 2025 09:33:46 +0000 Subject: [PATCH 152/271] Bump windows from 0.61.3 to 0.62.0 (#864) --- Cargo.lock | 111 ++++++++++++++++++++++++++++----- src/hyperlight_host/Cargo.toml | 6 +- 2 files changed, 100 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b23afe472..36e0de04a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1052,7 +1052,7 @@ dependencies = [ "libc", "log", "rustversion", - "windows", + "windows 0.61.3", ] [[package]] @@ -1511,8 +1511,8 @@ dependencies = [ "tracing-tracy", "uuid", "vmm-sys-util", - "windows", - "windows-result", + "windows 0.62.0", + "windows-result 0.4.0", "windows-sys 0.61.0", "windows-version", ] @@ -1555,7 +1555,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.61.2", ] [[package]] @@ -4088,11 +4088,24 @@ version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-collections", - "windows-core", - "windows-future", + "windows-collections 0.2.0", + "windows-core 0.61.2", + "windows-future 0.2.1", "windows-link 0.1.3", - "windows-numerics", + "windows-numerics 0.2.0", +] + +[[package]] +name = "windows" +version = "0.62.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9579d0e6970fd5250aa29aba5994052385ff55cf7b28a059e484bb79ea842e42" +dependencies = [ + "windows-collections 0.3.0", + "windows-core 0.62.0", + "windows-future 0.3.0", + "windows-link 0.2.0", + "windows-numerics 0.3.0", ] [[package]] @@ -4101,7 +4114,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core", + "windows-core 0.61.2", +] + +[[package]] +name = "windows-collections" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90dd7a7b86859ec4cdf864658b311545ef19dbcf17a672b52ab7cefe80c336f" +dependencies = [ + "windows-core 0.62.0", ] [[package]] @@ -4113,8 +4135,21 @@ dependencies = [ "windows-implement", "windows-interface", "windows-link 0.1.3", - "windows-result", - "windows-strings", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.0", + "windows-result 0.4.0", + "windows-strings 0.5.0", ] [[package]] @@ -4123,9 +4158,20 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "windows-core", + "windows-core 0.61.2", "windows-link 0.1.3", - "windows-threading", + "windows-threading 0.1.0", +] + +[[package]] +name = "windows-future" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2194dee901458cb79e1148a4e9aac2b164cc95fa431891e7b296ff0b2f1d8a6" +dependencies = [ + "windows-core 0.62.0", + "windows-link 0.2.0", + "windows-threading 0.2.0", ] [[package]] @@ -4168,10 +4214,20 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core", + "windows-core 0.61.2", "windows-link 0.1.3", ] +[[package]] +name = "windows-numerics" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce3498fe0aba81e62e477408383196b4b0363db5e0c27646f932676283b43d8" +dependencies = [ + "windows-core 0.62.0", + "windows-link 0.2.0", +] + [[package]] name = "windows-result" version = "0.3.4" @@ -4181,6 +4237,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-strings" version = "0.4.2" @@ -4190,6 +4255,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -4268,6 +4342,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-threading" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab47f085ad6932defa48855254c758cdd0e2f2d48e62a34118a268d8f345e118" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-version" version = "0.1.5" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 6885ec098..49b638895 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -51,7 +51,7 @@ elfcore = "2.0" uuid = { version = "1.18.1", features = ["v4"] } [target.'cfg(windows)'.dependencies] -windows = { version = "0.61", features = [ +windows = { version = "0.62", features = [ "Win32_Foundation", "Win32_System_LibraryLoader", "Win32_System_Threading", @@ -66,7 +66,7 @@ windows = { version = "0.61", features = [ "Win32_System_SystemServices", ] } windows-sys = { version = "0.61", features = ["Win32"] } -windows-result = "0.3" +windows-result = "0.4" rust-embed = { version = "8.7.2", features = ["debug-embed", "include-exclude", "interpolate-folder-path"] } sha256 = "1.6.0" windows-version = "0.1" @@ -111,7 +111,7 @@ serde_json = "1.0" hyperlight-component-macro = { workspace = true } [target.'cfg(windows)'.dev-dependencies] -windows = { version = "0.61", features = [ +windows = { version = "0.62", features = [ "Win32_System_Diagnostics_ToolHelp", ] } From 49e248a66a35fcb86c252578a6a83be33c01238d Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Mon, 8 Sep 2025 11:05:05 -0700 Subject: [PATCH 153/271] Only clear io buffer after unsuccesfull guest call (#811) * Only clear io buffer after unsuccesfull guest call. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Undo stuff that breaks unwinding Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Add error path to test Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --------- Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- .../src/sandbox/initialized_multi_use.rs | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 82a920158..dfdcc9668 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -425,9 +425,14 @@ impl MultiUseSandbox { .get_guest_function_call_result() })(); - // TODO: Do we want to allow re-entrant guest function calls? - self.get_mgr_wrapper_mut().as_mut().clear_io_buffers(); - + // In the happy path we do not need to clear io-buffers from the host because: + // - the serialized guest function call is zeroed out by the guest during deserialization, see call to `try_pop_shared_input_data_into::()` + // - the serialized guest function result is zeroed out by us (the host) during deserialization, see `get_guest_function_call_result` + // - any serialized host function call are zeroed out by us (the host) during deserialization, see `get_host_function_call` + // - any serialized host function result is zeroed out by the guest during deserialization, see `get_host_return_value` + if res.is_err() { + self.get_mgr_wrapper_mut().as_mut().clear_io_buffers(); + } res } @@ -497,6 +502,7 @@ mod tests { use std::sync::{Arc, Barrier}; use std::thread; + use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_testing::simple_guest_as_string; #[cfg(target_os = "linux")] @@ -506,6 +512,29 @@ mod tests { use crate::sandbox::SandboxConfiguration; use crate::{GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox}; + /// Make sure input/output buffers are properly reset after guest call (with host call) + #[test] + fn io_buffer_reset() { + let mut cfg = SandboxConfiguration::default(); + cfg.set_input_data_size(4096); + cfg.set_output_data_size(4096); + let path = simple_guest_as_string().unwrap(); + let mut sandbox = + UninitializedSandbox::new(GuestBinary::FilePath(path), Some(cfg)).unwrap(); + sandbox.register("HostAdd", |a: i32, b: i32| a + b).unwrap(); + let mut sandbox = sandbox.evolve().unwrap(); + + // will exhaust io if leaky. Tests both success and error paths + for _ in 0..1000 { + let result = sandbox.call::("Add", (5i32, 10i32)).unwrap(); + assert_eq!(result, 15); + let result = sandbox.call::("AddToStaticAndFail", ()).unwrap_err(); + assert!( + matches!(result, HyperlightError::GuestError (code, msg ) if code == ErrorCode::GuestError && msg == "Crash on purpose") + ); + } + } + /// Tests that call_guest_function_by_name restores the state correctly #[test] fn test_call_guest_function_by_name() { From 9cca6110b6bc3bbca5e85709294bb3800b450ca9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Sep 2025 04:05:37 +0000 Subject: [PATCH 154/271] Bump chrono from 0.4.41 to 0.4.42 (#872) Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.41 to 0.4.42. - [Release notes](https://github.com/chronotope/chrono/releases) - [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md) - [Commits](https://github.com/chronotope/chrono/compare/v0.4.41...v0.4.42) --- updated-dependencies: - dependency-name: chrono dependency-version: 0.4.42 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36e0de04a..072b85b2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,12 +54,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -411,16 +405,15 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-link 0.1.3", + "windows-link 0.2.0", ] [[package]] From 8ba379305530ea812b19ebfbce1b0dc14daca904 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Tue, 9 Sep 2025 09:49:21 -0700 Subject: [PATCH 155/271] Remove callbackguest (#871) moves functionality of callbackguest into simpleguest Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- .github/dependabot.yml | 10 - .github/workflows/Benchmarks.yml | 2 - .../workflows/dep_build_guest_binaries.yml | 2 - .vscode/settings.json | 1 - Cargo.toml | 1 - Justfile | 7 - c.just | 3 - src/hyperlight_host/src/lib.rs | 3 +- .../src/sandbox/uninitialized_evolve.rs | 7 +- src/hyperlight_host/tests/common/mod.rs | 19 +- src/hyperlight_host/tests/integration_test.rs | 8 +- .../tests/sandbox_host_tests.rs | 8 +- src/hyperlight_testing/src/lib.rs | 17 +- src/tests/c_guests/c_callbackguest/main.c | 51 --- src/tests/c_guests/c_simpleguest/main.c | 19 ++ .../callbackguest/.cargo/config.toml | 19 -- .../rust_guests/callbackguest/Cargo.lock | 271 ---------------- .../rust_guests/callbackguest/Cargo.toml | 16 - .../rust_guests/callbackguest/src/main.rs | 278 ----------------- src/tests/rust_guests/dummyguest/Cargo.lock | 4 +- src/tests/rust_guests/simpleguest/src/main.rs | 290 ++++++++++++++++-- src/tests/rust_guests/witguest/Cargo.lock | 8 +- 22 files changed, 298 insertions(+), 746 deletions(-) delete mode 100644 src/tests/c_guests/c_callbackguest/main.c delete mode 100644 src/tests/rust_guests/callbackguest/.cargo/config.toml delete mode 100644 src/tests/rust_guests/callbackguest/Cargo.lock delete mode 100644 src/tests/rust_guests/callbackguest/Cargo.toml delete mode 100644 src/tests/rust_guests/callbackguest/src/main.rs diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 088efd8a8..51e8bb207 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -21,16 +21,6 @@ updates: - dependency-name: "mshv-bindings" versions: [ ">=0.2.1" ] open-pull-requests-limit: 20 - # Excluded workspace members - guests with custom linker flags - - package-ecosystem: "cargo" - directory: "/src/tests/rust_guests/callbackguest" - schedule: - interval: "daily" - time: "03:00" - labels: - - "kind/dependencies" - - "area/guest" - open-pull-requests-limit: 5 - package-ecosystem: "cargo" directory: "/src/tests/rust_guests/dummyguest" schedule: diff --git a/.github/workflows/Benchmarks.yml b/.github/workflows/Benchmarks.yml index 45b782025..048b788cb 100644 --- a/.github/workflows/Benchmarks.yml +++ b/.github/workflows/Benchmarks.yml @@ -48,10 +48,8 @@ jobs: - name: Copy Guest Binaries run: | - cp ./downloaded-rust-guest-binaries-release/callbackguest ./src/tests/rust_guests/bin/release/callbackguest cp ./downloaded-rust-guest-binaries-release/simpleguest ./src/tests/rust_guests/bin/release/simpleguest cp ./downloaded-rust-guest-binaries-release/dummyguest ./src/tests/rust_guests/bin/release/dummyguest - cp ./downloaded-c-guest-binaries-release/callbackguest ./src/tests/c_guests/bin/release/callbackguest cp ./downloaded-c-guest-binaries-release/simpleguest ./src/tests/c_guests/bin/release/simpleguest ### Benchmarks ### diff --git a/.github/workflows/dep_build_guest_binaries.yml b/.github/workflows/dep_build_guest_binaries.yml index 89ebf4dca..2088d0ae5 100644 --- a/.github/workflows/dep_build_guest_binaries.yml +++ b/.github/workflows/dep_build_guest_binaries.yml @@ -45,7 +45,6 @@ jobs: with: name: rust-guest-binaries-${{ matrix.config }} path: | - src\tests\rust_guests\bin\${{ matrix.config }}\callbackguest src\tests\rust_guests\bin\${{ matrix.config }}\dummyguest src\tests\rust_guests\bin\${{ matrix.config }}\simpleguest if-no-files-found: error @@ -55,6 +54,5 @@ jobs: with: name: c-guest-binaries-${{ matrix.config }} path: | - src\tests\c_guests\bin\${{ matrix.config }}\callbackguest src\tests\c_guests\bin\${{ matrix.config }}\simpleguest if-no-files-found: error diff --git a/.vscode/settings.json b/.vscode/settings.json index 1ec1edf0e..3d6d12789 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,5 @@ "Cargo.toml", // guest crates for testing, not part of the workspace "src/tests/rust_guests/simpleguest/Cargo.toml", - "src/tests/rust_guests/callbackguest/Cargo.toml" ] } \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index d5f9a4092..8bccc53d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,6 @@ members = [ ] # Guests have custom linker flags, so we need to exclude them from the workspace exclude = [ - "src/tests/rust_guests/callbackguest", "src/tests/rust_guests/dummyguest", "src/tests/rust_guests/simpleguest", "src/tests/rust_guests/witguest", diff --git a/Justfile b/Justfile index aed82725d..6e8218958 100644 --- a/Justfile +++ b/Justfile @@ -11,7 +11,6 @@ root := justfile_directory() default-target := "debug" simpleguest_source := "src/tests/rust_guests/simpleguest/target/x86_64-unknown-none" dummyguest_source := "src/tests/rust_guests/dummyguest/target/x86_64-unknown-none" -callbackguest_source := "src/tests/rust_guests/callbackguest/target/x86_64-unknown-none" witguest_source := "src/tests/rust_guests/witguest/target/x86_64-unknown-none" rust_guests_bin_dir := "src/tests/rust_guests/bin" @@ -39,13 +38,11 @@ witguest-wit: cd src/tests/rust_guests/witguest && wasm-tools component wit guest.wit -w -o interface.wasm build-rust-guests target=default-target features="": (witguest-wit) - cd src/tests/rust_guests/callbackguest && cargo build {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} cd src/tests/rust_guests/simpleguest && cargo build {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} cd src/tests/rust_guests/dummyguest && cargo build {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} cd src/tests/rust_guests/witguest && cargo build {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} @move-rust-guests target=default-target: - cp {{ callbackguest_source }}/{{ target }}/callbackguest* {{ rust_guests_bin_dir }}/{{ target }}/ cp {{ simpleguest_source }}/{{ target }}/simpleguest* {{ rust_guests_bin_dir }}/{{ target }}/ cp {{ dummyguest_source }}/{{ target }}/dummyguest* {{ rust_guests_bin_dir }}/{{ target }}/ cp {{ witguest_source }}/{{ target }}/witguest* {{ rust_guests_bin_dir }}/{{ target }}/ @@ -59,7 +56,6 @@ clean-rust: cargo clean cd src/tests/rust_guests/simpleguest && cargo clean cd src/tests/rust_guests/dummyguest && cargo clean - cd src/tests/rust_guests/callbackguest && cargo clean {{ if os() == "windows" { "cd src/tests/rust_guests/witguest -ErrorAction SilentlyContinue; cargo clean" } else { "[ -d src/tests/rust_guests/witguest ] && cd src/tests/rust_guests/witguest && cargo clean || true" } }} {{ if os() == "windows" { "Remove-Item src/tests/rust_guests/witguest/interface.wasm -Force -ErrorAction SilentlyContinue" } else { "rm -f src/tests/rust_guests/witguest/interface.wasm" } }} git clean -fdx src/tests/c_guests/bin src/tests/rust_guests/bin @@ -229,7 +225,6 @@ check: fmt-check: cargo +nightly fmt --all -- --check - cargo +nightly fmt --manifest-path src/tests/rust_guests/callbackguest/Cargo.toml -- --check cargo +nightly fmt --manifest-path src/tests/rust_guests/simpleguest/Cargo.toml -- --check cargo +nightly fmt --manifest-path src/tests/rust_guests/dummyguest/Cargo.toml -- --check cargo +nightly fmt --manifest-path src/tests/rust_guests/witguest/Cargo.toml -- --check @@ -240,7 +235,6 @@ check-license-headers: fmt-apply: cargo +nightly fmt --all - cargo +nightly fmt --manifest-path src/tests/rust_guests/callbackguest/Cargo.toml cargo +nightly fmt --manifest-path src/tests/rust_guests/simpleguest/Cargo.toml cargo +nightly fmt --manifest-path src/tests/rust_guests/dummyguest/Cargo.toml cargo +nightly fmt --manifest-path src/tests/rust_guests/witguest/Cargo.toml @@ -251,7 +245,6 @@ clippy target=default-target: (witguest-wit) clippy-guests target=default-target: (witguest-wit) cd src/tests/rust_guests/simpleguest && cargo clippy --profile={{ if target == "debug" { "dev" } else { target } }} -- -D warnings - cd src/tests/rust_guests/callbackguest && cargo clippy --profile={{ if target == "debug" { "dev" } else { target } }} -- -D warnings cd src/tests/rust_guests/witguest && cargo clippy --profile={{ if target == "debug" { "dev" } else { target } }} -- -D warnings clippy-apply-fix-unix: diff --git a/c.just b/c.just index d83776cc5..aeed36808 100644 --- a/c.just +++ b/c.just @@ -16,14 +16,11 @@ build-rust-capi target=default-target: compile-c-guest target=default-target: # elf cd src/tests/c_guests/c_simpleguest && {{ mkdir }} "./out/{{target}}" && clang -c {{ c-compile-options-elf }} {{ if target == "debug" { c-flags-debug-elf } else { c-flags-release-elf } }} main.c {{c-include-flags-elf}} -o "out/{{ target }}/main.o" - cd src/tests/c_guests/c_callbackguest && {{ mkdir }} "./out/{{target}}" && clang -c {{ c-compile-options-elf }} {{ if target == "debug" { c-flags-debug-elf } else { c-flags-release-elf } }} main.c {{c-include-flags-elf}} -o "out/{{ target }}/main.o" link-c-guest target=default-target: # elf cd src/tests/c_guests/c_simpleguest && ld.lld -o out/{{target}}/simpleguest {{c-linker-options-elf}} out/{{target}}/main.o -l hyperlight_guest_capi -L "{{justfile_directory()}}/target/x86_64-unknown-none/{{target}}" - cd src/tests/c_guests/c_callbackguest && ld.lld -o out/{{target}}/callbackguest {{c-linker-options-elf}} out/{{target}}/main.o -l hyperlight_guest_capi -L "{{justfile_directory()}}/target/x86_64-unknown-none/{{target}}" move-c-guests target=default-target: # elf cp src/tests/c_guests/c_simpleguest/out/{{target}}/simpleguest src/tests/c_guests/bin/{{target}}/ - cp src/tests/c_guests/c_callbackguest/out/{{target}}/callbackguest src/tests/c_guests/bin/{{target}}/ diff --git a/src/hyperlight_host/src/lib.rs b/src/hyperlight_host/src/lib.rs index 9a32a9ecc..e1cc2e5a2 100644 --- a/src/hyperlight_host/src/lib.rs +++ b/src/hyperlight_host/src/lib.rs @@ -81,8 +81,7 @@ pub(crate) mod seccomp; /// Signal handling for Linux #[cfg(target_os = "linux")] pub(crate) mod signal_handlers; -/// Utilities for testing including interacting with `simpleguest.exe` -/// and `callbackguest.exe`, our two most basic guest binaries for testing +/// Utilities for testing including interacting with `simpleguest` testing guest binary #[cfg(test)] pub(crate) mod testing; diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index dc84c97a3..e3334fb3e 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -271,7 +271,7 @@ pub(crate) fn set_up_hypervisor_partition( #[cfg(test)] mod tests { - use hyperlight_testing::{callback_guest_as_string, simple_guest_as_string}; + use hyperlight_testing::simple_guest_as_string; use super::evolve_impl_multi_use; use crate::UninitializedSandbox; @@ -279,10 +279,7 @@ mod tests { #[test] fn test_evolve() { - let guest_bin_paths = vec![ - simple_guest_as_string().unwrap(), - callback_guest_as_string().unwrap(), - ]; + let guest_bin_paths = vec![simple_guest_as_string().unwrap()]; for guest_bin_path in guest_bin_paths { let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(guest_bin_path.clone()), None) diff --git a/src/hyperlight_host/tests/common/mod.rs b/src/hyperlight_host/tests/common/mod.rs index 39d08a3e5..ab1a97b71 100644 --- a/src/hyperlight_host/tests/common/mod.rs +++ b/src/hyperlight_host/tests/common/mod.rs @@ -15,10 +15,7 @@ limitations under the License. */ use hyperlight_host::func::HostFunction; use hyperlight_host::{GuestBinary, MultiUseSandbox, Result, UninitializedSandbox}; -use hyperlight_testing::{ - c_callback_guest_as_string, c_simple_guest_as_string, callback_guest_as_string, - simple_guest_as_string, -}; +use hyperlight_testing::{c_simple_guest_as_string, simple_guest_as_string}; /// Returns a rust/c simpleguest depending on environment variable GUEST. /// Uses rust guest by default. Run test with environment variable GUEST="c" to use the c version @@ -59,10 +56,10 @@ pub fn get_simpleguest_sandboxes( .collect() } -pub fn get_callbackguest_uninit_sandboxes( +pub fn get_uninit_simpleguest_sandboxes( writer: Option>, // An optional writer to make sure correct info is passed to the host printer ) -> Vec { - let elf_path = get_c_or_rust_callbackguest_path(); + let elf_path = get_c_or_rust_simpleguest_path(); let sandboxes = [ // in hypervisor elf @@ -89,13 +86,3 @@ pub(crate) fn get_c_or_rust_simpleguest_path() -> String { _ => panic!("Unknown guest type '{guest_type}', use either 'rust' or 'c'"), } } - -// returns the the path of callbackguest binary. Picks rust/ version depending on environment variable GUEST (or rust by default if unset) -fn get_c_or_rust_callbackguest_path() -> String { - let guest_type = std::env::var("GUEST").unwrap_or("rust".to_string()); - match guest_type.as_str() { - "rust" => callback_guest_as_string().unwrap(), - "c" => c_callback_guest_as_string().unwrap(), - _ => panic!("Unknown guest type '{guest_type}', use either 'rust' or 'c'"), - } -} diff --git a/src/hyperlight_host/tests/integration_test.rs b/src/hyperlight_host/tests/integration_test.rs index eceabd479..7d98532d3 100644 --- a/src/hyperlight_host/tests/integration_test.rs +++ b/src/hyperlight_host/tests/integration_test.rs @@ -24,9 +24,7 @@ use hyperlight_common::mem::PAGE_SIZE; use hyperlight_host::sandbox::SandboxConfiguration; use hyperlight_host::{GuestBinary, HyperlightError, MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::simplelogger::{LOGGER, SimpleLogger}; -use hyperlight_testing::{ - c_simple_guest_as_string, callback_guest_as_string, simple_guest_as_string, -}; +use hyperlight_testing::{c_simple_guest_as_string, simple_guest_as_string}; use log::LevelFilter; pub mod common; // pub to disable dead_code warning @@ -40,7 +38,7 @@ fn interrupt_host_call() { let barrier2 = barrier.clone(); let mut usbox = UninitializedSandbox::new( - GuestBinary::FilePath(callback_guest_as_string().expect("Guest Binary Missing")), + GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")), None, ) .unwrap(); @@ -312,7 +310,7 @@ fn interrupt_custom_signal_no_and_retry_delay() { #[test] fn interrupt_spamming_host_call() { let mut uninit = UninitializedSandbox::new( - GuestBinary::FilePath(callback_guest_as_string().unwrap()), + GuestBinary::FilePath(simple_guest_as_string().unwrap()), None, ) .unwrap(); diff --git a/src/hyperlight_host/tests/sandbox_host_tests.rs b/src/hyperlight_host/tests/sandbox_host_tests.rs index 32047653c..6c0247cf9 100644 --- a/src/hyperlight_host/tests/sandbox_host_tests.rs +++ b/src/hyperlight_host/tests/sandbox_host_tests.rs @@ -18,7 +18,7 @@ use core::f64; use std::sync::mpsc::channel; use std::sync::{Arc, Mutex}; -use common::new_uninit; +use common::{get_uninit_simpleguest_sandboxes, new_uninit}; use hyperlight_host::sandbox::SandboxConfiguration; use hyperlight_host::{ GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox, new_error, @@ -28,7 +28,7 @@ use hyperlight_testing::simple_guest_as_string; use serial_test::serial; // using LoadLibrary requires serial tests pub mod common; // pub to disable dead_code warning -use crate::common::{get_callbackguest_uninit_sandboxes, get_simpleguest_sandboxes}; +use crate::common::get_simpleguest_sandboxes; #[test] #[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests @@ -312,7 +312,7 @@ fn simple_test_parallel() { } fn callback_test_helper() -> Result<()> { - for mut sandbox in get_callbackguest_uninit_sandboxes(None).into_iter() { + for mut sandbox in get_uninit_simpleguest_sandboxes(None).into_iter() { // create host function let (tx, rx) = channel(); sandbox.register("HostMethod1", move |msg: String| { @@ -357,7 +357,7 @@ fn callback_test_parallel() { #[test] #[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn host_function_error() -> Result<()> { - for mut sandbox in get_callbackguest_uninit_sandboxes(None).into_iter() { + for mut sandbox in get_uninit_simpleguest_sandboxes(None).into_iter() { // create host function sandbox.register("HostMethod1", |_: String| -> Result { Err(new_error!("Host function error!")) diff --git a/src/hyperlight_testing/src/lib.rs b/src/hyperlight_testing/src/lib.rs index eb48e203a..c47b6c797 100644 --- a/src/hyperlight_testing/src/lib.rs +++ b/src/hyperlight_testing/src/lib.rs @@ -72,20 +72,12 @@ pub fn simple_guest_as_string() -> Result { .ok_or_else(|| anyhow!("couldn't convert simple guest PathBuf to string")) } -/// Get a fully qualified OS-specific path to the callbackguest elf binary -pub fn callback_guest_as_string() -> Result { - let buf = rust_guest_as_pathbuf("callbackguest"); - buf.to_str() - .map(|s| s.to_string()) - .ok_or_else(|| anyhow!("couldn't convert callback guest PathBuf to string")) -} - /// Get a fully-qualified OS-specific path to the witguest elf binary pub fn wit_guest_as_string() -> Result { let buf = rust_guest_as_pathbuf("witguest"); buf.to_str() .map(|s| s.to_string()) - .ok_or_else(|| anyhow!("couldn't convert callback guest PathBuf to string")) + .ok_or_else(|| anyhow!("couldn't convert wit guest PathBuf to string")) } /// Get a fully qualified OS-specific path to the dummyguest elf binary @@ -116,13 +108,6 @@ pub fn c_simple_guest_as_string() -> Result { .ok_or_else(|| anyhow!("couldn't convert simple guest PathBuf to string")) } -pub fn c_callback_guest_as_string() -> Result { - let buf = c_guest_as_pathbuf("callbackguest"); - buf.to_str() - .map(|s| s.to_string()) - .ok_or_else(|| anyhow!("couldn't convert callback guest PathBuf to string")) -} - /// Get a fully qualified path to a simple guest binary preferring a binary /// in the same directory as the parent executable. This will be used in /// fuzzing scenarios where pre-built binaries will be built and submitted to diff --git a/src/tests/c_guests/c_callbackguest/main.c b/src/tests/c_guests/c_callbackguest/main.c deleted file mode 100644 index e4fa2a678..000000000 --- a/src/tests/c_guests/c_callbackguest/main.c +++ /dev/null @@ -1,51 +0,0 @@ -// Included from hyperlight_guest_capi/include -#include "hyperlight_guest.h" -// Included from hyperlight_guest_bin/third_party/libc -#include "stdint.h" -#include "stdio.h" -#include "string.h" -// Included from hyperlight_guest_bin/third_party/printf -#include "printf.h" - -int print_output(const char *message) { - int res = printf("%s", message); - - return res; -} - -int guest_function(const char *from_host) { - char guest_message[256] = "Hello from GuestFunction1, "; - int len = strlen(from_host); - strncat(guest_message, from_host, len); - - hl_Parameter params = {.tag = hl_ParameterType_String, - .value = {.String = guest_message}}; - const hl_FunctionCall host_call = {.function_name = "HostMethod1", - .parameters = ¶ms, - .parameters_len = 1, - .return_type = hl_ReturnType_Int}; - hl_call_host_function(&host_call); - hl_get_host_return_value_as_Int(); - - return 0; -} - -HYPERLIGHT_WRAP_FUNCTION(print_output, Int, 1, String); -HYPERLIGHT_WRAP_FUNCTION(guest_function, Int, 1, String); - -void hyperlight_main(void) { - HYPERLIGHT_REGISTER_FUNCTION("PrintOutput", print_output); - HYPERLIGHT_REGISTER_FUNCTION("GuestMethod1", guest_function); -} - -// This dispatch function is only used when the host dispatches a guest function -// call but there is no registered guest function with the given name. -hl_Vec *c_guest_dispatch_function(const hl_FunctionCall *function_call) { - const char *func_name = function_call->function_name; - if (strcmp(func_name, "ThisIsNotARealFunctionButTheNameIsImportant") == 0) { - // This is special case for test `iostack_is_working - return hl_flatbuffer_result_from_Int(99); - } - - return NULL; -} diff --git a/src/tests/c_guests/c_simpleguest/main.c b/src/tests/c_guests/c_simpleguest/main.c index b7a9a596f..2822b108d 100644 --- a/src/tests/c_guests/c_simpleguest/main.c +++ b/src/tests/c_guests/c_simpleguest/main.c @@ -239,8 +239,26 @@ hl_Vec *twenty_four_k_in_eight_k_out(const hl_FunctionCall* params) { return hl_flatbuffer_result_from_Bytes(input.data, 8 * 1024); } +int guest_function(const char *from_host) { + char guest_message[256] = "Hello from GuestFunction1, "; + int len = strlen(from_host); + strncat(guest_message, from_host, len); + + hl_Parameter params = {.tag = hl_ParameterType_String, + .value = {.String = guest_message}}; + const hl_FunctionCall host_call = {.function_name = "HostMethod1", + .parameters = ¶ms, + .parameters_len = 1, + .return_type = hl_ReturnType_Int}; + hl_call_host_function(&host_call); + hl_get_host_return_value_as_Int(); + + return 0; +} + HYPERLIGHT_WRAP_FUNCTION(echo, String, 1, String) // HYPERLIGHT_WRAP_FUNCTION(set_byte_array_to_zero, 1, VecBytes) is not valid for functions that return VecBytes +HYPERLIGHT_WRAP_FUNCTION(guest_function, Int, 1, String) HYPERLIGHT_WRAP_FUNCTION(print_output, Int, 1, String) HYPERLIGHT_WRAP_FUNCTION(stack_allocate, Int, 1, Int) HYPERLIGHT_WRAP_FUNCTION(stack_overflow, Int, 1, Int) @@ -275,6 +293,7 @@ void hyperlight_main(void) // HYPERLIGHT_REGISTER_FUNCTION macro does not work for functions that return VecBytes, // so we use hl_register_function_definition directly hl_register_function_definition("SetByteArrayToZero", set_byte_array_to_zero, 1, (hl_ParameterType[]){hl_ParameterType_VecBytes}, hl_ReturnType_VecBytes); + HYPERLIGHT_REGISTER_FUNCTION("GuestMethod1", guest_function); HYPERLIGHT_REGISTER_FUNCTION("PrintOutput", print_output); HYPERLIGHT_REGISTER_FUNCTION("StackAllocate", stack_allocate); HYPERLIGHT_REGISTER_FUNCTION("StackOverflow", stack_overflow); diff --git a/src/tests/rust_guests/callbackguest/.cargo/config.toml b/src/tests/rust_guests/callbackguest/.cargo/config.toml deleted file mode 100644 index f977e97ab..000000000 --- a/src/tests/rust_guests/callbackguest/.cargo/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[build] -target = "x86_64-unknown-none" - -[target.x86_64-unknown-none] -rustflags = [ - "-C", - "code-model=small", - "-C", - "link-args=-e entrypoint", -] -linker = "rust-lld" - -[profile.release] -opt-level = 0 -panic = "abort" - -[profile.dev] -opt-level = 0 -panic = "abort" \ No newline at end of file diff --git a/src/tests/rust_guests/callbackguest/Cargo.lock b/src/tests/rust_guests/callbackguest/Cargo.lock deleted file mode 100644 index c899d36c5..000000000 --- a/src/tests/rust_guests/callbackguest/Cargo.lock +++ /dev/null @@ -1,271 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "anyhow" -version = "1.0.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "bitflags" -version = "2.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" - -[[package]] -name = "buddy_system_allocator" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0108968a3a2dab95b089c0fc3f1afa7759aa5ebe6f1d86d206d6f7ba726eb" -dependencies = [ - "spin 0.9.8", -] - -[[package]] -name = "callbackguest" -version = "0.9.0" -dependencies = [ - "hyperlight-common", - "hyperlight-guest", - "hyperlight-guest-bin", - "hyperlight-guest-tracing", -] - -[[package]] -name = "cc" -version = "1.2.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" - -[[package]] -name = "flatbuffers" -version = "25.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1045398c1bfd89168b5fd3f1fc11f6e70b34f6f66300c87d44d3de849463abf1" -dependencies = [ - "bitflags", - "rustc_version", -] - -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - -[[package]] -name = "hyperlight-common" -version = "0.9.0" -dependencies = [ - "anyhow", - "flatbuffers", - "log", - "spin 0.10.0", -] - -[[package]] -name = "hyperlight-guest" -version = "0.9.0" -dependencies = [ - "anyhow", - "flatbuffers", - "hyperlight-common", - "hyperlight-guest-tracing", - "serde_json", -] - -[[package]] -name = "hyperlight-guest-bin" -version = "0.9.0" -dependencies = [ - "buddy_system_allocator", - "cc", - "cfg-if", - "glob", - "hyperlight-common", - "hyperlight-guest", - "hyperlight-guest-tracing", - "log", - "spin 0.10.0", -] - -[[package]] -name = "hyperlight-guest-tracing" -version = "0.9.0" -dependencies = [ - "hyperlight-common", - "hyperlight-guest-tracing-macro", - "spin 0.10.0", -] - -[[package]] -name = "hyperlight-guest-tracing-macro" -version = "0.9.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "lock_api" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" - -[[package]] -name = "memchr" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" - -[[package]] -name = "proc-macro2" -version = "1.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.143" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "spin" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" -dependencies = [ - "lock_api", -] - -[[package]] -name = "syn" -version = "2.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" diff --git a/src/tests/rust_guests/callbackguest/Cargo.toml b/src/tests/rust_guests/callbackguest/Cargo.toml deleted file mode 100644 index fdb6ddbb2..000000000 --- a/src/tests/rust_guests/callbackguest/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "callbackguest" -version = "0.9.0" -edition = "2021" - -[dependencies] -hyperlight-guest = { path = "../../../hyperlight_guest" } -hyperlight-guest-bin = { path = "../../../hyperlight_guest_bin" } -hyperlight-common = { path = "../../../hyperlight_common", default-features = false } -hyperlight-guest-tracing = { path = "../../../hyperlight_guest_tracing" } - -[features] -default = [] -trace_guest = ["hyperlight-guest-bin/trace_guest", "hyperlight-guest/trace_guest", "hyperlight-guest-tracing/trace"] -unwind_guest = ["hyperlight-common/unwind_guest"] -mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] diff --git a/src/tests/rust_guests/callbackguest/src/main.rs b/src/tests/rust_guests/callbackguest/src/main.rs deleted file mode 100644 index d217ccd88..000000000 --- a/src/tests/rust_guests/callbackguest/src/main.rs +++ /dev/null @@ -1,278 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -#![no_std] -#![no_main] - -extern crate alloc; -extern crate hyperlight_guest; - -use alloc::format; -use alloc::string::ToString; -use alloc::vec::Vec; - -use hyperlight_common::flatbuffer_wrappers::function_call::FunctionCall; -use hyperlight_common::flatbuffer_wrappers::function_types::{ - ParameterType, ParameterValue, ReturnType, -}; -use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; -use hyperlight_common::flatbuffer_wrappers::guest_log_level::LogLevel; -use hyperlight_common::flatbuffer_wrappers::util::get_flatbuffer_result; -use hyperlight_guest::error::{HyperlightGuestError, Result}; -use hyperlight_guest_bin::guest_function::definition::GuestFunctionDefinition; -use hyperlight_guest_bin::guest_function::register::register_function; -use hyperlight_guest_bin::guest_logger::log_message; -use hyperlight_guest_bin::host_comm::{call_host_function, print_output_with_host_print}; - -#[hyperlight_guest_tracing::trace_function] -fn send_message_to_host_method( - method_name: &str, - guest_message: &str, - message: &str, -) -> Result> { - let message = format!("{}{}", guest_message, message); - let res = call_host_function::( - method_name, - Some(Vec::from(&[ParameterValue::String(message.to_string())])), - ReturnType::Int, - )?; - - Ok(get_flatbuffer_result(res)) -} - -#[hyperlight_guest_tracing::trace_function] -fn guest_function(function_call: &FunctionCall) -> Result> { - if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { - send_message_to_host_method("HostMethod", "Hello from GuestFunction, ", message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to guest_function".to_string(), - )) - } -} - -#[hyperlight_guest_tracing::trace_function] -fn guest_function1(function_call: &FunctionCall) -> Result> { - if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { - send_message_to_host_method("HostMethod1", "Hello from GuestFunction1, ", message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to guest_function1".to_string(), - )) - } -} - -#[hyperlight_guest_tracing::trace_function] -fn guest_function2(function_call: &FunctionCall) -> Result> { - if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { - send_message_to_host_method("HostMethod1", "Hello from GuestFunction2, ", message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to guest_function2".to_string(), - )) - } -} - -#[hyperlight_guest_tracing::trace_function] -fn guest_function3(function_call: &FunctionCall) -> Result> { - if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { - send_message_to_host_method("HostMethod1", "Hello from GuestFunction3, ", message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to guest_function3".to_string(), - )) - } -} - -#[hyperlight_guest_tracing::trace_function] -fn guest_function4(_: &FunctionCall) -> Result> { - call_host_function::<()>( - "HostMethod4", - Some(Vec::from(&[ParameterValue::String( - "Hello from GuestFunction4".to_string(), - )])), - ReturnType::Void, - )?; - - Ok(get_flatbuffer_result(())) -} - -#[hyperlight_guest_tracing::trace_function] -fn guest_log_message(function_call: &FunctionCall) -> Result> { - if let ( - ParameterValue::String(message), - ParameterValue::String(source), - ParameterValue::Int(level), - ) = ( - &function_call.parameters.as_ref().unwrap()[0], - &function_call.parameters.as_ref().unwrap()[1], - &function_call.parameters.as_ref().unwrap()[2], - ) { - let mut log_level = *level; - if !(0..=6).contains(&log_level) { - log_level = 0; - } - - log_message( - LogLevel::from(log_level as u8), - message, - source, - "guest_log_message", - file!(), - line!(), - ); - - Ok(get_flatbuffer_result(message.len() as i32)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to guest_log_message".to_string(), - )) - } -} - -#[hyperlight_guest_tracing::trace_function] -fn call_error_method(function_call: &FunctionCall) -> Result> { - if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { - send_message_to_host_method("ErrorMethod", "Error From Host: ", message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to call_error_method".to_string(), - )) - } -} - -#[hyperlight_guest_tracing::trace_function] -fn call_host_spin(_: &FunctionCall) -> Result> { - call_host_function::<()>("Spin", None, ReturnType::Void)?; - Ok(get_flatbuffer_result(())) -} - -#[hyperlight_guest_tracing::trace_function] -fn host_call_loop(function_call: &FunctionCall) -> Result> { - if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { - loop { - call_host_function::<()>(message, None, ReturnType::Void).unwrap(); - } - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to host_call_loop".to_string(), - )) - } -} - -#[no_mangle] -#[hyperlight_guest_tracing::trace_function] -pub extern "C" fn hyperlight_main() { - let print_output_def = GuestFunctionDefinition::new( - "PrintOutput".to_string(), - Vec::from(&[ParameterType::String]), - ReturnType::Int, - print_output_with_host_print as usize, - ); - register_function(print_output_def); - - let guest_function_def = GuestFunctionDefinition::new( - "GuestMethod".to_string(), - Vec::from(&[ParameterType::String]), - ReturnType::Int, - guest_function as usize, - ); - register_function(guest_function_def); - - let guest_function1_def = GuestFunctionDefinition::new( - "GuestMethod1".to_string(), - Vec::from(&[ParameterType::String]), - ReturnType::Int, - guest_function1 as usize, - ); - register_function(guest_function1_def); - - let guest_function2_def = GuestFunctionDefinition::new( - "GuestMethod2".to_string(), - Vec::from(&[ParameterType::String]), - ReturnType::Int, - guest_function2 as usize, - ); - register_function(guest_function2_def); - - let guest_function3_def = GuestFunctionDefinition::new( - "GuestMethod3".to_string(), - Vec::from(&[ParameterType::String]), - ReturnType::Int, - guest_function3 as usize, - ); - register_function(guest_function3_def); - - let guest_function4_def = GuestFunctionDefinition::new( - "GuestMethod4".to_string(), - Vec::new(), - ReturnType::Int, - guest_function4 as usize, - ); - register_function(guest_function4_def); - - let guest_log_message_def = GuestFunctionDefinition::new( - "LogMessage".to_string(), - Vec::from(&[ - ParameterType::String, - ParameterType::String, - ParameterType::Int, - ]), - ReturnType::Int, - guest_log_message as usize, - ); - register_function(guest_log_message_def); - - let call_error_method_def = GuestFunctionDefinition::new( - "CallErrorMethod".to_string(), - Vec::from(&[ParameterType::String]), - ReturnType::Int, - call_error_method as usize, - ); - register_function(call_error_method_def); - - let call_host_spin_def = GuestFunctionDefinition::new( - "CallHostSpin".to_string(), - Vec::new(), - ReturnType::Int, - call_host_spin as usize, - ); - register_function(call_host_spin_def); - - let host_call_loop_def = GuestFunctionDefinition::new( - "HostCallLoop".to_string(), - Vec::from(&[ParameterType::String]), - ReturnType::Void, - host_call_loop as usize, - ); - register_function(host_call_loop_def); -} - -#[no_mangle] -#[hyperlight_guest_tracing::trace_function] -pub fn guest_dispatch_function(function_call: FunctionCall) -> Result> { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionNotFound, - function_call.function_name.clone(), - )) -} diff --git a/src/tests/rust_guests/dummyguest/Cargo.lock b/src/tests/rust_guests/dummyguest/Cargo.lock index e93ad50ef..fa3de189b 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.lock +++ b/src/tests/rust_guests/dummyguest/Cargo.lock @@ -140,9 +140,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index c3b17ad58..d4d81d57f 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -46,7 +46,8 @@ use hyperlight_guest::exit::{abort_with_code, abort_with_code_and_message}; use hyperlight_guest_bin::guest_function::definition::GuestFunctionDefinition; use hyperlight_guest_bin::guest_function::register::register_function; use hyperlight_guest_bin::host_comm::{ - call_host_function, call_host_function_without_returning_result, read_n_bytes_from_user_memory, + call_host_function, call_host_function_without_returning_result, print_output_with_host_print, + read_n_bytes_from_user_memory, }; use hyperlight_guest_bin::memory::malloc; use hyperlight_guest_bin::{MIN_STACK_ADDRESS, guest_logger}; @@ -975,6 +976,90 @@ pub extern "C" fn hyperlight_main() { ); register_function(simple_print_output_def); + let print_output_def = GuestFunctionDefinition::new( + "PrintOutputWithHostPrint".to_string(), + Vec::from(&[ParameterType::String]), + ReturnType::Int, + print_output_with_host_print as usize, + ); + register_function(print_output_def); + + let guest_function_def = GuestFunctionDefinition::new( + "GuestMethod".to_string(), + Vec::from(&[ParameterType::String]), + ReturnType::Int, + guest_function as usize, + ); + register_function(guest_function_def); + + let guest_function1_def = GuestFunctionDefinition::new( + "GuestMethod1".to_string(), + Vec::from(&[ParameterType::String]), + ReturnType::Int, + guest_function1 as usize, + ); + register_function(guest_function1_def); + + let guest_function2_def = GuestFunctionDefinition::new( + "GuestMethod2".to_string(), + Vec::from(&[ParameterType::String]), + ReturnType::Int, + guest_function2 as usize, + ); + register_function(guest_function2_def); + + let guest_function3_def = GuestFunctionDefinition::new( + "GuestMethod3".to_string(), + Vec::from(&[ParameterType::String]), + ReturnType::Int, + guest_function3 as usize, + ); + register_function(guest_function3_def); + + let guest_function4_def = GuestFunctionDefinition::new( + "GuestMethod4".to_string(), + Vec::new(), + ReturnType::Int, + guest_function4 as usize, + ); + register_function(guest_function4_def); + + let guest_log_message_def = GuestFunctionDefinition::new( + "LogMessageWithSource".to_string(), + Vec::from(&[ + ParameterType::String, + ParameterType::String, + ParameterType::Int, + ]), + ReturnType::Int, + guest_log_message as usize, + ); + register_function(guest_log_message_def); + + let call_error_method_def = GuestFunctionDefinition::new( + "CallErrorMethod".to_string(), + Vec::from(&[ParameterType::String]), + ReturnType::Int, + call_error_method as usize, + ); + register_function(call_error_method_def); + + let call_host_spin_def = GuestFunctionDefinition::new( + "CallHostSpin".to_string(), + Vec::new(), + ReturnType::Int, + call_host_spin as usize, + ); + register_function(call_host_spin_def); + + let host_call_loop_def = GuestFunctionDefinition::new( + "HostCallLoop".to_string(), + Vec::from(&[ParameterType::String]), + ReturnType::Void, + host_call_loop as usize, + ); + register_function(host_call_loop_def); + let print_using_printf_def = GuestFunctionDefinition::new( "PrintUsingPrintf".to_string(), Vec::from(&[ParameterType::String]), @@ -1368,6 +1453,179 @@ pub extern "C" fn hyperlight_main() { register_function(call_given_hostfunc_def); } +#[hyperlight_guest_tracing::trace_function] +fn send_message_to_host_method( + method_name: &str, + guest_message: &str, + message: &str, +) -> Result> { + let message = format!("{}{}", guest_message, message); + let res = call_host_function::( + method_name, + Some(Vec::from(&[ParameterValue::String(message.to_string())])), + ReturnType::Int, + )?; + + Ok(get_flatbuffer_result(res)) +} + +#[hyperlight_guest_tracing::trace_function] +fn guest_function(function_call: &FunctionCall) -> Result> { + if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { + send_message_to_host_method("HostMethod", "Hello from GuestFunction, ", message) + } else { + Err(HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + "Invalid parameters passed to guest_function".to_string(), + )) + } +} + +#[hyperlight_guest_tracing::trace_function] +fn guest_function1(function_call: &FunctionCall) -> Result> { + if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { + send_message_to_host_method("HostMethod1", "Hello from GuestFunction1, ", message) + } else { + Err(HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + "Invalid parameters passed to guest_function1".to_string(), + )) + } +} + +#[hyperlight_guest_tracing::trace_function] +fn guest_function2(function_call: &FunctionCall) -> Result> { + if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { + send_message_to_host_method("HostMethod1", "Hello from GuestFunction2, ", message) + } else { + Err(HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + "Invalid parameters passed to guest_function2".to_string(), + )) + } +} + +#[hyperlight_guest_tracing::trace_function] +fn guest_function3(function_call: &FunctionCall) -> Result> { + if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { + send_message_to_host_method("HostMethod1", "Hello from GuestFunction3, ", message) + } else { + Err(HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + "Invalid parameters passed to guest_function3".to_string(), + )) + } +} + +#[hyperlight_guest_tracing::trace_function] +fn guest_function4(_: &FunctionCall) -> Result> { + call_host_function::<()>( + "HostMethod4", + Some(Vec::from(&[ParameterValue::String( + "Hello from GuestFunction4".to_string(), + )])), + ReturnType::Void, + )?; + + Ok(get_flatbuffer_result(())) +} + +#[hyperlight_guest_tracing::trace_function] +fn guest_log_message(function_call: &FunctionCall) -> Result> { + if let ( + ParameterValue::String(message), + ParameterValue::String(source), + ParameterValue::Int(level), + ) = ( + &function_call.parameters.as_ref().unwrap()[0], + &function_call.parameters.as_ref().unwrap()[1], + &function_call.parameters.as_ref().unwrap()[2], + ) { + let mut log_level = *level; + if !(0..=6).contains(&log_level) { + log_level = 0; + } + + guest_logger::log_message( + LogLevel::from(log_level as u8), + message, + source, + "guest_log_message", + file!(), + line!(), + ); + + Ok(get_flatbuffer_result(message.len() as i32)) + } else { + Err(HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + "Invalid parameters passed to guest_log_message".to_string(), + )) + } +} + +#[hyperlight_guest_tracing::trace_function] +fn call_error_method(function_call: &FunctionCall) -> Result> { + if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { + send_message_to_host_method("ErrorMethod", "Error From Host: ", message) + } else { + Err(HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + "Invalid parameters passed to call_error_method".to_string(), + )) + } +} + +#[hyperlight_guest_tracing::trace_function] +fn call_host_spin(_: &FunctionCall) -> Result> { + call_host_function::<()>("Spin", None, ReturnType::Void)?; + Ok(get_flatbuffer_result(())) +} + +#[hyperlight_guest_tracing::trace_function] +fn host_call_loop(function_call: &FunctionCall) -> Result> { + if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { + loop { + call_host_function::<()>(message, None, ReturnType::Void).unwrap(); + } + } else { + Err(HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + "Invalid parameters passed to host_call_loop".to_string(), + )) + } +} + +// Interprets the given guest function call as a host function call and dispatches it to the host. +#[hyperlight_guest_tracing::trace_function] +fn fuzz_host_function(func: FunctionCall) -> Result> { + let mut params = func.parameters.unwrap(); + // first parameter must be string (the name of the host function to call) + let host_func_name = match params.remove(0) { + // TODO use `swap_remove` instead of `remove` if performance is an issue, but left out + // to avoid confusion for replicating failure cases + ParameterValue::String(name) => name, + _ => { + return Err(HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + "Invalid parameters passed to fuzz_host_function".to_string(), + )); + } + }; + + // Because we do not know at compile time the actual return type of the host function to be called + // we cannot use the `call_host_function` generic function. + // We need to use the `call_host_function_without_returning_result` function that does not retrieve the return + // value + call_host_function_without_returning_result( + &host_func_name, + Some(params), + func.expected_return_type, + ) + .expect("failed to call host function"); + Ok(get_flatbuffer_result(())) +} + #[no_mangle] #[hyperlight_guest_tracing::trace_function] pub fn guest_dispatch_function(function_call: FunctionCall) -> Result> { @@ -1413,33 +1671,3 @@ pub fn guest_dispatch_function(function_call: FunctionCall) -> Result> { Ok(get_flatbuffer_result(99)) } - -// Interprets the given guest function call as a host function call and dispatches it to the host. -#[hyperlight_guest_tracing::trace_function] -fn fuzz_host_function(func: FunctionCall) -> Result> { - let mut params = func.parameters.unwrap(); - // first parameter must be string (the name of the host function to call) - let host_func_name = match params.remove(0) { - // TODO use `swap_remove` instead of `remove` if performance is an issue, but left out - // to avoid confusion for replicating failure cases - ParameterValue::String(name) => name, - _ => { - return Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to fuzz_host_function".to_string(), - )); - } - }; - - // Because we do not know at compile time the actual return type of the host function to be called - // we cannot use the `call_host_function` generic function. - // We need to use the `call_host_function_without_returning_result` function that does not retrieve the return - // value - call_host_function_without_returning_result( - &host_func_name, - Some(params), - func.expected_return_type, - ) - .expect("failed to call host function"); - Ok(get_flatbuffer_result(())) -} diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index 8bf176fa6..762a25e97 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -325,9 +325,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" @@ -521,9 +521,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "wasmparser" -version = "0.238.0" +version = "0.238.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ad4ca2ecb86b79ea410cd970985665de1d05774b7107b214bc5852b1bcbad7" +checksum = "3fa99c8328024423875ae4a55345cfde8f0371327fb2d0f33b0f52a06fc44408" dependencies = [ "bitflags", "hashbrown", From 5acd1a40a03fa52aac81c2f63927f6604d0eb2ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Sep 2025 18:57:59 +0000 Subject: [PATCH 156/271] Bump wasmparser from 0.238.1 to 0.239.0 (#874) Bumps [wasmparser](https://github.com/bytecodealliance/wasm-tools) from 0.238.1 to 0.239.0. - [Release notes](https://github.com/bytecodealliance/wasm-tools/releases) - [Commits](https://github.com/bytecodealliance/wasm-tools/commits) --- updated-dependencies: - dependency-name: wasmparser dependency-version: 0.239.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 072b85b2a..4600b67ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4013,9 +4013,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.238.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fa99c8328024423875ae4a55345cfde8f0371327fb2d0f33b0f52a06fc44408" +checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" dependencies = [ "bitflags 2.9.4", "hashbrown", diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index 559112b52..69eb27006 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -16,7 +16,7 @@ name = "hyperlight_component_macro" proc-macro = true [dependencies] -wasmparser = { version = "0.238.1" } +wasmparser = { version = "0.239.0" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index de650651c..9abbdd845 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -15,7 +15,7 @@ Shared implementation for the procedural macros that generate Hyperlight host an name = "hyperlight_component_util" [dependencies] -wasmparser = { version = "0.238.1" } +wasmparser = { version = "0.239.0" } quote = { version = "1.0.38" } proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } From d8b96fe40be003ad5895225315122161d9ea5d1b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Sep 2025 18:58:05 +0000 Subject: [PATCH 157/271] Bump tempfile from 3.21.0 to 3.22.0 (#873) Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.21.0 to 3.22.0. - [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md) - [Commits](https://github.com/Stebalien/tempfile/compare/v3.21.0...v3.22.0) --- updated-dependencies: - dependency-name: tempfile dependency-version: 3.22.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4600b67ec..a1f985d20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3333,15 +3333,15 @@ checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" [[package]] name = "tempfile" -version = "3.21.0" +version = "3.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" +checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 49b638895..6c32c40d7 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -87,7 +87,7 @@ signal-hook-registry = "1.4.6" envy = { version = "0.4.2" } serde = "1.0" proptest = "1.7.0" -tempfile = "3.21.0" +tempfile = "3.22.0" crossbeam-queue = "0.3.12" tracing-serde = "0.2.0" serial_test = "3.1.1" From a71c03c1bd888052aa0685cbf9eebc37fec1d782 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Tue, 9 Sep 2025 20:07:20 +0100 Subject: [PATCH 158/271] Update readme to remove some pre-reqs (#875) Signed-off-by: Simon Davies --- README.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 7dbf56e50..eed169cfc 100644 --- a/README.md +++ b/README.md @@ -198,13 +198,9 @@ After having an environment with a hypervisor setup, running the example has the ```sh wget https://apt.llvm.org/llvm.sh chmod +x ./llvm.sh - sudo ./llvm.sh 17 all - sudo ln -s /usr/lib/llvm-17/bin/clang-cl /usr/bin/clang-cl - sudo ln -s /usr/lib/llvm-17/bin/llvm-lib /usr/bin/llvm-lib - sudo ln -s /usr/lib/llvm-17/bin/lld-link /usr/bin/lld-link - sudo ln -s /usr/lib/llvm-17/bin/llvm-ml /usr/bin/llvm-ml - sudo ln -s /usr/lib/llvm-17/bin/ld.lld /usr/bin/ld.lld - sudo ln -s /usr/lib/llvm-17/bin/clang /usr/bin/clang + sudo ./llvm.sh 18 clang clang-tools-extra + sudo ln -s /usr/lib/llvm-18/bin/ld.lld /usr/bin/ld.lld + sudo ln -s /usr/lib/llvm-18/bin/clang /usr/bin/clang ``` - On Windows, see [this](https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild?view=msvc-170). @@ -212,9 +208,10 @@ After having an environment with a hypervisor setup, running the example has the - On Azure Linux, run: ```sh - sudo dnf remove clang -y || true - sudo dnf install clang17 -y - sudo dnf install clang17-tools-extra -y + if ! command -v clang > /dev/null 2>&1; then + sudo dnf install clang -y + sudo dnf install clang-tools-extra -y + fi ``` Then, we are ready to build and run the example: From f3e96383716464690a28af175d9b3b71e78c147a Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Tue, 9 Sep 2025 22:13:03 +0100 Subject: [PATCH 159/271] Update devcontainer llvm version to 18 (#877) Remove some llvm components, remove links for windows tools Signed-off-by: Simon Davies --- .devcontainer/Dockerfile | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index db7867495..ee79b5dff 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -24,16 +24,12 @@ RUN apt-get update \ sudo \ wget -ARG LLVM_VERSION=17 +ARG LLVM_VERSION=18 # Install llvm RUN wget https://apt.llvm.org/llvm.sh \ && chmod +x ./llvm.sh \ - && sudo ./llvm.sh ${LLVM_VERSION} all \ - && sudo ln -s /usr/lib/llvm-${LLVM_VERSION}/bin/clang-cl /usr/bin/clang-cl \ - && sudo ln -s /usr/lib/llvm-${LLVM_VERSION}/bin/llvm-lib /usr/bin/llvm-lib \ - && sudo ln -s /usr/lib/llvm-${LLVM_VERSION}/bin/lld-link /usr/bin/lld-link \ - && sudo ln -s /usr/lib/llvm-${LLVM_VERSION}/bin/llvm-ml /usr/bin/llvm-ml \ + && sudo ./llvm.sh ${LLVM_VERSION} clang clang-tools-extra \ && sudo ln -s /usr/lib/llvm-${LLVM_VERSION}/bin/ld.lld /usr/bin/ld.lld \ && sudo ln -s /usr/lib/llvm-${LLVM_VERSION}/bin/clang /usr/bin/clang From 1de203d083d35178a352d99026f4a51a2797b626 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Tue, 9 Sep 2025 22:14:08 +0100 Subject: [PATCH 160/271] Add missing benchmark runs for windows server 2025 (#876) Signed-off-by: Simon Davies --- .github/workflows/Benchmarks.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/Benchmarks.yml b/.github/workflows/Benchmarks.yml index 048b788cb..8bbd983a0 100644 --- a/.github/workflows/Benchmarks.yml +++ b/.github/workflows/Benchmarks.yml @@ -14,15 +14,18 @@ jobs: # its execution. this dependency should be expressed in the dependent # workflow benchmark: + timeout-minutes: 60 strategy: fail-fast: true matrix: - hypervisor: [hyperv, mshv, mshv3, kvm] # hyperv is windows, mshv and kvm are linux + hypervisor: [hyperv, 'hyperv-ws2025', mshv, mshv3, kvm] # hyperv,hyperv-ws2025 are windows, mshv, mshv3 and kvm are linux cpu: [amd, intel] - config: [release] # don't want to benchmark debug-builds - - runs-on: ${{ fromJson(format('["self-hosted", "{0}", "X64", "1ES.Pool=hld-{1}-{2}"]', matrix.hypervisor == 'hyperv' && 'Windows' || 'Linux', matrix.hypervisor == 'hyperv' && 'win2022' || matrix.hypervisor == 'mshv3' && 'azlinux3-mshv' || matrix.hypervisor, matrix.cpu)) }} - + config: [release] + runs-on: ${{ fromJson( + format('["self-hosted", "{0}", "X64", "1ES.Pool=hld-{1}-{2}"]', + (matrix.hypervisor == 'hyperv' || matrix.hypervisor == 'hyperv-ws2025') && 'Windows' || 'Linux', + matrix.hypervisor == 'hyperv' && 'win2022' || matrix.hypervisor == 'hyperv-ws2025' && 'win2025' || matrix.hypervisor == 'mshv3' && 'azlinux3-mshv' || matrix.hypervisor, + matrix.cpu)) }} steps: ### Setup ### From f154d8e5db159689e17ad5cdab50d28eb49f16d7 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Tue, 9 Sep 2025 14:15:33 -0700 Subject: [PATCH 161/271] Remove serial testing (#878) we no longer need it since we don't support running in-process Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- Cargo.lock | 57 ------------------- src/hyperlight_host/Cargo.toml | 1 - .../hypervisor/surrogate_process_manager.rs | 2 - .../tests/sandbox_host_tests.rs | 15 ----- 4 files changed, 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1f985d20..7b95df4d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -921,21 +921,6 @@ dependencies = [ "pe-unwind-info", ] -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.31" @@ -998,7 +983,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ - "futures-channel", "futures-core", "futures-io", "futures-macro", @@ -1486,7 +1470,6 @@ dependencies = [ "seccompiler", "serde", "serde_json", - "serial_test", "sha256", "signal-hook-registry", "tempfile", @@ -3020,15 +3003,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scc" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" -dependencies = [ - "sdd", -] - [[package]] name = "scoped-tls" version = "1.0.1" @@ -3061,12 +3035,6 @@ dependencies = [ "syn", ] -[[package]] -name = "sdd" -version = "3.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" - [[package]] name = "seccompiler" version = "0.5.0" @@ -3135,31 +3103,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serial_test" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" -dependencies = [ - "futures", - "log", - "once_cell", - "parking_lot", - "scc", - "serial_test_derive", -] - -[[package]] -name = "serial_test_derive" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "sha2" version = "0.10.9" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 6c32c40d7..ea934c696 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -90,7 +90,6 @@ proptest = "1.7.0" tempfile = "3.22.0" crossbeam-queue = "0.3.12" tracing-serde = "0.2.0" -serial_test = "3.1.1" hyperlight-testing = { workspace = true } env_logger = "0.11.8" tracing-forest = { version = "0.2.0", features = ["uuid", "chrono", "smallvec", "serde", "env-filter"] } diff --git a/src/hyperlight_host/src/hypervisor/surrogate_process_manager.rs b/src/hyperlight_host/src/hypervisor/surrogate_process_manager.rs index dbef96a93..6724f2c6d 100644 --- a/src/hyperlight_host/src/hypervisor/surrogate_process_manager.rs +++ b/src/hyperlight_host/src/hypervisor/surrogate_process_manager.rs @@ -422,7 +422,6 @@ mod tests { use hyperlight_common::mem::PAGE_SIZE_USIZE; use rand::{Rng, rng}; - use serial_test::serial; use windows::Win32::Foundation::{CloseHandle, HANDLE, INVALID_HANDLE_VALUE}; use windows::Win32::System::Diagnostics::ToolHelp::{ CreateToolhelp32Snapshot, PROCESSENTRY32, Process32First, Process32Next, TH32CS_SNAPPROCESS, @@ -437,7 +436,6 @@ mod tests { use super::*; use crate::mem::shared_mem::{ExclusiveSharedMemory, SharedMemory}; #[test] - #[serial] fn test_surrogate_process_manager() { let mut threads = Vec::new(); // create more threads than surrogate processes as we want to test that diff --git a/src/hyperlight_host/tests/sandbox_host_tests.rs b/src/hyperlight_host/tests/sandbox_host_tests.rs index 6c0247cf9..5255cd811 100644 --- a/src/hyperlight_host/tests/sandbox_host_tests.rs +++ b/src/hyperlight_host/tests/sandbox_host_tests.rs @@ -24,14 +24,11 @@ use hyperlight_host::{ GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox, new_error, }; use hyperlight_testing::simple_guest_as_string; -#[cfg(target_os = "windows")] -use serial_test::serial; // using LoadLibrary requires serial tests pub mod common; // pub to disable dead_code warning use crate::common::get_simpleguest_sandboxes; #[test] -#[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn pass_byte_array() { for mut sandbox in get_simpleguest_sandboxes(None).into_iter() { const LEN: usize = 10; @@ -49,7 +46,6 @@ fn pass_byte_array() { #[test] #[ignore = "Fails with mismatched float only when c .exe guest?!"] -#[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn float_roundtrip() { let doubles = [ 0.0, @@ -107,7 +103,6 @@ fn float_roundtrip() { } #[test] -#[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn invalid_guest_function_name() { for mut sandbox in get_simpleguest_sandboxes(None).into_iter() { let fn_name = "FunctionDoesntExist"; @@ -120,7 +115,6 @@ fn invalid_guest_function_name() { } #[test] -#[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn set_static() { for mut sandbox in get_simpleguest_sandboxes(None).into_iter() { let fn_name = "SetStatic"; @@ -133,7 +127,6 @@ fn set_static() { } #[test] -#[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn multiple_parameters() { let (tx, rx) = channel(); let writer = move |msg: String| { @@ -181,7 +174,6 @@ fn multiple_parameters() { } #[test] -#[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn incorrect_parameter_type() { for mut sandbox in get_simpleguest_sandboxes(None) { let res = sandbox.call::( @@ -199,7 +191,6 @@ fn incorrect_parameter_type() { } #[test] -#[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn incorrect_parameter_num() { for mut sandbox in get_simpleguest_sandboxes(None).into_iter() { let res = sandbox.call::("Echo", ("1".to_string(), 2_i32)); @@ -229,7 +220,6 @@ fn max_memory_sandbox() { } #[test] -#[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn iostack_is_working() { for mut sandbox in get_simpleguest_sandboxes(None).into_iter() { let res: i32 = sandbox @@ -290,13 +280,11 @@ fn simple_test_helper() -> Result<()> { } #[test] -#[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn simple_test() { simple_test_helper().unwrap(); } #[test] -#[cfg(target_os = "linux")] fn simple_test_parallel() { let handles: Vec<_> = (0..50) .map(|_| { @@ -333,13 +321,11 @@ fn callback_test_helper() -> Result<()> { } #[test] -#[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn callback_test() { callback_test_helper().unwrap(); } #[test] -#[cfg(target_os = "linux")] // windows can't run parallel with LoadLibrary fn callback_test_parallel() { let handles: Vec<_> = (0..100) .map(|_| { @@ -355,7 +341,6 @@ fn callback_test_parallel() { } #[test] -#[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn host_function_error() -> Result<()> { for mut sandbox in get_uninit_simpleguest_sandboxes(None).into_iter() { // create host function From 6432590a78b59c5332d45048ea2cd614365b9dc9 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Tue, 9 Sep 2025 17:27:01 -0700 Subject: [PATCH 162/271] Remove Allocations from Panic Handler (#818) * Update cargo hash in flake.nix Signed-off-by: adamperlin * Remove allocations in panic handler by formatting panic message using a new FixedStringBuf type backed by a static mut array. Adds a test to verify that StackOverflow no longer occurs on OOM panic Signed-off-by: adamperlin * Clear buffer before recursive panics Add some docstrings Signed-off-by: adamperlin * Update cargoHash in flake.nix Signed-off-by: adamperlin * Remove unused imports Signed-off-by: adamperlin * Add copyright header to fixed_buf.rrs Signed-off-by: adamperlin * Call abort_with_code_and_message directly in case of format failure in panic handler to avoid any possible recursive panic Signed-off-by: adamperlin * Update src/hyperlight_host/tests/integration_test.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Adam Perlin * Update src/tests/rust_guests/simpleguest/src/main.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Adam Perlin * Make FixedBuf take ownership of underlying byte slice Signed-off-by: adamperlin * Apply cargo fmt Signed-off-by: adamperlin * Remove unused import Signed-off-by: adamperlin * 1. Add vec allocation after alloc::alloc failure to ensure panic in integration test 2. Resolve clippy errors Signed-off-by: adamperlin * Use heapless crate instead of custom fixed string buffer for panic string formatting Signed-off-by: adamperlin * Downgrade heapless to 0.8.0 to fix cargo crash Signed-off-by: adamperlin * apply cargo fmt Signed-off-by: adamperlin * Remove whitespace in panic handler and rename test function in simpleguest Signed-off-by: adamperlin * Write null terminator as part of initial panic message format Signed-off-by: adamperlin * Stack allocate panic message buffer to avoid use of mutex on static Signed-off-by: adamperlin * Increase panic buffer size and add description to format error message Signed-off-by: adamperlin * Create an fmt::Write implementation that writes formatted string to port-based io directly to stream error messages to the host and avoid needing a fixed-size buffer in the panic handler. Signed-off-by: adamperlin * Remove heapless dependency Signed-off-by: adamperlin * fmt-apply Signed-off-by: adamperlin * Remove unnecessary unsafe in write_abort Signed-off-by: adamperlin * Update src/hyperlight_guest/src/exit.rs Co-authored-by: Dan Chiarlone Signed-off-by: James Sturtevant --------- Signed-off-by: adamperlin Signed-off-by: Adam Perlin Signed-off-by: James Sturtevant Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: James Sturtevant Co-authored-by: Dan Chiarlone --- flake.nix | 2 +- src/hyperlight_guest/src/exit.rs | 8 ++++ src/hyperlight_guest_bin/src/lib.rs | 38 ++++++++++++++++--- src/hyperlight_host/tests/integration_test.rs | 30 +++++++++++++++ src/tests/rust_guests/simpleguest/src/main.rs | 26 +++++++++++++ 5 files changed, 97 insertions(+), 7 deletions(-) diff --git a/flake.nix b/flake.nix index fb6de20dd..d700857ac 100644 --- a/flake.nix +++ b/flake.nix @@ -107,7 +107,7 @@ pname = "hyperlight"; version = "0.0.0"; src = lib.cleanSource ./.; - cargoHash = "sha256-mNKnsaSKVz4khzWO7VhmN0cR+Ed5ML7fD1PJJCeQQ6E="; + cargoHash = "sha256-hoeJEBdxaoyLlhQQ4X4Wk5X1QVtQ7RRQYaxkiGg8rWA="; nativeBuildInputs = [ azure-cli diff --git a/src/hyperlight_guest/src/exit.rs b/src/hyperlight_guest/src/exit.rs index 715086c7b..a64ae390a 100644 --- a/src/hyperlight_guest/src/exit.rs +++ b/src/hyperlight_guest/src/exit.rs @@ -67,6 +67,14 @@ pub unsafe fn abort_with_code_and_message(code: &[u8], message_ptr: *const c_cha } } +/// This function exists to give the guest more manual control +/// over the abort sequence. For example, in `hyperlight_guest_bin`'s panic handler, +/// we have a message of unknown length that we want to stream +/// to the host, which requires sending the message in chunks +pub fn write_abort(code: &[u8]) { + outb(OutBAction::Abort as u16, code); +} + /// OUT bytes to the host through multiple exits. #[hyperlight_guest_tracing::trace_function] pub(crate) fn outb(port: u16, data: &[u8]) { diff --git a/src/hyperlight_guest_bin/src/lib.rs b/src/hyperlight_guest_bin/src/lib.rs index 27918ad3f..8686aab5e 100644 --- a/src/hyperlight_guest_bin/src/lib.rs +++ b/src/hyperlight_guest_bin/src/lib.rs @@ -18,7 +18,7 @@ limitations under the License. // === Dependencies === extern crate alloc; -use alloc::string::ToString; +use core::fmt::Write; use buddy_system_allocator::LockedHeap; #[cfg(target_arch = "x86_64")] @@ -30,7 +30,7 @@ use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_common::mem::HyperlightPEB; #[cfg(feature = "mem_profile")] use hyperlight_common::outb::OutBAction; -use hyperlight_guest::exit::{abort_with_code_and_message, halt}; +use hyperlight_guest::exit::{halt, write_abort}; use hyperlight_guest::guest_handle::handle::GuestHandle; use hyperlight_guest_tracing::{trace, trace_function}; use log::LevelFilter; @@ -139,11 +139,37 @@ pub static mut OS_PAGE_SIZE: u32 = 0; // to satisfy the clippy when cfg == test #[allow(dead_code)] fn panic(info: &core::panic::PanicInfo) -> ! { - let msg = info.to_string(); - let c_string = alloc::ffi::CString::new(msg) - .unwrap_or_else(|_| alloc::ffi::CString::new("panic (invalid utf8)").unwrap()); + _panic_handler(info) +} + +/// A writer that sends all output to the hyperlight host +/// using output ports. This allows us to not impose a +/// buffering limit on error message size on the guest end, +/// though one exists for the host. +struct HyperlightAbortWriter; +impl core::fmt::Write for HyperlightAbortWriter { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + write_abort(s.as_bytes()); + Ok(()) + } +} + +#[inline(always)] +fn _panic_handler(info: &core::panic::PanicInfo) -> ! { + let mut w = HyperlightAbortWriter; + + // begin abort sequence by writing the error code + write_abort(&[ErrorCode::UnknownError as u8]); + + let write_res = write!(w, "{}", info); + if write_res.is_err() { + write_abort("panic: message format failed".as_bytes()); + } - unsafe { abort_with_code_and_message(&[ErrorCode::UnknownError as u8], c_string.as_ptr()) } + // write abort terminator to finish the abort + // and signal to the host that the message can now be read + write_abort(&[0xFF]); + unreachable!(); } // === Entrypoint === diff --git a/src/hyperlight_host/tests/integration_test.rs b/src/hyperlight_host/tests/integration_test.rs index 7d98532d3..8b2077a19 100644 --- a/src/hyperlight_host/tests/integration_test.rs +++ b/src/hyperlight_host/tests/integration_test.rs @@ -531,6 +531,36 @@ fn guest_malloc_abort() { )); } +#[test] +fn guest_panic_no_alloc() { + let heap_size = 0x4000; + + let mut cfg = SandboxConfiguration::default(); + cfg.set_heap_size(heap_size); + let uninit = UninitializedSandbox::new( + GuestBinary::FilePath(simple_guest_as_string().unwrap()), + Some(cfg), + ) + .unwrap(); + let mut sbox: MultiUseSandbox = uninit.evolve().unwrap(); + + let res = sbox + .call::( + "ExhaustHeap", // uses the rust allocator to allocate small blocks on the heap until OOM + (), + ) + .unwrap_err(); + + if let HyperlightError::StackOverflow() = res { + panic!("panic on OOM caused stack overflow, this implies allocation in panic handler"); + } + + assert!(matches!( + res, + HyperlightError::GuestAborted(code, msg) if code == ErrorCode::UnknownError as u8 && msg.contains("memory allocation of ") && msg.contains("bytes failed") + )); +} + // Tests libc alloca #[test] fn dynamic_stack_allocate_c_guest() { diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index d4d81d57f..aabe74dc5 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -29,6 +29,7 @@ use alloc::boxed::Box; use alloc::string::ToString; use alloc::vec::Vec; use alloc::{format, vec}; +use core::alloc::Layout; use core::ffi::c_char; use core::hint::black_box; use core::ptr::write_volatile; @@ -508,6 +509,23 @@ fn call_malloc(function_call: &FunctionCall) -> Result> { } } +#[hyperlight_guest_tracing::trace_function] +unsafe fn exhaust_heap(_: &FunctionCall) -> ! { + let layout: Layout = Layout::new::(); + let mut ptr = alloc::alloc::alloc_zeroed(layout); + while !ptr.is_null() { + black_box(ptr); + ptr = alloc::alloc::alloc_zeroed(layout); + } + + // after alloc::alloc_zeroed failure (null return when called in loop above) + // allocate a Vec to ensure OOM panic + let vec = Vec::::with_capacity(1); + black_box(vec); + + panic!("function should have panicked before due to OOM") +} + #[hyperlight_guest_tracing::trace_function] fn malloc_and_free(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(size) = function_call.parameters.clone().unwrap()[0].clone() { @@ -1108,6 +1126,14 @@ pub extern "C" fn hyperlight_main() { ); register_function(call_malloc_def); + let exhaust_heap_def = GuestFunctionDefinition::new( + "ExhaustHeap".to_string(), + Vec::new(), + ReturnType::Int, + exhaust_heap as usize, + ); + register_function(exhaust_heap_def); + let malloc_and_free_def = GuestFunctionDefinition::new( "MallocAndFree".to_string(), Vec::from(&[ParameterType::Int]), From 3c826956df9ee94fa0f09ebbf5ab0647d27b86b4 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Wed, 10 Sep 2025 12:55:52 +0100 Subject: [PATCH 163/271] Update common workflow (#880) Signed-off-by: Simon Davies --- .github/workflows/Benchmarks.yml | 2 +- .github/workflows/CargoPublish.yml | 2 +- .github/workflows/CreateRelease.yml | 6 +++--- .github/workflows/copilot-setup-steps.yml | 2 +- .github/workflows/dep_build_guest_binaries.yml | 2 +- .github/workflows/dep_fuzzing.yml | 2 +- .github/workflows/dep_rust.yml | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/Benchmarks.yml b/.github/workflows/Benchmarks.yml index 8bbd983a0..d5ad18939 100644 --- a/.github/workflows/Benchmarks.yml +++ b/.github/workflows/Benchmarks.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@v5 - - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: rust-toolchain: "1.86" env: diff --git a/.github/workflows/CargoPublish.yml b/.github/workflows/CargoPublish.yml index a9e77f08e..0c4ad8304 100644 --- a/.github/workflows/CargoPublish.yml +++ b/.github/workflows/CargoPublish.yml @@ -32,7 +32,7 @@ jobs: fetch-depth: 0 fetch-tags: true - - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: rust-toolchain: "1.86" diff --git a/.github/workflows/CreateRelease.yml b/.github/workflows/CreateRelease.yml index 2adc5069d..07e8e6da2 100644 --- a/.github/workflows/CreateRelease.yml +++ b/.github/workflows/CreateRelease.yml @@ -31,7 +31,7 @@ jobs: steps: - uses: actions/checkout@v5 - - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: rust-toolchain: "1.86" env: @@ -52,7 +52,7 @@ jobs: steps: - uses: actions/checkout@v5 - - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: rust-toolchain: "1.86" env: @@ -112,7 +112,7 @@ jobs: fetch-depth: 0 fetch-tags: true - - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: rust-toolchain: "1.86" env: diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 6abf73e74..e50e7792c 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -26,7 +26,7 @@ jobs: with: components: rustfmt - - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: rust-toolchain: "1.86" env: diff --git a/.github/workflows/dep_build_guest_binaries.yml b/.github/workflows/dep_build_guest_binaries.yml index 2088d0ae5..9656f5702 100644 --- a/.github/workflows/dep_build_guest_binaries.yml +++ b/.github/workflows/dep_build_guest_binaries.yml @@ -31,7 +31,7 @@ jobs: steps: - uses: actions/checkout@v5 - - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: rust-toolchain: "1.86" env: diff --git a/.github/workflows/dep_fuzzing.yml b/.github/workflows/dep_fuzzing.yml index 95008efd4..4386cc58a 100644 --- a/.github/workflows/dep_fuzzing.yml +++ b/.github/workflows/dep_fuzzing.yml @@ -32,7 +32,7 @@ jobs: - name: Checkout code uses: actions/checkout@v5 - - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: rust-toolchain: "1.86" env: diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index b93042c50..25777ca43 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -46,7 +46,7 @@ jobs: steps: - uses: actions/checkout@v5 - - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: rust-toolchain: "1.86" env: @@ -98,7 +98,7 @@ jobs: with: components: rustfmt - - uses: hyperlight-dev/ci-setup-workflow@v1.6.0 + - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: rust-toolchain: "1.86" env: From 08d8d8c5dfa53ca3d1a25e2ff700b7e669f96757 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Wed, 10 Sep 2025 12:08:25 -0700 Subject: [PATCH 164/271] Add benchmark for measuring performance impact on moving sandbox across thread (#882) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- src/hyperlight_host/benches/benchmarks.rs | 43 +++++++++++++++++++++++ src/tests/rust_guests/witguest/Cargo.lock | 4 +-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/hyperlight_host/benches/benchmarks.rs b/src/hyperlight_host/benches/benchmarks.rs index 3ed91820f..61d405370 100644 --- a/src/hyperlight_host/benches/benchmarks.rs +++ b/src/hyperlight_host/benches/benchmarks.rs @@ -14,6 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ +use std::sync::Mutex; + use criterion::{Criterion, criterion_group, criterion_main}; use flatbuffers::FlatBufferBuilder; use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType}; @@ -74,6 +76,47 @@ fn guest_call_benchmark(c: &mut Criterion) { }); }); + // same as guest_call, but the call will be made on different thread + group.bench_function("guest_call_on_different_thread", |b| { + use std::sync::{Arc, Barrier}; + use std::thread; + use std::time::Instant; + + b.iter_custom(|iters| { + let mut total_duration = std::time::Duration::ZERO; + let sbox = Arc::new(Mutex::new(create_multiuse_sandbox())); + + for _ in 0..iters { + // Ensure vcpu is "bound" on this main thread + { + let mut sbox = sbox.lock().unwrap(); + sbox.call::("Echo", "warmup\n".to_string()).unwrap(); + } + + let barrier = Arc::new(Barrier::new(2)); + let barrier_clone = Arc::clone(&barrier); + let sbox_clone = Arc::clone(&sbox); + + let handle = thread::spawn(move || { + barrier_clone.wait(); + + let mut sbox = sbox_clone.lock().unwrap(); + let start = Instant::now(); + // Measure the first call after thread switch + // According to KVM docs, this should show performance impact + sbox.call::("Echo", "hello\n".to_string()).unwrap(); + start.elapsed() + }); + + barrier.wait(); + + total_duration += handle.join().unwrap(); + } + + total_duration + }); + }); + group.finish(); } diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index 762a25e97..6a33cb503 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -521,9 +521,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "wasmparser" -version = "0.238.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fa99c8328024423875ae4a55345cfde8f0371327fb2d0f33b0f52a06fc44408" +checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" dependencies = [ "bitflags", "hashbrown", From b419bde3cec2bb2db1b0258891f52f620e1d3ca5 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Wed, 10 Sep 2025 13:32:13 -0700 Subject: [PATCH 165/271] Remove old code used for removed in-process feature (#879) * Remove old code Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Remove unused snapshot method + fix tests Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Clippy Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * fixup! Remove old code Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --------- Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- src/hyperlight_host/src/mem/layout.rs | 37 +------- src/hyperlight_host/src/mem/mgr.rs | 15 --- src/hyperlight_host/src/mem/shared_mem.rs | 51 +---------- .../src/mem/shared_mem_snapshot.rs | 91 +++++++++++-------- .../src/sandbox/initialized_multi_use.rs | 1 - 5 files changed, 54 insertions(+), 141 deletions(-) diff --git a/src/hyperlight_host/src/mem/layout.rs b/src/hyperlight_host/src/mem/layout.rs index de357b7ca..e08e256af 100644 --- a/src/hyperlight_host/src/mem/layout.rs +++ b/src/hyperlight_host/src/mem/layout.rs @@ -385,24 +385,6 @@ impl SandboxMemoryLayout { self.stack_size } - /// Get the offset in guest memory to the OutB pointer. - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - #[allow(dead_code)] - pub(super) fn get_outb_pointer_offset(&self) -> usize { - // The outb pointer is immediately after the code pointer - // in the `CodeAndOutBPointers` struct which is a u64 - self.peb_code_pointer_offset + size_of::() - } - - /// Get the offset in guest memory to the OutB context. - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - #[allow(dead_code)] - pub(super) fn get_outb_context_offset(&self) -> usize { - // The outb context is immediately after the outb pointer - // in the `CodeAndOutBPointers` struct which is a u64 - self.get_outb_pointer_offset() + size_of::() - } - /// Get the offset in guest memory to the output data pointer. #[instrument(skip_all, parent = Span::current(), level= "Trace")] fn get_output_data_pointer_offset(&self) -> usize { @@ -420,11 +402,8 @@ impl SandboxMemoryLayout { } /// Get the offset in guest memory to the start of output data. - /// - /// This function exists to accommodate the macro that generates C API - /// compatible functions. #[instrument(skip_all, parent = Span::current(), level= "Trace")] - #[allow(dead_code)] + #[cfg(test)] pub(crate) fn get_output_data_offset(&self) -> usize { self.output_data_buffer_offset } @@ -459,13 +438,6 @@ impl SandboxMemoryLayout { self.peb_guest_dispatch_function_ptr_offset } - /// Get the offset in guest memory to the PEB address - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - #[allow(dead_code)] - pub(super) fn get_in_process_peb_offset(&self) -> usize { - self.peb_offset - } - /// Get the offset in guest memory to the heap size #[instrument(skip_all, parent = Span::current(), level= "Trace")] fn get_heap_size_offset(&self) -> usize { @@ -494,13 +466,6 @@ impl SandboxMemoryLayout { self.get_min_guest_stack_address_offset() + size_of::() } - /// Get the offset to the guest guard page - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - #[allow(dead_code)] - pub fn get_guard_page_offset(&self) -> usize { - self.guard_page_offset - } - /// Get the total size of guest memory in `self`'s memory /// layout. #[instrument(skip_all, parent = Span::current(), level= "Trace")] diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index e33c4b08d..787f095e2 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -281,21 +281,6 @@ where snapshot.restore_from_snapshot(&mut self.shared_mem)?; Ok(()) } - - /// Sets `addr` to the correct offset in the memory referenced by - /// `shared_mem` to indicate the address of the outb pointer and context - /// for calling outb function - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - #[allow(dead_code)] - pub(crate) fn set_outb_address_and_context(&mut self, addr: u64, context: u64) -> Result<()> { - let pointer_offset = self.layout.get_outb_pointer_offset(); - let context_offset = self.layout.get_outb_context_offset(); - self.shared_mem.with_exclusivity(|excl| -> Result<()> { - excl.write_u64(pointer_offset, addr)?; - excl.write_u64(context_offset, context)?; - Ok(()) - })? - } } impl SandboxMemoryManager { diff --git a/src/hyperlight_host/src/mem/shared_mem.rs b/src/hyperlight_host/src/mem/shared_mem.rs index bd39a73fd..84cbb4c8e 100644 --- a/src/hyperlight_host/src/mem/shared_mem.rs +++ b/src/hyperlight_host/src/mem/shared_mem.rs @@ -30,7 +30,7 @@ use windows::Win32::System::Memory::PAGE_READWRITE; #[cfg(target_os = "windows")] use windows::Win32::System::Memory::{ CreateFileMappingA, FILE_MAP_ALL_ACCESS, MEMORY_MAPPED_VIEW_ADDRESS, MapViewOfFile, - PAGE_EXECUTE_READWRITE, PAGE_NOACCESS, PAGE_PROTECTION_FLAGS, UnmapViewOfFile, VirtualProtect, + PAGE_NOACCESS, PAGE_PROTECTION_FLAGS, UnmapViewOfFile, VirtualProtect, }; #[cfg(target_os = "windows")] use windows::core::PCSTR; @@ -502,46 +502,6 @@ impl ExclusiveSharedMemory { }) } - #[allow(dead_code)] - pub(super) fn make_memory_executable(&self) -> Result<()> { - #[cfg(target_os = "windows")] - { - let mut _old_flags = PAGE_PROTECTION_FLAGS::default(); - if let Err(e) = unsafe { - VirtualProtect( - self.region.ptr as *const c_void, - self.region.size, - PAGE_EXECUTE_READWRITE, - &mut _old_flags as *mut PAGE_PROTECTION_FLAGS, - ) - } { - log_then_return!(WindowsAPIError(e.clone())); - } - } - - // make the memory executable on Linux - #[cfg(target_os = "linux")] - { - use libc::{PROT_EXEC, PROT_READ, PROT_WRITE, mprotect}; - - let res = unsafe { - mprotect( - self.region.ptr as *mut c_void, - self.region.size, - PROT_READ | PROT_WRITE | PROT_EXEC, - ) - }; - - if res != 0 { - return Err(new_error!( - "Failed to make memory executable: {:#?}", - Error::last_os_error().raw_os_error() - )); - } - } - Ok(()) - } - /// Internal helper method to get the backing memory as a mutable slice. /// /// # Safety @@ -614,15 +574,6 @@ impl ExclusiveSharedMemory { Ok(()) } - /// Return the address of memory at an offset to this `SharedMemory` checking - /// that the memory is within the bounds of the `SharedMemory`. - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - #[allow(dead_code)] - pub(crate) fn calculate_address(&self, offset: usize) -> Result { - bounds_check!(offset, 0, self.mem_size()); - Ok(self.base_addr() + offset) - } - generate_reader!(read_u8, u8); generate_reader!(read_i8, i8); generate_reader!(read_u16, u16); diff --git a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs index 49af2d99d..dd44422df 100644 --- a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs +++ b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs @@ -50,15 +50,6 @@ impl SharedMemorySnapshot { }) } - /// Take another snapshot of the internally-stored `SharedMemory`, - /// then store it internally. - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - #[allow(dead_code)] - pub(super) fn replace_snapshot(&mut self, shared_mem: &mut S) -> Result<()> { - self.snapshot = shared_mem.with_exclusivity(|e| e.copy_all_to_vec())??; - Ok(()) - } - /// Copy the memory from the internally-stored memory snapshot /// into the internally-stored `SharedMemory`. #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] @@ -91,36 +82,58 @@ mod tests { use crate::mem::shared_mem::ExclusiveSharedMemory; #[test] - fn restore_replace() { - let mut data1 = vec![b'a', b'b', b'c']; - data1.resize_with(PAGE_SIZE_USIZE, || 0); - let data2 = data1.iter().map(|b| b + 1).collect::>(); + fn restore() { + // Simplified version of the original test + let data1 = vec![b'a'; PAGE_SIZE_USIZE]; + let data2 = vec![b'b'; PAGE_SIZE_USIZE]; + let mut gm = ExclusiveSharedMemory::new(PAGE_SIZE_USIZE).unwrap(); - gm.copy_from_slice(data1.as_slice(), 0).unwrap(); - let mut snap = super::SharedMemorySnapshot::new(&mut gm, 0, Vec::new()).unwrap(); - { - // after the first snapshot is taken, make sure gm has the equivalent - // of data1 - assert_eq!(data1, gm.copy_all_to_vec().unwrap()); - } - - { - // modify gm with data2 rather than data1 and restore from - // snapshot. we should have the equivalent of data1 again - gm.copy_from_slice(data2.as_slice(), 0).unwrap(); - assert_eq!(data2, gm.copy_all_to_vec().unwrap()); - snap.restore_from_snapshot(&mut gm).unwrap(); - assert_eq!(data1, gm.copy_all_to_vec().unwrap()); - } - { - // modify gm with data2, then retake the snapshot and restore - // from the new snapshot. we should have the equivalent of data2 - gm.copy_from_slice(data2.as_slice(), 0).unwrap(); - assert_eq!(data2, gm.copy_all_to_vec().unwrap()); - snap.replace_snapshot(&mut gm).unwrap(); - assert_eq!(data2, gm.copy_all_to_vec().unwrap()); - snap.restore_from_snapshot(&mut gm).unwrap(); - assert_eq!(data2, gm.copy_all_to_vec().unwrap()); - } + gm.copy_from_slice(&data1, 0).unwrap(); + + // Take snapshot of data1 + let snapshot = super::SharedMemorySnapshot::new(&mut gm, 0, Vec::new()).unwrap(); + + // Modify memory to data2 + gm.copy_from_slice(&data2, 0).unwrap(); + assert_eq!(gm.as_slice(), &data2[..]); + + // Restore should bring back data1 + snapshot.restore_from_snapshot(&mut gm).unwrap(); + assert_eq!(gm.as_slice(), &data1[..]); + } + + #[test] + fn snapshot_mem_size() { + let size = PAGE_SIZE_USIZE * 2; + let mut gm = ExclusiveSharedMemory::new(size).unwrap(); + + let snapshot = super::SharedMemorySnapshot::new(&mut gm, 0, Vec::new()).unwrap(); + assert_eq!(snapshot.mem_size(), size); + } + + #[test] + fn multiple_snapshots_independent() { + let mut gm = ExclusiveSharedMemory::new(PAGE_SIZE_USIZE).unwrap(); + + // Create first snapshot with pattern A + let pattern_a = vec![0xAA; PAGE_SIZE_USIZE]; + gm.copy_from_slice(&pattern_a, 0).unwrap(); + let snapshot_a = super::SharedMemorySnapshot::new(&mut gm, 1, Vec::new()).unwrap(); + + // Create second snapshot with pattern B + let pattern_b = vec![0xBB; PAGE_SIZE_USIZE]; + gm.copy_from_slice(&pattern_b, 0).unwrap(); + let snapshot_b = super::SharedMemorySnapshot::new(&mut gm, 2, Vec::new()).unwrap(); + + // Clear memory + gm.copy_from_slice(&[0; PAGE_SIZE_USIZE], 0).unwrap(); + + // Restore snapshot A + snapshot_a.restore_from_snapshot(&mut gm).unwrap(); + assert_eq!(gm.as_slice(), &pattern_a[..]); + + // Restore snapshot B + snapshot_b.restore_from_snapshot(&mut gm).unwrap(); + assert_eq!(gm.as_slice(), &pattern_b[..]); } } diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index dfdcc9668..b1b41fff2 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -333,7 +333,6 @@ impl MultiUseSandbox { /// Map the contents of a file into the guest at a particular address /// /// Returns the length of the mapping in bytes. - #[allow(dead_code)] #[instrument(err(Debug), skip(self, _fp, _guest_base), parent = Span::current())] pub fn map_file_cow(&mut self, _fp: &Path, _guest_base: u64) -> Result { #[cfg(windows)] From 0336f18073c1943d60623f1043d967900c4a961a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 04:05:36 +0000 Subject: [PATCH 166/271] Bump addr2line from 0.25.0 to 0.25.1 (#887) Bumps [addr2line](https://github.com/gimli-rs/addr2line) from 0.25.0 to 0.25.1. - [Changelog](https://github.com/gimli-rs/addr2line/blob/master/CHANGELOG.md) - [Commits](https://github.com/gimli-rs/addr2line/compare/0.25.0...0.25.1) --- updated-dependencies: - dependency-name: addr2line dependency-version: 0.25.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- src/trace_dump/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7b95df4d7..d8fe77cb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.25.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9acbfca36652500c911ddb767ed433e3ed99b032b5d935be73c6923662db1d43" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "cpp_demangle", "fallible-iterator", @@ -3518,7 +3518,7 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" name = "trace_dump" version = "0.9.0" dependencies = [ - "addr2line 0.25.0", + "addr2line 0.25.1", "blake3", "piet-common", ] diff --git a/src/trace_dump/Cargo.toml b/src/trace_dump/Cargo.toml index 52014a8f3..f98c2c251 100644 --- a/src/trace_dump/Cargo.toml +++ b/src/trace_dump/Cargo.toml @@ -5,7 +5,7 @@ publish = false edition = "2021" [dependencies] -addr2line = "0.25.0" +addr2line = "0.25.1" piet-common = { version = "0.8.0", features = [ "png" ] } blake3 = { version = "1.5.5" } From 730ee20cd7ea1f83dc294b3189dd9b4231eeb4d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 04:05:42 +0000 Subject: [PATCH 167/271] Bump cc from 1.2.36 to 1.2.37 (#886) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.36 to 1.2.37. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.36...cc-v1.2.37) --- updated-dependencies: - dependency-name: cc dependency-version: 1.2.37 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d8fe77cb5..11cb51362 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,9 +362,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.36" +version = "1.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" +checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44" dependencies = [ "find-msvc-tools", "jobserver", From ae74c26b3346640bdca69023908070aae7feb600 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 04:44:29 +0000 Subject: [PATCH 168/271] Bump serde from 1.0.219 to 1.0.223 (#888) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.219 to 1.0.223. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.219...v1.0.223) --- updated-dependencies: - dependency-name: serde dependency-version: 1.0.223 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 11cb51362..5a337c5e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3052,18 +3052,28 @@ checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.223" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "a505d71960adde88e293da5cb5eda57093379f64e61cf77bf0e6a63af07a7bac" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.223" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20f57cbd357666aa7b3ac84a90b4ea328f1d4ddb6772b430caa5d9e1309bb9e9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.223" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "3d428d07faf17e306e699ec1e91996e5a165ba5d6bce5b5155173e91a8a01a56" dependencies = [ "proc-macro2", "quote", From a70a2a3a6ecdc4a4dfe00cfbbc7891ae95767d18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 08:37:46 +0000 Subject: [PATCH 169/271] Bump serde_json from 1.0.143 to 1.0.145 (#889) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.143 to 1.0.145. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.143...v1.0.145) --- updated-dependencies: - dependency-name: serde_json dependency-version: 1.0.145 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5a337c5e1..7c628c8e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3082,14 +3082,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] From 44808b977acb82a88a507962a8d4d3ea1036a5d4 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Mon, 15 Sep 2025 17:40:06 +0100 Subject: [PATCH 170/271] Update mshv crates for Azure Linux to v0.6.1 (#891) Signed-off-by: Simon Davies --- Cargo.lock | 14 +++++++------- src/hyperlight_host/Cargo.toml | 4 ++-- src/hyperlight_host/src/hypervisor/hyperv_linux.rs | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c628c8e1..ea5317085 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1455,9 +1455,9 @@ dependencies = [ "metrics-exporter-prometheus", "metrics-util", "mshv-bindings 0.2.1", - "mshv-bindings 0.3.2", + "mshv-bindings 0.6.1", "mshv-ioctls 0.2.1", - "mshv-ioctls 0.3.2", + "mshv-ioctls 0.6.1", "opentelemetry", "opentelemetry-otlp", "opentelemetry-semantic-conventions", @@ -2053,9 +2053,9 @@ dependencies = [ [[package]] name = "mshv-bindings" -version = "0.3.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0cb5031f3243a7459b7c13d960d25420980874eebda816db24ce6077e21d43" +checksum = "fef6d8b8215ff502f0f662d1fc5229d6c79628208a0d03277ce52fbbe7fe1872" dependencies = [ "libc", "num_enum", @@ -2077,12 +2077,12 @@ dependencies = [ [[package]] name = "mshv-ioctls" -version = "0.3.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89abe853221fa6f14ad4066affb9abda241a03d65622887d5794e1422d0bd75a" +checksum = "fdbb879d6a9ca5359ae020c17ebf8587e0be309bf32beae636030e4408c2e481" dependencies = [ "libc", - "mshv-bindings 0.3.2", + "mshv-bindings 0.6.1", "thiserror 2.0.16", "vmm-sys-util", ] diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index ea934c696..a28e09cd2 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -78,8 +78,8 @@ kvm-bindings = { version = "0.14", features = ["fam-wrappers"], optional = true kvm-ioctls = { version = "0.24", optional = true } mshv-bindings2 = { package="mshv-bindings", version = "=0.2.1", optional = true } mshv-ioctls2 = { package="mshv-ioctls", version = "=0.2.1", optional = true} -mshv-bindings3 = { package="mshv-bindings", version = "=0.3.2", optional = true } -mshv-ioctls3 = { package="mshv-ioctls", version = "=0.3.2", optional = true} +mshv-bindings3 = { package="mshv-bindings", version = "0.6.1", optional = true } +mshv-ioctls3 = { package="mshv-ioctls", version = "0.6.1", optional = true} [dev-dependencies] uuid = { version = "1.18.1", features = ["v4"] } diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 1907d8e0b..b0ab43e26 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -363,7 +363,7 @@ impl HypervLinuxDriver { let vm_fd = mshv.create_vm_with_args(&pr)?; let features: hv_partition_synthetic_processor_features = Default::default(); - vm_fd.hvcall_set_partition_property( + vm_fd.set_partition_property( hv_partition_property_code_HV_PARTITION_PROPERTY_SYNTHETIC_PROC_FEATURES, unsafe { features.as_uint64[0] }, )?; From 81ad3047a1893456db55432b22d7b1612bceacef Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Mon, 15 Sep 2025 09:43:26 -0700 Subject: [PATCH 171/271] Remove MemMgrWrapper abstraction because it's useless overhead with no benefit. Also remove WrapperGetter (#884) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- src/hyperlight_host/src/func/guest_err.rs | 8 +- .../src/func/host_functions.rs | 6 +- src/hyperlight_host/src/hypervisor/gdb/mod.rs | 12 +- .../src/hypervisor/hyperv_linux.rs | 19 ++- .../src/hypervisor/hyperv_windows.rs | 19 ++- src/hyperlight_host/src/hypervisor/kvm.rs | 19 ++- src/hyperlight_host/src/hypervisor/mod.rs | 12 +- src/hyperlight_host/src/lib.rs | 2 - src/hyperlight_host/src/mem/mgr.rs | 69 ++++++++-- .../src/sandbox/initialized_multi_use.rs | 44 ++----- src/hyperlight_host/src/sandbox/mem_mgr.rs | 123 ------------------ src/hyperlight_host/src/sandbox/mod.rs | 10 -- src/hyperlight_host/src/sandbox/outb.rs | 20 ++- .../src/sandbox/uninitialized.rs | 28 ++-- .../src/sandbox/uninitialized_evolve.rs | 6 +- 15 files changed, 135 insertions(+), 262 deletions(-) delete mode 100644 src/hyperlight_host/src/sandbox/mem_mgr.rs diff --git a/src/hyperlight_host/src/func/guest_err.rs b/src/hyperlight_host/src/func/guest_err.rs index af3a0bbe3..27db6d231 100644 --- a/src/hyperlight_host/src/func/guest_err.rs +++ b/src/hyperlight_host/src/func/guest_err.rs @@ -17,15 +17,17 @@ limitations under the License. use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use crate::error::HyperlightError::{GuestError, StackOverflow}; +use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; use crate::metrics::{METRIC_GUEST_ERROR, METRIC_GUEST_ERROR_LABEL_CODE}; -use crate::sandbox::mem_mgr::MemMgrWrapper; use crate::{Result, log_then_return}; /// Check for a guest error and return an `Err` if one was found, /// and `Ok` if one was not found. -pub(crate) fn check_for_guest_error(mgr: &mut MemMgrWrapper) -> Result<()> { - let guest_err = mgr.as_mut().get_guest_error().ok(); +pub(crate) fn check_for_guest_error( + mgr: &mut SandboxMemoryManager, +) -> Result<()> { + let guest_err = mgr.get_guest_error().ok(); let Some(guest_err) = guest_err else { return Ok(()); }; diff --git a/src/hyperlight_host/src/func/host_functions.rs b/src/hyperlight_host/src/func/host_functions.rs index 3944b0703..871d04c97 100644 --- a/src/hyperlight_host/src/func/host_functions.rs +++ b/src/hyperlight_host/src/func/host_functions.rs @@ -61,7 +61,7 @@ impl Registerable for UninitializedSandbox { return_type: Output::TYPE, }; - (*hfs).register_host_function(name.to_string(), entry, self.mgr.unwrap_mgr_mut()) + (*hfs).register_host_function(name.to_string(), entry, &mut self.mgr) } #[cfg(all(feature = "seccomp", target_os = "linux"))] fn register_host_function_with_syscalls( @@ -82,7 +82,7 @@ impl Registerable for UninitializedSandbox { return_type: Output::TYPE, }; - (*hfs).register_host_function(name.to_string(), entry, self.mgr.unwrap_mgr_mut()) + (*hfs).register_host_function(name.to_string(), entry, &mut self.mgr) } } @@ -210,7 +210,7 @@ pub(crate) fn register_host_function>>, + dbg_mem_access_fn: Arc>>, ) -> crate::Result<()> { let addr = self.translate_gva(vcpu_fd, addr)?; @@ -235,7 +235,7 @@ pub(super) trait GuestDebug { vcpu_fd: &Self::Vcpu, mut gva: u64, mut data: &mut [u8], - dbg_mem_access_fn: Arc>>, + dbg_mem_access_fn: Arc>>, ) -> crate::Result<()> { let data_len = data.len(); log::debug!("Read addr: {:X} len: {:X}", gva, data_len); @@ -259,7 +259,6 @@ pub(super) trait GuestDebug { dbg_mem_access_fn .try_lock() .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .unwrap_mgr_mut() .get_shared_mem_mut() .copy_to_slice(&mut data[..read_len], offset)?; @@ -285,7 +284,7 @@ pub(super) trait GuestDebug { &mut self, vcpu_fd: &Self::Vcpu, addr: u64, - dbg_mem_access_fn: Arc>>, + dbg_mem_access_fn: Arc>>, ) -> crate::Result<()> { let addr = self.translate_gva(vcpu_fd, addr)?; @@ -309,7 +308,7 @@ pub(super) trait GuestDebug { vcpu_fd: &Self::Vcpu, mut gva: u64, mut data: &[u8], - dbg_mem_access_fn: Arc>>, + dbg_mem_access_fn: Arc>>, ) -> crate::Result<()> { let data_len = data.len(); log::debug!("Write addr: {:X} len: {:X}", gva, data_len); @@ -333,7 +332,6 @@ pub(super) trait GuestDebug { dbg_mem_access_fn .try_lock() .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .unwrap_mgr_mut() .get_shared_mem_mut() .copy_from_slice(&data[..write_len], offset)?; diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index b0ab43e26..a5a32f456 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -75,13 +75,13 @@ use super::{HyperlightExit, Hypervisor, InterruptHandle, LinuxInterruptHandle, V use crate::HyperlightError; use crate::hypervisor::get_memory_access_violation; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; +use crate::mem::mgr::SandboxMemoryManager; use crate::mem::ptr::{GuestPtr, RawPtr}; use crate::mem::shared_mem::HostSharedMemory; use crate::sandbox::SandboxConfiguration; #[cfg(feature = "trace_guest")] use crate::sandbox::TraceInfo; use crate::sandbox::host_funcs::FunctionRegistry; -use crate::sandbox::mem_mgr::MemMgrWrapper; use crate::sandbox::outb::handle_outb; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; @@ -94,8 +94,8 @@ mod debug { use super::mshv_bindings::hv_x64_exception_intercept_message; use super::{HypervLinuxDriver, *}; use crate::hypervisor::gdb::{DebugMsg, DebugResponse, VcpuStopReason, X86_64Regs}; + use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; - use crate::sandbox::mem_mgr::MemMgrWrapper; use crate::{Result, new_error}; impl HypervLinuxDriver { @@ -126,7 +126,7 @@ mod debug { pub(crate) fn process_dbg_request( &mut self, req: DebugMsg, - dbg_mem_access_fn: Arc>>, + dbg_mem_access_fn: Arc>>, ) -> Result { if let Some(debug) = self.debug.as_mut() { match req { @@ -174,7 +174,6 @@ mod debug { .map_err(|e| { new_error!("Error locking at {}:{}: {}", file!(), line!(), e) })? - .unwrap_mgr() .layout .get_guest_code_address(); @@ -312,7 +311,7 @@ pub(crate) struct HypervLinuxDriver { orig_rsp: GuestPtr, entrypoint: u64, interrupt_handle: Arc, - mem_mgr: Option>, + mem_mgr: Option>, host_funcs: Option>>, sandbox_regions: Vec, // Initially mapped regions when sandbox is created @@ -584,10 +583,10 @@ impl Hypervisor for HypervLinuxDriver { peb_addr: RawPtr, seed: u64, page_size: u32, - mem_mgr: MemMgrWrapper, + mem_mgr: SandboxMemoryManager, host_funcs: Arc>, max_guest_log_level: Option, - #[cfg(gdb)] dbg_mem_access_fn: Arc>>, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()> { self.mem_mgr = Some(mem_mgr); self.host_funcs = Some(host_funcs); @@ -659,7 +658,7 @@ impl Hypervisor for HypervLinuxDriver { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - #[cfg(gdb)] dbg_mem_access_fn: Arc>>, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()> { // Reset general purpose registers, then set RIP and RSP let regs = StandardRegisters { @@ -705,7 +704,7 @@ impl Hypervisor for HypervLinuxDriver { #[cfg(feature = "trace_guest")] { // We need to handle the borrow checker issue where we need both: - // - &mut MemMgrWrapper (from self.mem_mgr.as_mut()) + // - &mut SandboxMemoryManager (from self.mem_mgr) // - &mut dyn Hypervisor (from self) // We'll use a temporary approach to extract the mem_mgr temporarily let mem_mgr_option = self.mem_mgr.take(); @@ -1021,7 +1020,7 @@ impl Hypervisor for HypervLinuxDriver { #[cfg(gdb)] fn handle_debug( &mut self, - dbg_mem_access_fn: Arc>>, + dbg_mem_access_fn: Arc>>, stop_reason: VcpuStopReason, ) -> Result<()> { if self.debug.is_none() { diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index f8b4727d1..0f98613b3 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -58,12 +58,12 @@ use crate::hypervisor::fpu::FP_CONTROL_WORD_DEFAULT; use crate::hypervisor::get_memory_access_violation; use crate::hypervisor::wrappers::WHvGeneralRegisters; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; +use crate::mem::mgr::SandboxMemoryManager; use crate::mem::ptr::{GuestPtr, RawPtr}; use crate::mem::shared_mem::HostSharedMemory; #[cfg(feature = "trace_guest")] use crate::sandbox::TraceInfo; use crate::sandbox::host_funcs::FunctionRegistry; -use crate::sandbox::mem_mgr::MemMgrWrapper; use crate::sandbox::outb::handle_outb; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; @@ -78,8 +78,8 @@ mod debug { use super::{HypervWindowsDriver, *}; use crate::Result; use crate::hypervisor::gdb::{DebugMsg, DebugResponse, VcpuStopReason, X86_64Regs}; + use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; - use crate::sandbox::mem_mgr::MemMgrWrapper; impl HypervWindowsDriver { /// Resets the debug information to disable debugging @@ -109,7 +109,7 @@ mod debug { pub(crate) fn process_dbg_request( &mut self, req: DebugMsg, - dbg_mem_access_fn: Arc>>, + dbg_mem_access_fn: Arc>>, ) -> Result { if let Some(debug) = self.debug.as_mut() { match req { @@ -157,7 +157,6 @@ mod debug { .map_err(|e| { new_error!("Error locking at {}:{}: {}", file!(), line!(), e) })? - .unwrap_mgr() .layout .get_guest_code_address(); @@ -279,7 +278,7 @@ pub(crate) struct HypervWindowsDriver { entrypoint: u64, orig_rsp: GuestPtr, interrupt_handle: Arc, - mem_mgr: Option>, + mem_mgr: Option>, host_funcs: Option>>, sandbox_regions: Vec, // Initially mapped regions when sandbox is created @@ -599,10 +598,10 @@ impl Hypervisor for HypervWindowsDriver { peb_address: RawPtr, seed: u64, page_size: u32, - mem_mgr: MemMgrWrapper, + mem_mgr: SandboxMemoryManager, host_funcs: Arc>, max_guest_log_level: Option, - #[cfg(gdb)] dbg_mem_access_hdl: Arc>>, + #[cfg(gdb)] dbg_mem_access_hdl: Arc>>, ) -> Result<()> { self.mem_mgr = Some(mem_mgr); self.host_funcs = Some(host_funcs); @@ -652,7 +651,7 @@ impl Hypervisor for HypervWindowsDriver { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - #[cfg(gdb)] dbg_mem_access_hdl: Arc>>, + #[cfg(gdb)] dbg_mem_access_hdl: Arc>>, ) -> Result<()> { // Reset general purpose registers, then set RIP and RSP let regs = WHvGeneralRegisters { @@ -696,7 +695,7 @@ impl Hypervisor for HypervWindowsDriver { #[cfg(feature = "trace_guest")] { // We need to handle the borrow checker issue where we need both: - // - &mut MemMgrWrapper (from self.mem_mgr.as_mut()) + // - &mut SandboxMemoryManager (from self.mem_mgr.as_mut()) // - &mut dyn Hypervisor (from self) // We'll use a temporary approach to extract the mem_mgr temporarily let mem_mgr_option = self.mem_mgr.take(); @@ -955,7 +954,7 @@ impl Hypervisor for HypervWindowsDriver { #[cfg(gdb)] fn handle_debug( &mut self, - dbg_mem_access_fn: Arc>>, + dbg_mem_access_fn: Arc>>, stop_reason: super::gdb::VcpuStopReason, ) -> Result<()> { if self.debug.is_none() { diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index be76129fb..d048e20f3 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -42,13 +42,13 @@ use super::{HyperlightExit, Hypervisor, InterruptHandle, LinuxInterruptHandle, V use crate::HyperlightError; use crate::hypervisor::get_memory_access_violation; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; +use crate::mem::mgr::SandboxMemoryManager; use crate::mem::ptr::{GuestPtr, RawPtr}; use crate::mem::shared_mem::HostSharedMemory; use crate::sandbox::SandboxConfiguration; #[cfg(feature = "trace_guest")] use crate::sandbox::TraceInfo; use crate::sandbox::host_funcs::FunctionRegistry; -use crate::sandbox::mem_mgr::MemMgrWrapper; use crate::sandbox::outb::handle_outb; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; @@ -86,8 +86,8 @@ mod debug { use crate::hypervisor::gdb::{ DebugMsg, DebugResponse, GuestDebug, KvmDebug, VcpuStopReason, X86_64Regs, }; + use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; - use crate::sandbox::mem_mgr::MemMgrWrapper; use crate::{Result, new_error}; impl KVMDriver { @@ -118,7 +118,7 @@ mod debug { pub(crate) fn process_dbg_request( &mut self, req: DebugMsg, - dbg_mem_access_fn: Arc>>, + dbg_mem_access_fn: Arc>>, ) -> Result { if let Some(debug) = self.debug.as_mut() { match req { @@ -166,7 +166,6 @@ mod debug { .map_err(|e| { new_error!("Error locking at {}:{}: {}", file!(), line!(), e) })? - .unwrap_mgr() .layout .get_guest_code_address(); @@ -292,7 +291,7 @@ pub(crate) struct KVMDriver { entrypoint: u64, orig_rsp: GuestPtr, interrupt_handle: Arc, - mem_mgr: Option>, + mem_mgr: Option>, host_funcs: Option>>, sandbox_regions: Vec, // Initially mapped regions when sandbox is created @@ -472,10 +471,10 @@ impl Hypervisor for KVMDriver { peb_addr: RawPtr, seed: u64, page_size: u32, - mem_mgr: MemMgrWrapper, + mem_mgr: SandboxMemoryManager, host_funcs: Arc>, max_guest_log_level: Option, - #[cfg(gdb)] dbg_mem_access_fn: Arc>>, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()> { self.mem_mgr = Some(mem_mgr); self.host_funcs = Some(host_funcs); @@ -570,7 +569,7 @@ impl Hypervisor for KVMDriver { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - #[cfg(gdb)] dbg_mem_access_fn: Arc>>, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()> { // Reset general purpose registers, then set RIP and RSP let regs = kvm_regs { @@ -623,7 +622,7 @@ impl Hypervisor for KVMDriver { #[cfg(feature = "trace_guest")] { // We need to handle the borrow checker issue where we need both: - // - &mut MemMgrWrapper (from self.mem_mgr.as_mut()) + // - &mut SandboxMemoryManager (from self.mem_mgr.as_mut()) // - &mut dyn Hypervisor (from self) // We'll use a temporary approach to extract the mem_mgr temporarily let mem_mgr_option = self.mem_mgr.take(); @@ -898,7 +897,7 @@ impl Hypervisor for KVMDriver { #[cfg(gdb)] fn handle_debug( &mut self, - dbg_mem_access_fn: Arc>>, + dbg_mem_access_fn: Arc>>, stop_reason: VcpuStopReason, ) -> Result<()> { if self.debug.is_none() { diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index 4e55e7ac5..928d9ac2e 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -70,10 +70,10 @@ use std::time::Duration; #[cfg(gdb)] use gdb::VcpuStopReason; +use crate::mem::mgr::SandboxMemoryManager; use crate::mem::ptr::RawPtr; use crate::mem::shared_mem::HostSharedMemory; use crate::sandbox::host_funcs::FunctionRegistry; -use crate::sandbox::mem_mgr::MemMgrWrapper; cfg_if::cfg_if! { if #[cfg(feature = "init-paging")] { @@ -141,10 +141,10 @@ pub(crate) trait Hypervisor: Debug + Send { peb_addr: RawPtr, seed: u64, page_size: u32, - mem_mgr: MemMgrWrapper, + mem_mgr: SandboxMemoryManager, host_funcs: Arc>, guest_max_log_level: Option, - #[cfg(gdb)] dbg_mem_access_fn: Arc>>, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()>; /// Map a region of host memory into the sandbox. @@ -171,7 +171,7 @@ pub(crate) trait Hypervisor: Debug + Send { fn dispatch_call_from_host( &mut self, dispatch_func_addr: RawPtr, - #[cfg(gdb)] dbg_mem_access_fn: Arc>>, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()>; /// Handle an IO exit from the internally stored vCPU. @@ -236,7 +236,7 @@ pub(crate) trait Hypervisor: Debug + Send { /// handles the cases when the vCPU stops due to a Debug event fn handle_debug( &mut self, - _dbg_mem_access_fn: Arc>>, + _dbg_mem_access_fn: Arc>>, _stop_reason: VcpuStopReason, ) -> Result<()> { unimplemented!() @@ -289,7 +289,7 @@ impl VirtualCPU { #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] pub(crate) fn run( hv: &mut dyn Hypervisor, - #[cfg(gdb)] dbg_mem_access_fn: Arc>>, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()> { loop { match hv.run() { diff --git a/src/hyperlight_host/src/lib.rs b/src/hyperlight_host/src/lib.rs index e1cc2e5a2..34c7ddd2a 100644 --- a/src/hyperlight_host/src/lib.rs +++ b/src/hyperlight_host/src/lib.rs @@ -87,8 +87,6 @@ pub(crate) mod testing; /// The re-export for the `HyperlightError` type pub use error::HyperlightError; -/// Re-export for `HypervisorWrapper` trait -/// Re-export for `MemMgrWrapper` type /// A sandbox that can call be used to make multiple calls to guest functions, /// and otherwise reused multiple times pub use sandbox::MultiUseSandbox; diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 787f095e2..f578f3ea8 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -74,6 +74,10 @@ pub(crate) struct SandboxMemoryManager { pub(crate) entrypoint_offset: Offset, /// How many memory regions were mapped after sandbox creation pub(crate) mapped_rgns: u64, + /// Stack cookie for stack guard verification + pub(crate) stack_cookie: [u8; STACK_COOKIE_LEN], + /// Buffer for accumulating guest abort messages + pub(crate) abort_buffer: Vec, } impl SandboxMemoryManager @@ -82,11 +86,12 @@ where { /// Create a new `SandboxMemoryManager` with the given parameters #[instrument(skip_all, parent = Span::current(), level= "Trace")] - fn new( + pub(crate) fn new( layout: SandboxMemoryLayout, shared_mem: S, load_addr: RawPtr, entrypoint_offset: Offset, + stack_cookie: [u8; STACK_COOKIE_LEN], ) -> Self { Self { layout, @@ -94,10 +99,24 @@ where load_addr, entrypoint_offset, mapped_rgns: 0, + stack_cookie, + abort_buffer: Vec::new(), } } + /// Get the stack cookie + #[instrument(skip_all, parent = Span::current(), level= "Trace")] + pub(crate) fn get_stack_cookie(&self) -> &[u8; STACK_COOKIE_LEN] { + &self.stack_cookie + } + + /// Get mutable access to the abort buffer + pub(crate) fn get_abort_buffer_mut(&mut self) -> &mut Vec { + &mut self.abort_buffer + } + /// Get `SharedMemory` in `self` as a mutable reference + #[cfg(any(gdb, test))] pub(crate) fn get_shared_mem_mut(&mut self) -> &mut S { &mut self.shared_mem } @@ -334,8 +353,18 @@ impl SandboxMemoryManager { &mut shared_mem.as_mut_slice()[layout.get_guest_code_offset()..], )?; + let stack_cookie = rand::random::<[u8; STACK_COOKIE_LEN]>(); + let stack_offset = layout.get_top_of_user_stack_offset(); + shared_mem.copy_from_slice(&stack_cookie, stack_offset)?; + Ok(( - Self::new(layout, shared_mem, load_addr, entrypoint_offset), + Self::new( + layout, + shared_mem, + load_addr, + entrypoint_offset, + stack_cookie, + ), load_info, )) } @@ -376,12 +405,23 @@ impl SandboxMemoryManager { Ok(()) } - /// Set the stack guard to `cookie` using `layout` to calculate - /// its location and `shared_mem` to write it. + /// Write memory layout #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - pub(crate) fn set_stack_guard(&mut self, cookie: &[u8; STACK_COOKIE_LEN]) -> Result<()> { - let stack_offset = self.layout.get_top_of_user_stack_offset(); - self.shared_mem.copy_from_slice(cookie, stack_offset) + pub(crate) fn write_memory_layout(&mut self) -> Result<()> { + let mem_size = self.shared_mem.mem_size(); + self.layout.write( + &mut self.shared_mem, + SandboxMemoryLayout::BASE_ADDRESS, + mem_size, + ) + } + + /// Write init data + #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] + pub(crate) fn write_init_data(&mut self, user_memory: &[u8]) -> Result<()> { + self.layout + .write_init_data(&mut self.shared_mem, user_memory)?; + Ok(()) } /// Wraps ExclusiveSharedMemory::build @@ -398,14 +438,18 @@ impl SandboxMemoryManager { layout: self.layout, load_addr: self.load_addr.clone(), entrypoint_offset: self.entrypoint_offset, - mapped_rgns: 0, + mapped_rgns: self.mapped_rgns, + stack_cookie: self.stack_cookie, + abort_buffer: self.abort_buffer, }, SandboxMemoryManager { shared_mem: gshm, layout: self.layout, load_addr: self.load_addr.clone(), entrypoint_offset: self.entrypoint_offset, - mapped_rgns: 0, + mapped_rgns: self.mapped_rgns, + stack_cookie: self.stack_cookie, + abort_buffer: Vec::new(), // Guest doesn't need abort buffer }, ) } @@ -425,10 +469,11 @@ impl SandboxMemoryManager { /// documentation at the bottom `set_stack_guard` for description /// of why it isn't. #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - pub(crate) fn check_stack_guard(&self, cookie: [u8; STACK_COOKIE_LEN]) -> Result { + pub(crate) fn check_stack_guard(&self) -> Result { + let expected = self.stack_cookie; let offset = self.layout.get_top_of_user_stack_offset(); - let test_cookie: [u8; STACK_COOKIE_LEN] = self.shared_mem.read(offset)?; - let cmp_res = cookie.iter().cmp(test_cookie.iter()); + let actual: [u8; STACK_COOKIE_LEN] = self.shared_mem.read(offset)?; + let cmp_res = expected.iter().cmp(actual.iter()); Ok(cmp_res == Ordering::Equal) } diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index b1b41fff2..9223c5e1b 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -31,9 +31,9 @@ use hyperlight_common::flatbuffer_wrappers::function_types::{ use hyperlight_common::flatbuffer_wrappers::util::estimate_flatbuffer_capacity; use tracing::{Span, instrument}; +use super::Callable; use super::host_funcs::FunctionRegistry; use super::snapshot::Snapshot; -use super::{Callable, WrapperGetter}; use crate::HyperlightError::SnapshotSandboxMismatch; use crate::func::guest_err::check_for_guest_error; use crate::func::{ParameterTuple, SupportedReturnType}; @@ -41,10 +41,10 @@ use crate::hypervisor::{Hypervisor, InterruptHandle}; #[cfg(unix)] use crate::mem::memory_region::MemoryRegionType; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; +use crate::mem::mgr::SandboxMemoryManager; use crate::mem::ptr::RawPtr; use crate::mem::shared_mem::HostSharedMemory; use crate::metrics::maybe_time_and_emit_guest_call; -use crate::sandbox::mem_mgr::MemMgrWrapper; use crate::{Result, log_then_return}; /// Global counter for assigning unique IDs to sandboxes @@ -59,11 +59,11 @@ pub struct MultiUseSandbox { id: u64, // We need to keep a reference to the host functions, even if the compiler marks it as unused. The compiler cannot detect our dynamic usages of the host function in `HyperlightFunction::call`. pub(super) _host_funcs: Arc>, - pub(crate) mem_mgr: MemMgrWrapper, + pub(crate) mem_mgr: SandboxMemoryManager, vm: Box, dispatch_ptr: RawPtr, #[cfg(gdb)] - dbg_mem_access_fn: Arc>>, + dbg_mem_access_fn: Arc>>, /// If the current state of the sandbox has been captured in a snapshot, /// that snapshot is stored here. snapshot: Option, @@ -78,10 +78,10 @@ impl MultiUseSandbox { #[instrument(skip_all, parent = Span::current(), level = "Trace")] pub(super) fn from_uninit( host_funcs: Arc>, - mgr: MemMgrWrapper, + mgr: SandboxMemoryManager, vm: Box, dispatch_ptr: RawPtr, - #[cfg(gdb)] dbg_mem_access_fn: Arc>>, + #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> MultiUseSandbox { Self { id: SANDBOX_ID_COUNTER.fetch_add(1, Ordering::Relaxed), @@ -125,10 +125,7 @@ impl MultiUseSandbox { } let mapped_regions_iter = self.vm.get_mapped_regions(); let mapped_regions_vec: Vec = mapped_regions_iter.cloned().collect(); - let memory_snapshot = self - .mem_mgr - .unwrap_mgr_mut() - .snapshot(self.id, mapped_regions_vec)?; + let memory_snapshot = self.mem_mgr.snapshot(self.id, mapped_regions_vec)?; let inner = Arc::new(memory_snapshot); let snapshot = Snapshot { inner }; self.snapshot = Some(snapshot.clone()); @@ -179,9 +176,7 @@ impl MultiUseSandbox { return Err(SnapshotSandboxMismatch); } - self.mem_mgr - .unwrap_mgr_mut() - .restore_snapshot(&snapshot.inner)?; + self.mem_mgr.restore_snapshot(&snapshot.inner)?; let current_regions: HashSet<_> = self.vm.get_mapped_regions().cloned().collect(); let snapshot_regions: HashSet<_> = snapshot.inner.regions().iter().cloned().collect(); @@ -326,7 +321,7 @@ impl MultiUseSandbox { // Reset snapshot since we are mutating the sandbox state self.snapshot = None; unsafe { self.vm.map_region(rgn) }?; - self.mem_mgr.unwrap_mgr_mut().mapped_rgns += 1; + self.mem_mgr.mapped_rgns += 1; Ok(()) } @@ -406,9 +401,7 @@ impl MultiUseSandbox { let mut builder = FlatBufferBuilder::with_capacity(estimated_capacity); let buffer = fc.encode(&mut builder); - self.get_mgr_wrapper_mut() - .as_mut() - .write_guest_function_call(buffer)?; + self.mem_mgr.write_guest_function_call(buffer)?; self.vm.dispatch_call_from_host( self.dispatch_ptr.clone(), @@ -417,11 +410,9 @@ impl MultiUseSandbox { )?; self.mem_mgr.check_stack_guard()?; - check_for_guest_error(self.get_mgr_wrapper_mut())?; + check_for_guest_error(&mut self.mem_mgr)?; - self.get_mgr_wrapper_mut() - .as_mut() - .get_guest_function_call_result() + self.mem_mgr.get_guest_function_call_result() })(); // In the happy path we do not need to clear io-buffers from the host because: @@ -430,7 +421,7 @@ impl MultiUseSandbox { // - any serialized host function call are zeroed out by us (the host) during deserialization, see `get_host_function_call` // - any serialized host function result is zeroed out by the guest during deserialization, see `get_host_return_value` if res.is_err() { - self.get_mgr_wrapper_mut().as_mut().clear_io_buffers(); + self.mem_mgr.clear_io_buffers(); } res } @@ -479,15 +470,6 @@ impl Callable for MultiUseSandbox { } } -impl WrapperGetter for MultiUseSandbox { - fn get_mgr_wrapper(&self) -> &MemMgrWrapper { - &self.mem_mgr - } - fn get_mgr_wrapper_mut(&mut self) -> &mut MemMgrWrapper { - &mut self.mem_mgr - } -} - impl std::fmt::Debug for MultiUseSandbox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MultiUseSandbox") diff --git a/src/hyperlight_host/src/sandbox/mem_mgr.rs b/src/hyperlight_host/src/sandbox/mem_mgr.rs deleted file mode 100644 index eb25af9da..000000000 --- a/src/hyperlight_host/src/sandbox/mem_mgr.rs +++ /dev/null @@ -1,123 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -use tracing::{Span, instrument}; - -use crate::Result; -use crate::mem::layout::SandboxMemoryLayout; -use crate::mem::mgr::{STACK_COOKIE_LEN, SandboxMemoryManager}; -use crate::mem::shared_mem::{ - ExclusiveSharedMemory, GuestSharedMemory, HostSharedMemory, SharedMemory, -}; - -/// StackCookie -pub type StackCookie = [u8; STACK_COOKIE_LEN]; - -/// A container with methods for accessing `SandboxMemoryManager` and other -/// related objects -#[derive(Clone)] -pub(crate) struct MemMgrWrapper { - mgr: SandboxMemoryManager, - stack_cookie: StackCookie, - abort_buffer: Vec, -} - -impl MemMgrWrapper { - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - pub(super) fn new(mgr: SandboxMemoryManager, stack_cookie: StackCookie) -> Self { - Self { - mgr, - stack_cookie, - abort_buffer: Vec::new(), - } - } - - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - pub(crate) fn unwrap_mgr(&self) -> &SandboxMemoryManager { - &self.mgr - } - - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - pub(crate) fn unwrap_mgr_mut(&mut self) -> &mut SandboxMemoryManager { - &mut self.mgr - } - - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - pub(super) fn get_stack_cookie(&self) -> &StackCookie { - &self.stack_cookie - } - - pub fn get_abort_buffer_mut(&mut self) -> &mut Vec { - &mut self.abort_buffer - } -} - -impl AsMut> for MemMgrWrapper { - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - fn as_mut(&mut self) -> &mut SandboxMemoryManager { - self.unwrap_mgr_mut() - } -} - -impl AsRef> for MemMgrWrapper { - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - fn as_ref(&self) -> &SandboxMemoryManager { - self.unwrap_mgr() - } -} - -impl MemMgrWrapper { - pub(crate) fn build( - self, - ) -> ( - MemMgrWrapper, - SandboxMemoryManager, - ) { - let (hshm, gshm) = self.mgr.build(); - (MemMgrWrapper::new(hshm, self.stack_cookie), gshm) - } - - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - pub(super) fn write_memory_layout(&mut self) -> Result<()> { - let mgr = self.unwrap_mgr_mut(); - let layout = mgr.layout; - let shared_mem = mgr.get_shared_mem_mut(); - let mem_size = shared_mem.mem_size(); - layout.write(shared_mem, SandboxMemoryLayout::BASE_ADDRESS, mem_size) - } - - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - pub(super) fn write_init_data(&mut self, user_memory: &[u8]) -> Result<()> { - let mgr = self.unwrap_mgr_mut(); - let layout = mgr.layout; - let shared_mem = mgr.get_shared_mem_mut(); - layout.write_init_data(shared_mem, user_memory)?; - Ok(()) - } -} - -impl MemMgrWrapper { - /// Check the stack guard against the given `stack_cookie`. - /// - /// Return `Ok(true)` if the given cookie matches the one in guest memory, - /// and `Ok(false)` otherwise. Return `Err` if it could not be found or - /// there was some other error. - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - pub(crate) fn check_stack_guard(&self) -> Result { - self.unwrap_mgr() - .check_stack_guard(*self.get_stack_cookie()) - } -} diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index b3f54e738..2f8bee004 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -23,9 +23,6 @@ pub(crate) mod hypervisor; /// Functionality for dealing with initialized sandboxes that can /// call 0 or more guest functions pub mod initialized_multi_use; -/// Functionality for interacting with a sandbox's internally-stored -/// `SandboxMemoryManager` -pub(crate) mod mem_mgr; pub(crate) mod outb; /// Functionality for creating uninitialized sandboxes, manipulating them, /// and converting them to initialized sandboxes. @@ -59,7 +56,6 @@ pub use uninitialized::GuestBinary; /// Re-export for `UninitializedSandbox` type pub use uninitialized::UninitializedSandbox; -use self::mem_mgr::MemMgrWrapper; #[cfg(target_os = "windows")] use crate::hypervisor::windows_hypervisor_platform; use crate::mem::shared_mem::HostSharedMemory; @@ -227,12 +223,6 @@ impl TraceInfo { } } -pub(crate) trait WrapperGetter { - #[allow(dead_code)] - fn get_mgr_wrapper(&self) -> &MemMgrWrapper; - fn get_mgr_wrapper_mut(&mut self) -> &mut MemMgrWrapper; -} - #[cfg(test)] mod tests { use std::sync::Arc; diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index 20a5d8f94..8f9c1166f 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -33,7 +33,6 @@ use tracing::{Span, instrument}; use tracing_log::format_trace; use super::host_funcs::FunctionRegistry; -use super::mem_mgr::MemMgrWrapper; #[cfg(feature = "trace_guest")] use crate::hypervisor::Hypervisor; #[cfg(feature = "trace_guest")] @@ -109,7 +108,7 @@ pub(super) fn outb_log(mgr: &mut SandboxMemoryManager) -> Resu const ABORT_TERMINATOR: u8 = 0xFF; const MAX_ABORT_BUFFER_LEN: usize = 1024; -fn outb_abort(mem_mgr: &mut MemMgrWrapper, data: u32) -> Result<()> { +fn outb_abort(mem_mgr: &mut SandboxMemoryManager, data: u32) -> Result<()> { let buffer = mem_mgr.get_abort_buffer_mut(); let bytes = data.to_le_bytes(); // [len, b1, b2, b3] @@ -269,25 +268,23 @@ pub(super) fn record_guest_trace_frame( /// Handles OutB operations from the guest. #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] pub(crate) fn handle_outb( - mem_mgr: &mut MemMgrWrapper, + mem_mgr: &mut SandboxMemoryManager, host_funcs: Arc>, #[cfg(feature = "trace_guest")] _hv: &mut dyn Hypervisor, port: u16, data: u32, ) -> Result<()> { match port.try_into()? { - OutBAction::Log => outb_log(mem_mgr.as_mut()), + OutBAction::Log => outb_log(mem_mgr), OutBAction::CallFunction => { - let call = mem_mgr.as_mut().get_host_function_call()?; // pop output buffer + let call = mem_mgr.get_host_function_call()?; // pop output buffer let name = call.function_name.clone(); let args: Vec = call.parameters.unwrap_or(vec![]); let res = host_funcs .try_lock() .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? .call_host_function(&name, args)?; - mem_mgr - .as_mut() - .write_response_from_host_method_call(&res)?; // push input buffers + mem_mgr.write_response_from_host_method_call(&res)?; // push input buffers Ok(()) } @@ -305,7 +302,7 @@ pub(crate) fn handle_outb( } #[cfg(feature = "unwind_guest")] OutBAction::TraceRecordStack => { - let Ok(stack) = unwind(_hv, mem_mgr.as_ref(), _hv.trace_info_as_ref()) else { + let Ok(stack) = unwind(_hv, mem_mgr, _hv.trace_info_as_ref()) else { return Ok(()); }; record_trace_frame(_hv.trace_info_as_ref(), 1u64, |f| { @@ -314,7 +311,7 @@ pub(crate) fn handle_outb( } #[cfg(feature = "mem_profile")] OutBAction::TraceMemoryAlloc => { - let Ok(stack) = unwind(_hv, mem_mgr.as_ref(), _hv.trace_info_as_ref()) else { + let Ok(stack) = unwind(_hv, mem_mgr, _hv.trace_info_as_ref()) else { return Ok(()); }; let Ok(amt) = _hv.read_trace_reg(crate::hypervisor::TraceRegister::RAX) else { @@ -331,7 +328,7 @@ pub(crate) fn handle_outb( } #[cfg(feature = "mem_profile")] OutBAction::TraceMemoryFree => { - let Ok(stack) = unwind(_hv, mem_mgr.as_ref(), _hv.trace_info_as_ref()) else { + let Ok(stack) = unwind(_hv, mem_mgr, _hv.trace_info_as_ref()) else { return Ok(()); }; let Ok(ptr) = _hv.read_trace_reg(crate::hypervisor::TraceRegister::RCX) else { @@ -355,7 +352,6 @@ pub(crate) fn handle_outb( // Read the trace records from the guest memory mem_mgr - .as_ref() .shared_mem .copy_to_slice(buffer, ptr as usize - SandboxMemoryLayout::BASE_ADDRESS) .map_err(|e| { diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index 6d905cf52..679d5e0e5 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -23,7 +23,6 @@ use log::LevelFilter; use tracing::{Span, instrument}; use super::host_funcs::{FunctionRegistry, default_writer_func}; -use super::mem_mgr::MemMgrWrapper; use super::uninitialized_evolve::evolve_impl_multi_use; use crate::func::host_functions::{HostFunction, register_host_function}; use crate::func::{ParameterTuple, SupportedReturnType}; @@ -31,7 +30,7 @@ use crate::func::{ParameterTuple, SupportedReturnType}; use crate::log_build_details; use crate::mem::exe::ExeInfo; use crate::mem::memory_region::{DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegionFlags}; -use crate::mem::mgr::{STACK_COOKIE_LEN, SandboxMemoryManager}; +use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::ExclusiveSharedMemory; use crate::sandbox::SandboxConfiguration; use crate::{MultiUseSandbox, Result, new_error}; @@ -77,7 +76,7 @@ pub struct UninitializedSandbox { /// Registered host functions pub(crate) host_funcs: Arc>, /// The memory manager for the sandbox. - pub(crate) mgr: MemMgrWrapper, + pub(crate) mgr: SandboxMemoryManager, pub(crate) max_guest_log_level: Option, pub(crate) config: SandboxConfiguration, #[cfg(any(crashdump, gdb))] @@ -88,7 +87,7 @@ pub struct UninitializedSandbox { impl Debug for UninitializedSandbox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("UninitializedSandbox") - .field("memory_layout", &self.mgr.unwrap_mgr().layout) + .field("memory_layout", &self.mgr.layout) .finish() } } @@ -233,17 +232,11 @@ impl UninitializedSandbox { } }; - let (mut mem_mgr_wrapper, load_info) = { - let (mut mgr, load_info) = UninitializedSandbox::load_guest_binary( - sandbox_cfg, - &guest_binary, - guest_blob.as_ref(), - )?; - - let stack_guard = Self::create_stack_guard(); - mgr.set_stack_guard(&stack_guard)?; - (MemMgrWrapper::new(mgr, stack_guard), load_info) - }; + let (mut mem_mgr_wrapper, load_info) = UninitializedSandbox::load_guest_binary( + sandbox_cfg, + &guest_binary, + guest_blob.as_ref(), + )?; mem_mgr_wrapper.write_memory_layout()?; @@ -272,11 +265,6 @@ impl UninitializedSandbox { Ok(sandbox) } - #[instrument(skip_all, parent = Span::current(), level = "Trace")] - fn create_stack_guard() -> [u8; STACK_COOKIE_LEN] { - rand::random::<[u8; STACK_COOKIE_LEN]>() - } - /// Load the file at `bin_path_str` into a PE file, then attempt to /// load the PE file into a `SandboxMemoryManager` and return it. /// diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index e3334fb3e..f73e334e8 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -33,12 +33,12 @@ use crate::mem::ptr_offset::Offset; use crate::mem::shared_mem::GuestSharedMemory; #[cfg(any(feature = "init-paging", target_os = "windows"))] use crate::mem::shared_mem::SharedMemory; +use crate::sandbox::HostSharedMemory; #[cfg(feature = "trace_guest")] use crate::sandbox::TraceInfo; #[cfg(gdb)] use crate::sandbox::config::DebugInfo; use crate::sandbox::host_funcs::FunctionRegistry; -use crate::sandbox::{HostSharedMemory, MemMgrWrapper}; #[cfg(target_os = "linux")] use crate::signal_handlers::setup_signal_handlers; use crate::{MultiUseSandbox, Result, UninitializedSandbox, log_then_return, new_error}; @@ -62,7 +62,7 @@ fn evolve_impl( where TransformFunc: Fn( Arc>, - MemMgrWrapper, + SandboxMemoryManager, Box, RawPtr, ) -> Result, @@ -104,7 +104,7 @@ where dbg_mem_access_hdl, )?; - let dispatch_function_addr = hshm.as_ref().get_pointer_to_dispatch_function()?; + let dispatch_function_addr = hshm.get_pointer_to_dispatch_function()?; if dispatch_function_addr == 0 { return Err(new_error!("Dispatch function address is null")); } From afdfc042d177144dcd4bbb7e5dc7a7ef838aa5ee Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Mon, 15 Sep 2025 20:19:54 +0100 Subject: [PATCH 172/271] Add missing clippy checks to clippy-exhaustive-target (#890) Signed-off-by: Simon Davies --- Justfile | 6 +++++- src/hyperlight_guest_tracing/src/lib.rs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Justfile b/Justfile index 6e8218958..c0cedc8ea 100644 --- a/Justfile +++ b/Justfile @@ -260,6 +260,10 @@ clippy-exhaustive target=default-target: (witguest-wit) ./hack/clippy-package-features.sh hyperlight-guest-bin {{ target }} ./hack/clippy-package-features.sh hyperlight-common {{ target }} ./hack/clippy-package-features.sh hyperlight-testing {{ target }} + ./hack/clippy-package-features.sh hyperlight-component-macro {{ target }} + ./hack/clippy-package-features.sh hyperlight-component-util {{ target }} + ./hack/clippy-package-features.sh hyperlight-guest-tracing-macro {{ target }} + ./hack/clippy-package-features.sh hyperlight-guest-tracing {{ target }} just clippy-guests {{ target }} # Test a specific package with all feature combinations @@ -268,7 +272,7 @@ clippy-package package target=default-target: (witguest-wit) # Verify Minimum Supported Rust Version verify-msrv: - ./dev/verify-msrv.sh hyperlight-host hyperlight-guest hyperlight-guest-lib hyperlight-common + ./dev/verify-msrv.sh hyperlight-common hyperlight-guest hyperlight-guest-bin hyperlight-host hyperlight-component-util hyperlight-component-macro hyperlight-guest-tracing-macro hyperlight-guest-tracing ##################### ### RUST EXAMPLES ### diff --git a/src/hyperlight_guest_tracing/src/lib.rs b/src/hyperlight_guest_tracing/src/lib.rs index b89f88e9b..631890161 100644 --- a/src/hyperlight_guest_tracing/src/lib.rs +++ b/src/hyperlight_guest_tracing/src/lib.rs @@ -355,7 +355,7 @@ mod trace { #[test] fn test_trace_record_creation_valid() { let msg = "Valid message"; - let entry = TraceRecord::try_from(msg).expect("Failed to create TraceRecord"); + let entry = TraceRecord::from(msg); assert_eq!(entry.msg_len, msg.len()); assert_eq!(&entry.msg[..msg.len()], msg.as_bytes()); assert!(entry.cycles > 0); // Ensure cycles is set From 225ecb71e6efa59fa79719cf1c4ca91c6fe76708 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 11 Sep 2025 12:34:16 +0100 Subject: [PATCH 173/271] Update to Rust 1.89 Signed-off-by: Simon Davies --- .devcontainer/Dockerfile | 2 +- .github/workflows/Benchmarks.yml | 2 +- .github/workflows/CargoAudit.yml | 4 ++-- .github/workflows/CargoPublish.yml | 3 +-- .github/workflows/CreateDevcontainerImage.yml | 4 ++-- .github/workflows/CreateRelease.yml | 6 +++--- .github/workflows/copilot-setup-steps.yml | 2 +- .github/workflows/dep_build_guest_binaries.yml | 2 +- .github/workflows/dep_fuzzing.yml | 2 +- .github/workflows/dep_rust.yml | 4 ++-- Cargo.toml | 2 +- README.md | 2 +- rust-toolchain.toml | 2 +- src/hyperlight_common/src/lib.rs | 9 +-------- 14 files changed, 19 insertions(+), 27 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index ee79b5dff..d4191b5b2 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -48,7 +48,7 @@ RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhisto USER $USER -ARG RUST_TOOLCHAIN=1.86 +ARG RUST_TOOLCHAIN=1.89 # Install rust RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \ diff --git a/.github/workflows/Benchmarks.yml b/.github/workflows/Benchmarks.yml index d5ad18939..25b62de49 100644 --- a/.github/workflows/Benchmarks.yml +++ b/.github/workflows/Benchmarks.yml @@ -33,7 +33,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: - rust-toolchain: "1.86" + rust-toolchain: "1.89" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/CargoAudit.yml b/.github/workflows/CargoAudit.yml index 4c19c8a74..b38b7507d 100644 --- a/.github/workflows/CargoAudit.yml +++ b/.github/workflows/CargoAudit.yml @@ -19,8 +19,8 @@ jobs: # TODO: Once the runner image is updated to include the necessary tools (without downloading), we can switch to the common workflow. - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.86" - + toolchain: "1.89" + - uses: rustsec/audit-check@v2.0.0 with: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/CargoPublish.yml b/.github/workflows/CargoPublish.yml index 0c4ad8304..7bebfb28c 100644 --- a/.github/workflows/CargoPublish.yml +++ b/.github/workflows/CargoPublish.yml @@ -34,8 +34,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: - rust-toolchain: "1.86" - + rust-toolchain: "1.89" - name: Check crate versions shell: bash run: | diff --git a/.github/workflows/CreateDevcontainerImage.yml b/.github/workflows/CreateDevcontainerImage.yml index 72b977f98..6716ef233 100644 --- a/.github/workflows/CreateDevcontainerImage.yml +++ b/.github/workflows/CreateDevcontainerImage.yml @@ -15,8 +15,8 @@ env: IMAGE_NAME: ${{ github.repository }}-devcontainer USER: vscode GROUP: vscode - LLVM_VERSION: 17 - RUST_TOOLCHAIN_DEFAULT: 1.86 + LLVM_VERSION: 18 + RUST_TOOLCHAIN_DEFAULT: 1.89 RUST_TOOLCHAIN_FILE: rust-toolchain.toml # There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. diff --git a/.github/workflows/CreateRelease.yml b/.github/workflows/CreateRelease.yml index 07e8e6da2..64791b3f5 100644 --- a/.github/workflows/CreateRelease.yml +++ b/.github/workflows/CreateRelease.yml @@ -33,7 +33,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: - rust-toolchain: "1.86" + rust-toolchain: "1.89" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -54,7 +54,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: - rust-toolchain: "1.86" + rust-toolchain: "1.89" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -114,7 +114,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: - rust-toolchain: "1.86" + rust-toolchain: "1.89" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index e50e7792c..d1343bcc6 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -28,6 +28,6 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: - rust-toolchain: "1.86" + rust-toolchain: "1.89" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/dep_build_guest_binaries.yml b/.github/workflows/dep_build_guest_binaries.yml index 9656f5702..5b20336ea 100644 --- a/.github/workflows/dep_build_guest_binaries.yml +++ b/.github/workflows/dep_build_guest_binaries.yml @@ -33,7 +33,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: - rust-toolchain: "1.86" + rust-toolchain: "1.89" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/dep_fuzzing.yml b/.github/workflows/dep_fuzzing.yml index 4386cc58a..d4c4f2609 100644 --- a/.github/workflows/dep_fuzzing.yml +++ b/.github/workflows/dep_fuzzing.yml @@ -34,7 +34,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: - rust-toolchain: "1.86" + rust-toolchain: "1.89" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index 25777ca43..ffa79aa8c 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -48,7 +48,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: - rust-toolchain: "1.86" + rust-toolchain: "1.89" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -100,7 +100,7 @@ jobs: - uses: hyperlight-dev/ci-setup-workflow@v1.8.0 with: - rust-toolchain: "1.86" + rust-toolchain: "1.89" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Cargo.toml b/Cargo.toml index 8bccc53d3..dcf5f8f7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ exclude = [ [workspace.package] version = "0.9.0" edition = "2024" -rust-version = "1.86" +rust-version = "1.88" license = "Apache-2.0" homepage = "https://github.com/hyperlight-dev/hyperlight" repository = "https://github.com/hyperlight-dev/hyperlight" diff --git a/README.md b/README.md index eed169cfc..185cc5fdc 100644 --- a/README.md +++ b/README.md @@ -190,7 +190,7 @@ After having an environment with a hypervisor setup, running the example has the 1. On Linux or WSL, you'll most likely need build essential. For Ubuntu, run `sudo apt install build-essential`. For Azure Linux, run `sudo dnf install build-essential`. -2. [Rust](https://www.rust-lang.org/tools/install). Install toolchain v1.86 or later. +2. [Rust](https://www.rust-lang.org/tools/install). Install toolchain v1.89 or later. 3. [just](https://github.com/casey/just). `cargo install just` On Windows you also need [pwsh](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.4). 4. [clang and LLVM](https://clang.llvm.org/get_started.html). - On Ubuntu, run: diff --git a/rust-toolchain.toml b/rust-toolchain.toml index b8aa83f43..aec2748e0 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.86" +channel = "1.89" # Target used for guest binaries. This is an additive list of targets in addition to host platform. # Will install the target if not already installed when building guest binaries. targets = ["x86_64-unknown-none", "x86_64-unknown-linux-musl"] diff --git a/src/hyperlight_common/src/lib.rs b/src/hyperlight_common/src/lib.rs index e22cf6417..3ec6aa6fc 100644 --- a/src/hyperlight_common/src/lib.rs +++ b/src/hyperlight_common/src/lib.rs @@ -25,14 +25,7 @@ extern crate alloc; pub mod flatbuffer_wrappers; /// cbindgen:ignore /// FlatBuffers-related utilities and (mostly) generated code -#[allow( - dead_code, - unused_imports, - clippy::all, - clippy::unwrap_used, - unsafe_op_in_unsafe_fn, - non_camel_case_types -)] +#[allow(clippy::all, warnings)] mod flatbuffers; /// cbindgen:ignore pub mod mem; From ccd623a5dcb20ae1faa9e3c49cea363dfec58a79 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 11 Sep 2025 16:25:47 +0100 Subject: [PATCH 174/271] Regenerate flatbuffer code Signed-off-by: Simon Davies --- .../generated/error_code_generated.rs | 6 +- .../generated/function_call_generated.rs | 6 +- .../function_call_result_generated.rs | 6 +- .../generated/function_call_type_generated.rs | 6 +- .../generated/guest_error_generated.rs | 6 +- .../generated/guest_log_data_generated.rs | 6 +- .../hyperlight/generated/hlbool_generated.rs | 2 +- .../generated/hldouble_generated.rs | 2 +- .../hyperlight/generated/hlfloat_generated.rs | 2 +- .../hyperlight/generated/hlint_generated.rs | 2 +- .../hyperlight/generated/hllong_generated.rs | 2 +- .../hlsizeprefixedbuffer_generated.rs | 2 +- .../generated/hlstring_generated.rs | 2 +- .../hyperlight/generated/hluint_generated.rs | 2 +- .../hyperlight/generated/hlulong_generated.rs | 2 +- .../generated/hlvecbytes_generated.rs | 2 +- .../hyperlight/generated/hlvoid_generated.rs | 2 +- .../host_function_definition_generated.rs | 87 ++++++++++++++++++- .../host_function_details_generated.rs | 6 +- .../generated/log_level_generated.rs | 6 +- .../generated/parameter_generated.rs | 2 +- .../generated/parameter_type_generated.rs | 6 +- .../generated/parameter_value_generated.rs | 6 +- .../generated/return_type_generated.rs | 6 +- .../generated/return_value_generated.rs | 6 +- 25 files changed, 141 insertions(+), 42 deletions(-) diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/error_code_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/error_code_generated.rs index dba1ed055..6b03bb0cb 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/error_code_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/error_code_generated.rs @@ -124,7 +124,7 @@ impl<'a> flatbuffers::Follow<'a> for ErrorCode { type Inner = Self; #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - let b = flatbuffers::read_scalar_at::(buf, loc); + let b = unsafe { flatbuffers::read_scalar_at::(buf, loc) }; Self(b) } } @@ -133,7 +133,9 @@ impl flatbuffers::Push for ErrorCode { type Output = ErrorCode; #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - flatbuffers::emplace_scalar::(dst, self.0); + unsafe { + flatbuffers::emplace_scalar::(dst, self.0); + } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_generated.rs index 17d31fa9f..786d6de98 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for FunctionCall<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } @@ -290,14 +290,14 @@ pub fn size_prefixed_root_as_function_call_with_opts<'b, 'o>( /// # Safety /// Callers must trust the given bytes do indeed contain a valid `FunctionCall`. pub unsafe fn root_as_function_call_unchecked(buf: &[u8]) -> FunctionCall { - flatbuffers::root_unchecked::(buf) + unsafe { flatbuffers::root_unchecked::(buf) } } #[inline] /// Assumes, without verification, that a buffer of bytes contains a size prefixed FunctionCall and returns it. /// # Safety /// Callers must trust the given bytes do indeed contain a valid size prefixed `FunctionCall`. pub unsafe fn size_prefixed_root_as_function_call_unchecked(buf: &[u8]) -> FunctionCall { - flatbuffers::size_prefixed_root_unchecked::(buf) + unsafe { flatbuffers::size_prefixed_root_unchecked::(buf) } } #[inline] pub fn finish_function_call_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_result_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_result_generated.rs index 8ff674e6c..9e7cddd15 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_result_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_result_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for FunctionCallResult<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } @@ -513,7 +513,7 @@ pub fn size_prefixed_root_as_function_call_result_with_opts<'b, 'o>( /// # Safety /// Callers must trust the given bytes do indeed contain a valid `FunctionCallResult`. pub unsafe fn root_as_function_call_result_unchecked(buf: &[u8]) -> FunctionCallResult { - flatbuffers::root_unchecked::(buf) + unsafe { flatbuffers::root_unchecked::(buf) } } #[inline] /// Assumes, without verification, that a buffer of bytes contains a size prefixed FunctionCallResult and returns it. @@ -522,7 +522,7 @@ pub unsafe fn root_as_function_call_result_unchecked(buf: &[u8]) -> FunctionCall pub unsafe fn size_prefixed_root_as_function_call_result_unchecked( buf: &[u8], ) -> FunctionCallResult { - flatbuffers::size_prefixed_root_unchecked::(buf) + unsafe { flatbuffers::size_prefixed_root_unchecked::(buf) } } #[inline] pub fn finish_function_call_result_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_type_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_type_generated.rs index 67edacdf9..84356d89a 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_type_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_type_generated.rs @@ -66,7 +66,7 @@ impl<'a> flatbuffers::Follow<'a> for FunctionCallType { type Inner = Self; #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - let b = flatbuffers::read_scalar_at::(buf, loc); + let b = unsafe { flatbuffers::read_scalar_at::(buf, loc) }; Self(b) } } @@ -75,7 +75,9 @@ impl flatbuffers::Push for FunctionCallType { type Output = FunctionCallType; #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - flatbuffers::emplace_scalar::(dst, self.0); + unsafe { + flatbuffers::emplace_scalar::(dst, self.0); + } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_error_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_error_generated.rs index 57887a31b..24b76ea47 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_error_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_error_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for GuestError<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } @@ -192,14 +192,14 @@ pub fn size_prefixed_root_as_guest_error_with_opts<'b, 'o>( /// # Safety /// Callers must trust the given bytes do indeed contain a valid `GuestError`. pub unsafe fn root_as_guest_error_unchecked(buf: &[u8]) -> GuestError { - flatbuffers::root_unchecked::(buf) + unsafe { flatbuffers::root_unchecked::(buf) } } #[inline] /// Assumes, without verification, that a buffer of bytes contains a size prefixed GuestError and returns it. /// # Safety /// Callers must trust the given bytes do indeed contain a valid size prefixed `GuestError`. pub unsafe fn size_prefixed_root_as_guest_error_unchecked(buf: &[u8]) -> GuestError { - flatbuffers::size_prefixed_root_unchecked::(buf) + unsafe { flatbuffers::size_prefixed_root_unchecked::(buf) } } #[inline] pub fn finish_guest_error_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_log_data_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_log_data_generated.rs index 8deec7cad..d57f8ed7e 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_log_data_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_log_data_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for GuestLogData<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } @@ -288,14 +288,14 @@ pub fn size_prefixed_root_as_guest_log_data_with_opts<'b, 'o>( /// # Safety /// Callers must trust the given bytes do indeed contain a valid `GuestLogData`. pub unsafe fn root_as_guest_log_data_unchecked(buf: &[u8]) -> GuestLogData { - flatbuffers::root_unchecked::(buf) + unsafe { flatbuffers::root_unchecked::(buf) } } #[inline] /// Assumes, without verification, that a buffer of bytes contains a size prefixed GuestLogData and returns it. /// # Safety /// Callers must trust the given bytes do indeed contain a valid size prefixed `GuestLogData`. pub unsafe fn size_prefixed_root_as_guest_log_data_unchecked(buf: &[u8]) -> GuestLogData { - flatbuffers::size_prefixed_root_unchecked::(buf) + unsafe { flatbuffers::size_prefixed_root_unchecked::(buf) } } #[inline] pub fn finish_guest_log_data_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlbool_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlbool_generated.rs index d2005e5a5..c4a2b6673 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlbool_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlbool_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for hlbool<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hldouble_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hldouble_generated.rs index 5c71c2c9e..0cbabb8b1 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hldouble_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hldouble_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for hldouble<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlfloat_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlfloat_generated.rs index 93673efe1..ca59467d4 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlfloat_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlfloat_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for hlfloat<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlint_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlint_generated.rs index a162f6eec..726f3ba29 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlint_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlint_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for hlint<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hllong_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hllong_generated.rs index 690afaa26..7c088ff8c 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hllong_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hllong_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for hllong<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlsizeprefixedbuffer_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlsizeprefixedbuffer_generated.rs index ed1e74b37..cbbb2729c 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlsizeprefixedbuffer_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlsizeprefixedbuffer_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for hlsizeprefixedbuffer<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlstring_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlstring_generated.rs index ba8c2eb7f..cb2d7db09 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlstring_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlstring_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for hlstring<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hluint_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hluint_generated.rs index e10699658..67f8cbd6d 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hluint_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hluint_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for hluint<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlulong_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlulong_generated.rs index db83b936d..f701f3d6c 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlulong_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlulong_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for hlulong<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlvecbytes_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlvecbytes_generated.rs index e673cd425..8b1c4a109 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlvecbytes_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlvecbytes_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for hlvecbytes<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlvoid_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlvoid_generated.rs index 76e0e9f97..a218c60ba 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlvoid_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/hlvoid_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for hlvoid<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_definition_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_definition_generated.rs index 381f77fcc..010d111bf 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_definition_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_definition_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for HostFunctionDefinition<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } @@ -202,3 +202,88 @@ impl core::fmt::Debug for HostFunctionDefinition<'_> { ds.finish() } } +#[inline] +/// Verifies that a buffer of bytes contains a `HostFunctionDefinition` +/// and returns it. +/// Note that verification is still experimental and may not +/// catch every error, or be maximally performant. For the +/// previous, unchecked, behavior use +/// `root_as_host_function_definition_unchecked`. +pub fn root_as_host_function_definition( + buf: &[u8], +) -> Result { + flatbuffers::root::(buf) +} +#[inline] +/// Verifies that a buffer of bytes contains a size prefixed +/// `HostFunctionDefinition` and returns it. +/// Note that verification is still experimental and may not +/// catch every error, or be maximally performant. For the +/// previous, unchecked, behavior use +/// `size_prefixed_root_as_host_function_definition_unchecked`. +pub fn size_prefixed_root_as_host_function_definition( + buf: &[u8], +) -> Result { + flatbuffers::size_prefixed_root::(buf) +} +#[inline] +/// Verifies, with the given options, that a buffer of bytes +/// contains a `HostFunctionDefinition` and returns it. +/// Note that verification is still experimental and may not +/// catch every error, or be maximally performant. For the +/// previous, unchecked, behavior use +/// `root_as_host_function_definition_unchecked`. +pub fn root_as_host_function_definition_with_opts<'b, 'o>( + opts: &'o flatbuffers::VerifierOptions, + buf: &'b [u8], +) -> Result, flatbuffers::InvalidFlatbuffer> { + flatbuffers::root_with_opts::>(opts, buf) +} +#[inline] +/// Verifies, with the given verifier options, that a buffer of +/// bytes contains a size prefixed `HostFunctionDefinition` and returns +/// it. Note that verification is still experimental and may not +/// catch every error, or be maximally performant. For the +/// previous, unchecked, behavior use +/// `root_as_host_function_definition_unchecked`. +pub fn size_prefixed_root_as_host_function_definition_with_opts<'b, 'o>( + opts: &'o flatbuffers::VerifierOptions, + buf: &'b [u8], +) -> Result, flatbuffers::InvalidFlatbuffer> { + flatbuffers::size_prefixed_root_with_opts::>(opts, buf) +} +#[inline] +/// Assumes, without verification, that a buffer of bytes contains a HostFunctionDefinition and returns it. +/// # Safety +/// Callers must trust the given bytes do indeed contain a valid `HostFunctionDefinition`. +pub unsafe fn root_as_host_function_definition_unchecked(buf: &[u8]) -> HostFunctionDefinition { + unsafe { flatbuffers::root_unchecked::(buf) } +} +#[inline] +/// Assumes, without verification, that a buffer of bytes contains a size prefixed HostFunctionDefinition and returns it. +/// # Safety +/// Callers must trust the given bytes do indeed contain a valid size prefixed `HostFunctionDefinition`. +pub unsafe fn size_prefixed_root_as_host_function_definition_unchecked( + buf: &[u8], +) -> HostFunctionDefinition { + unsafe { flatbuffers::size_prefixed_root_unchecked::(buf) } +} +#[inline] +pub fn finish_host_function_definition_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( + fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, + root: flatbuffers::WIPOffset>, +) { + fbb.finish(root, None); +} + +#[inline] +pub fn finish_size_prefixed_host_function_definition_buffer< + 'a, + 'b, + A: flatbuffers::Allocator + 'a, +>( + fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, + root: flatbuffers::WIPOffset>, +) { + fbb.finish_size_prefixed(root, None); +} diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_details_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_details_generated.rs index 71edd22b3..a502dd491 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_details_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_details_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for HostFunctionDetails<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } @@ -187,7 +187,7 @@ pub fn size_prefixed_root_as_host_function_details_with_opts<'b, 'o>( /// # Safety /// Callers must trust the given bytes do indeed contain a valid `HostFunctionDetails`. pub unsafe fn root_as_host_function_details_unchecked(buf: &[u8]) -> HostFunctionDetails { - flatbuffers::root_unchecked::(buf) + unsafe { flatbuffers::root_unchecked::(buf) } } #[inline] /// Assumes, without verification, that a buffer of bytes contains a size prefixed HostFunctionDetails and returns it. @@ -196,7 +196,7 @@ pub unsafe fn root_as_host_function_details_unchecked(buf: &[u8]) -> HostFunctio pub unsafe fn size_prefixed_root_as_host_function_details_unchecked( buf: &[u8], ) -> HostFunctionDetails { - flatbuffers::size_prefixed_root_unchecked::(buf) + unsafe { flatbuffers::size_prefixed_root_unchecked::(buf) } } #[inline] pub fn finish_host_function_details_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/log_level_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/log_level_generated.rs index a47458489..6fb5ce2c6 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/log_level_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/log_level_generated.rs @@ -86,7 +86,7 @@ impl<'a> flatbuffers::Follow<'a> for LogLevel { type Inner = Self; #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - let b = flatbuffers::read_scalar_at::(buf, loc); + let b = unsafe { flatbuffers::read_scalar_at::(buf, loc) }; Self(b) } } @@ -95,7 +95,9 @@ impl flatbuffers::Push for LogLevel { type Output = LogLevel; #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - flatbuffers::emplace_scalar::(dst, self.0); + unsafe { + flatbuffers::emplace_scalar::(dst, self.0); + } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/parameter_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/parameter_generated.rs index 41e80c4ac..b0e803ec5 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/parameter_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/parameter_generated.rs @@ -22,7 +22,7 @@ impl<'a> flatbuffers::Follow<'a> for Parameter<'a> { #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { - _tab: flatbuffers::Table::new(buf, loc), + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/parameter_type_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/parameter_type_generated.rs index 5ef4b56e1..cf46560b1 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/parameter_type_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/parameter_type_generated.rs @@ -94,7 +94,7 @@ impl<'a> flatbuffers::Follow<'a> for ParameterType { type Inner = Self; #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - let b = flatbuffers::read_scalar_at::(buf, loc); + let b = unsafe { flatbuffers::read_scalar_at::(buf, loc) }; Self(b) } } @@ -103,7 +103,9 @@ impl flatbuffers::Push for ParameterType { type Output = ParameterType; #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - flatbuffers::emplace_scalar::(dst, self.0); + unsafe { + flatbuffers::emplace_scalar::(dst, self.0); + } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/parameter_value_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/parameter_value_generated.rs index 91d51b456..8113df5fc 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/parameter_value_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/parameter_value_generated.rs @@ -98,7 +98,7 @@ impl<'a> flatbuffers::Follow<'a> for ParameterValue { type Inner = Self; #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - let b = flatbuffers::read_scalar_at::(buf, loc); + let b = unsafe { flatbuffers::read_scalar_at::(buf, loc) }; Self(b) } } @@ -107,7 +107,9 @@ impl flatbuffers::Push for ParameterValue { type Output = ParameterValue; #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - flatbuffers::emplace_scalar::(dst, self.0); + unsafe { + flatbuffers::emplace_scalar::(dst, self.0); + } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/return_type_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/return_type_generated.rs index 0610cdd55..913b1fe78 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/return_type_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/return_type_generated.rs @@ -98,7 +98,7 @@ impl<'a> flatbuffers::Follow<'a> for ReturnType { type Inner = Self; #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - let b = flatbuffers::read_scalar_at::(buf, loc); + let b = unsafe { flatbuffers::read_scalar_at::(buf, loc) }; Self(b) } } @@ -107,7 +107,9 @@ impl flatbuffers::Push for ReturnType { type Output = ReturnType; #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - flatbuffers::emplace_scalar::(dst, self.0); + unsafe { + flatbuffers::emplace_scalar::(dst, self.0); + } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/return_value_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/return_value_generated.rs index 2c9f94872..d13c73623 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/return_value_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/return_value_generated.rs @@ -102,7 +102,7 @@ impl<'a> flatbuffers::Follow<'a> for ReturnValue { type Inner = Self; #[inline] unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - let b = flatbuffers::read_scalar_at::(buf, loc); + let b = unsafe { flatbuffers::read_scalar_at::(buf, loc) }; Self(b) } } @@ -111,7 +111,9 @@ impl flatbuffers::Push for ReturnValue { type Output = ReturnValue; #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - flatbuffers::emplace_scalar::(dst, self.0); + unsafe { + flatbuffers::emplace_scalar::(dst, self.0); + } } } From cac246697fe266ec620dc38e48abd8caffc0ca85 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 11 Sep 2025 16:26:09 +0100 Subject: [PATCH 175/271] Changes for new lints/issues in Rust v1.89 Signed-off-by: Simon Davies --- src/hyperlight_common/src/clippy.toml | 2 -- src/hyperlight_common/src/flatbuffers/mod.rs | 1 + src/hyperlight_component_util/src/emit.rs | 2 +- src/hyperlight_guest_tracing_macro/src/lib.rs | 8 +++---- src/hyperlight_host/clippy.toml | 2 -- .../src/hypervisor/gdb/x86_64_target.rs | 12 +++++------ .../src/hypervisor/hyperv_linux.rs | 2 +- src/hyperlight_host/src/hypervisor/kvm.rs | 2 +- src/hyperlight_host/src/hypervisor/mod.rs | 21 +++++++++---------- src/hyperlight_host/src/mem/mgr.rs | 9 ++++---- .../src/sandbox/initialized_multi_use.rs | 10 ++++----- .../src/sandbox/uninitialized.rs | 15 +++++++------ src/hyperlight_host/src/seccomp/guest.rs | 9 ++++---- 13 files changed, 46 insertions(+), 49 deletions(-) diff --git a/src/hyperlight_common/src/clippy.toml b/src/hyperlight_common/src/clippy.toml index cda217749..05fdbf5a2 100644 --- a/src/hyperlight_common/src/clippy.toml +++ b/src/hyperlight_common/src/clippy.toml @@ -2,6 +2,4 @@ disallowed-macros = [ { path = "std::assert", reason = "no asserts in release builds" }, { path = "std::assert_eq", reason = "no asserts in release builds" }, { path = "std::assert_ne", reason = "no asserts in release builds" }, - { path = "std::assert_true", reason = "no asserts in release builds" }, - { path = "std::assert_false", reason = "no asserts in release builds" }, ] diff --git a/src/hyperlight_common/src/flatbuffers/mod.rs b/src/hyperlight_common/src/flatbuffers/mod.rs index f8ac0929d..d0a859cd8 100644 --- a/src/hyperlight_common/src/flatbuffers/mod.rs +++ b/src/hyperlight_common/src/flatbuffers/mod.rs @@ -2,6 +2,7 @@ // @generated pub mod hyperlight { use super::*; + #[allow(mismatched_lifetime_syntaxes)] pub mod generated { use super::*; mod parameter_value_generated; diff --git a/src/hyperlight_component_util/src/emit.rs b/src/hyperlight_component_util/src/emit.rs index 2cd14c9df..1b3545813 100644 --- a/src/hyperlight_component_util/src/emit.rs +++ b/src/hyperlight_component_util/src/emit.rs @@ -680,7 +680,7 @@ impl<'a> WitName<'a> { } } /// Parse a kebab-name as a WIT name -pub fn split_wit_name(n: &str) -> WitName { +pub fn split_wit_name(n: &str) -> WitName<'_> { let mut namespaces = Vec::new(); let mut colon_components = n.split(':').rev(); let last = colon_components.next().unwrap(); diff --git a/src/hyperlight_guest_tracing_macro/src/lib.rs b/src/hyperlight_guest_tracing_macro/src/lib.rs index 22a5cdf0e..cba0bcff3 100644 --- a/src/hyperlight_guest_tracing_macro/src/lib.rs +++ b/src/hyperlight_guest_tracing_macro/src/lib.rs @@ -113,10 +113,10 @@ impl syn::parse::Parse for TraceMacroInput { if !matches!(message, syn::Lit::Str(_)) { return Err(input.error("first argument to trace! must be a string literal")); } - if let syn::Lit::Str(ref lit_str) = message { - if lit_str.value().is_empty() { - return Err(input.error("trace message must not be empty")); - } + if let syn::Lit::Str(ref lit_str) = message + && lit_str.value().is_empty() + { + return Err(input.error("trace message must not be empty")); } let statement = if input.peek(syn::Token![,]) { diff --git a/src/hyperlight_host/clippy.toml b/src/hyperlight_host/clippy.toml index cda217749..05fdbf5a2 100644 --- a/src/hyperlight_host/clippy.toml +++ b/src/hyperlight_host/clippy.toml @@ -2,6 +2,4 @@ disallowed-macros = [ { path = "std::assert", reason = "no asserts in release builds" }, { path = "std::assert_eq", reason = "no asserts in release builds" }, { path = "std::assert_ne", reason = "no asserts in release builds" }, - { path = "std::assert_true", reason = "no asserts in release builds" }, - { path = "std::assert_false", reason = "no asserts in release builds" }, ] diff --git a/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs b/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs index 3248e6082..a3e36ebb7 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs @@ -133,18 +133,18 @@ impl Target for HyperlightSandboxTarget { type Arch = GdbTargetArch; type Error = GdbTargetError; - fn support_breakpoints(&mut self) -> Option> { + fn support_breakpoints(&mut self) -> Option> { Some(self) } #[inline(always)] - fn base_ops(&mut self) -> BaseOps { + fn base_ops(&mut self) -> BaseOps<'_, Self::Arch, Self::Error> { BaseOps::SingleThread(self) } fn support_section_offsets( &mut self, - ) -> Option> { + ) -> Option> { Some(self) } } @@ -288,7 +288,7 @@ impl SingleThreadBase for HyperlightSandboxTarget { } } - fn support_resume(&mut self) -> Option> { + fn support_resume(&mut self) -> Option> { Some(self) } } @@ -315,7 +315,7 @@ impl SectionOffsets for HyperlightSandboxTarget { } impl Breakpoints for HyperlightSandboxTarget { - fn support_hw_breakpoint(&mut self) -> Option> { + fn support_hw_breakpoint(&mut self) -> Option> { Some(self) } fn support_sw_breakpoint(&mut self) -> Option> { @@ -438,7 +438,7 @@ impl SingleThreadResume for HyperlightSandboxTarget { log::debug!("Resume"); self.resume_vcpu() } - fn support_single_step(&mut self) -> Option> { + fn support_single_step(&mut self) -> Option> { Some(self) } } diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index a5a32f456..aaef9316d 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -960,7 +960,7 @@ impl Hypervisor for HypervLinuxDriver { } #[cfg(crashdump)] - fn crashdump_context(&self) -> Result> { + fn crashdump_context(&self) -> Result>> { if self.rt_cfg.guest_core_dump { let mut regs = [0; 27]; diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index d048e20f3..a69b51f55 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -831,7 +831,7 @@ impl Hypervisor for KVMDriver { } #[cfg(crashdump)] - fn crashdump_context(&self) -> Result> { + fn crashdump_context(&self) -> Result>> { if self.rt_cfg.guest_core_dump { let mut regs = [0; 27]; diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index 928d9ac2e..9c04ad3a0 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -230,7 +230,7 @@ pub(crate) trait Hypervisor: Debug + Send { fn as_mut_hypervisor(&mut self) -> &mut dyn Hypervisor; #[cfg(crashdump)] - fn crashdump_context(&self) -> Result>; + fn crashdump_context(&self) -> Result>>; #[cfg(gdb)] /// handles the cases when the vCPU stops due to a Debug event @@ -267,16 +267,15 @@ pub(crate) fn get_memory_access_violation<'a>( // find the region containing the given gpa let region = mem_regions.find(|region| region.guest_region.contains(&gpa)); - if let Some(region) = region { - if !region.flags.contains(access_info) - || region.flags.contains(MemoryRegionFlags::STACK_GUARD) - { - return Some(HyperlightExit::AccessViolation( - gpa as u64, - access_info, - region.flags, - )); - } + if let Some(region) = region + && (!region.flags.contains(access_info) + || region.flags.contains(MemoryRegionFlags::STACK_GUARD)) + { + return Some(HyperlightExit::AccessViolation( + gpa as u64, + access_info, + region.flags, + )); } None } diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index f578f3ea8..7d9d0d288 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -242,10 +242,11 @@ where let addr = (p << 21) + (i << 12); // First check if we're still in the cached region - if let Some(cached_idx) = *cached_region_idx { - if cached_idx < regions.len() && regions[cached_idx].guest_region.contains(&addr) { - return Ok(regions[cached_idx].region_type); - } + if let Some(cached_idx) = *cached_region_idx + && cached_idx < regions.len() + && regions[cached_idx].guest_region.contains(&addr) + { + return Ok(regions[cached_idx].region_type); } // If not in cached region, try adjacent regions first (common for sequential access) diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 9223c5e1b..fc860caf6 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -165,11 +165,11 @@ impl MultiUseSandbox { /// ``` #[instrument(err(Debug), skip_all, parent = Span::current())] pub fn restore(&mut self, snapshot: &Snapshot) -> Result<()> { - if let Some(snap) = &self.snapshot { - if Arc::ptr_eq(&snap.inner, &snapshot.inner) { - // If the snapshot is already the current one, no need to restore - return Ok(()); - } + if let Some(snap) = &self.snapshot + && Arc::ptr_eq(&snap.inner, &snapshot.inner) + { + // If the snapshot is already the current one, no need to restore + return Ok(()); } if self.id != snapshot.inner.sandbox_id() { diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index 679d5e0e5..f952c6bd7 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -946,14 +946,13 @@ mod tests { (metadata_values_map, "module_path"), (metadata_values_map, "target"), ]); - if let Ok(err_vals) = err_vals_res { - if err_vals[0] == "ERROR" - && err_vals[1].starts_with(expected_error_start) - && err_vals[2] == "hyperlight_host::sandbox::uninitialized" - && err_vals[3] == "hyperlight_host::sandbox::uninitialized" - { - count_matching_events += 1; - } + if let Ok(err_vals) = err_vals_res + && err_vals[0] == "ERROR" + && err_vals[1].starts_with(expected_error_start) + && err_vals[2] == "hyperlight_host::sandbox::uninitialized" + && err_vals[3] == "hyperlight_host::sandbox::uninitialized" + { + count_matching_events += 1; } } assert!( diff --git a/src/hyperlight_host/src/seccomp/guest.rs b/src/hyperlight_host/src/seccomp/guest.rs index b08f483f6..c55d40686 100644 --- a/src/hyperlight_host/src/seccomp/guest.rs +++ b/src/hyperlight_host/src/seccomp/guest.rs @@ -121,11 +121,12 @@ pub(crate) fn get_seccomp_filter_for_host_function_worker_thread( .try_into()?; // If `openat` is an explicitly allowed syscall, we shouldn't return the filter that forces it to return EACCES. - if let Some(extra_syscalls) = extra_allowed_syscalls { - if extra_syscalls.contains(&libc::SYS_openat) { - return Ok(vec![allowlist]); - } + if let Some(extra_syscalls) = extra_allowed_syscalls + && extra_syscalls.contains(&libc::SYS_openat) + { + return Ok(vec![allowlist]); } + // Otherwise, we return both filters. // Filter that forces `openat` to return EACCES From 048179a6e32e02fae500cdc1b92c8c6dba9e14d2 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 11 Sep 2025 19:26:35 +0100 Subject: [PATCH 176/271] Fix windows lint errors Signed-off-by: Simon Davies --- src/hyperlight_host/src/hypervisor/hyperv_windows.rs | 2 +- .../src/hypervisor/surrogate_process_manager.rs | 6 +++--- .../src/hypervisor/windows_hypervisor_platform.rs | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index 0f98613b3..620910004 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -894,7 +894,7 @@ impl Hypervisor for HypervWindowsDriver { } #[cfg(crashdump)] - fn crashdump_context(&self) -> Result> { + fn crashdump_context(&self) -> Result>> { if self.rt_cfg.guest_core_dump { let mut regs = [0; 27]; diff --git a/src/hyperlight_host/src/hypervisor/surrogate_process_manager.rs b/src/hyperlight_host/src/hypervisor/surrogate_process_manager.rs index 6724f2c6d..f805e94ad 100644 --- a/src/hyperlight_host/src/hypervisor/surrogate_process_manager.rs +++ b/src/hyperlight_host/src/hypervisor/surrogate_process_manager.rs @@ -531,11 +531,11 @@ mod tests { while result { if let Ok(process_name) = unsafe { CStr::from_ptr(process_entry.szExeFile.as_ptr()).to_str() } + && process_name == SURROGATE_PROCESS_BINARY_NAME { - if process_name == SURROGATE_PROCESS_BINARY_NAME { - count += 1; - } + count += 1; } + unsafe { result = Process32Next(snapshot_handle, &mut process_entry).is_ok(); } diff --git a/src/hyperlight_host/src/hypervisor/windows_hypervisor_platform.rs b/src/hyperlight_host/src/hypervisor/windows_hypervisor_platform.rs index d6064443b..3d97de9ea 100644 --- a/src/hyperlight_host/src/hypervisor/windows_hypervisor_platform.rs +++ b/src/hyperlight_host/src/hypervisor/windows_hypervisor_platform.rs @@ -213,7 +213,7 @@ impl VMPartition { // with an error about a missing entrypoint // This function should always succeed since before we get here we have already checked that the hypervisor is present and // that we are on a supported version of windows. -type WHvMapGpaRange2Func = unsafe extern "cdecl" fn( +type WHvMapGpaRange2Func = unsafe extern "system" fn( WHV_PARTITION_HANDLE, HANDLE, *const c_void, @@ -523,10 +523,10 @@ impl VMProcessor { ); // If it failed for reasons other than insufficient buffer, return error - if let Err(e) = result { - if e.code() != windows::Win32::Foundation::WHV_E_INSUFFICIENT_BUFFER { - return Err(HyperlightError::WindowsAPIError(e)); - } + if let Err(e) = result + && e.code() != windows::Win32::Foundation::WHV_E_INSUFFICIENT_BUFFER + { + return Err(HyperlightError::WindowsAPIError(e)); } } From 9cb2fa4cfbb7a9561363d7b16d4897276cd2f958 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 11 Sep 2025 22:27:47 +0100 Subject: [PATCH 177/271] Ignore trace dir Signed-off-by: Simon Davies --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index dec76e560..2abe2940f 100644 --- a/.gitignore +++ b/.gitignore @@ -471,3 +471,4 @@ hyperlight_guest.h # gdb .gdbinit +trace/* From 6a68f85e7e7304dac61458ad4ab50ee37185e1e4 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Mon, 15 Sep 2025 10:55:35 +0100 Subject: [PATCH 178/271] Update Justfile to check msrv on additional crates Signed-off-by: Simon Davies --- Justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Justfile b/Justfile index c0cedc8ea..9d7b62dfe 100644 --- a/Justfile +++ b/Justfile @@ -104,7 +104,7 @@ like-ci config=default-target hypervisor="kvm": {{ if os() == "linux" { "just clippy-exhaustive " + config } else { "" } }} @# Verify MSRV - ./dev/verify-msrv.sh hyperlight-host hyperlight-guest hyperlight-guest-bin hyperlight-common + ./dev/verify-msrv.sh hyperlight-common hyperlight-guest hyperlight-guest-bin hyperlight-host hyperlight-component-util hyperlight-component-macro hyperlight-guest-tracing-macro hyperlight-guest-tracing @# Build and move Rust guests just build-rust-guests {{config}} From f3f610bb89a396366288f399be85d5974bdaaf88 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 04:05:06 +0000 Subject: [PATCH 179/271] Bump serde from 1.0.223 to 1.0.224 (#892) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.223 to 1.0.224. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.223...v1.0.224) --- updated-dependencies: - dependency-name: serde dependency-version: 1.0.224 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea5317085..79af978ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3052,9 +3052,9 @@ checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.223" +version = "1.0.224" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a505d71960adde88e293da5cb5eda57093379f64e61cf77bf0e6a63af07a7bac" +checksum = "6aaeb1e94f53b16384af593c71e20b095e958dab1d26939c1b70645c5cfbcc0b" dependencies = [ "serde_core", "serde_derive", @@ -3062,18 +3062,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.223" +version = "1.0.224" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20f57cbd357666aa7b3ac84a90b4ea328f1d4ddb6772b430caa5d9e1309bb9e9" +checksum = "32f39390fa6346e24defbcdd3d9544ba8a19985d0af74df8501fbfe9a64341ab" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.223" +version = "1.0.224" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d428d07faf17e306e699ec1e91996e5a165ba5d6bce5b5155173e91a8a01a56" +checksum = "87ff78ab5e8561c9a675bfc1785cb07ae721f0ee53329a595cefd8c04c2ac4e0" dependencies = [ "proc-macro2", "quote", From f4fbb2653cbcb680c7b66cca5ce322c7cafd2f6e Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Tue, 16 Sep 2025 15:41:08 -0700 Subject: [PATCH 180/271] Add benchmark for measuring time to interrupt a sandbox (#893) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- src/hyperlight_host/benches/benchmarks.rs | 54 ++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/hyperlight_host/benches/benchmarks.rs b/src/hyperlight_host/benches/benchmarks.rs index 61d405370..df9808494 100644 --- a/src/hyperlight_host/benches/benchmarks.rs +++ b/src/hyperlight_host/benches/benchmarks.rs @@ -14,6 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ +#![expect( + clippy::disallowed_macros, + reason = "This is a benchmark file, so using disallowed macros is fine here." +)] + use std::sync::Mutex; use criterion::{Criterion, criterion_group, criterion_main}; @@ -117,6 +122,54 @@ fn guest_call_benchmark(c: &mut Criterion) { }); }); + // Measure the time between calling interrupt_handle.kill() and the guest function returning. + group.bench_function("guest_call_time_to_interrupt", |b| { + use std::sync::{Arc, Barrier}; + use std::thread; + use std::time::Instant; + + b.iter_custom(|iters| { + let mut total_interrupt_latency = std::time::Duration::ZERO; + + for _ in 0..iters { + let mut sbox = create_multiuse_sandbox(); + let interrupt_handle = sbox.interrupt_handle(); + + let start_barrier = Arc::new(Barrier::new(2)); + let start_barrier_clone = Arc::clone(&start_barrier); + + let observer_thread = thread::spawn(move || { + start_barrier_clone.wait(); + + // Small delay to ensure the guest function is running in VM before interrupting + thread::sleep(std::time::Duration::from_millis(1)); + let kill_start = Instant::now(); + interrupt_handle.kill(); + kill_start + }); + + start_barrier.wait(); + + let result = sbox.call::("Spin", ()); + + let call_end = Instant::now(); + let kill_start = observer_thread.join().unwrap(); + + assert!( + matches!( + result, + Err(hyperlight_host::HyperlightError::ExecutionCanceledByHost()) + ), + "Guest function should be interrupted" + ); + + total_interrupt_latency += call_end.duration_since(kill_start); + } + + total_interrupt_latency + }); + }); + group.finish(); } @@ -228,7 +281,6 @@ fn function_call_serialization_benchmark(c: &mut Criterion) { group.finish(); } -#[allow(clippy::disallowed_macros)] fn sample_workloads_benchmark(c: &mut Criterion) { let mut group = c.benchmark_group("sample_workloads"); From 0b10a393d8586f95a2f6e7887b39b83e60b84858 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 04:05:16 +0000 Subject: [PATCH 181/271] Bump serde from 1.0.224 to 1.0.225 (#894) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.224 to 1.0.225. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.224...v1.0.225) --- updated-dependencies: - dependency-name: serde dependency-version: 1.0.225 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 79af978ba..df1a46e09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3052,9 +3052,9 @@ checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.224" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aaeb1e94f53b16384af593c71e20b095e958dab1d26939c1b70645c5cfbcc0b" +checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" dependencies = [ "serde_core", "serde_derive", @@ -3062,18 +3062,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.224" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f39390fa6346e24defbcdd3d9544ba8a19985d0af74df8501fbfe9a64341ab" +checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.224" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ff78ab5e8561c9a675bfc1785cb07ae721f0ee53329a595cefd8c04c2ac4e0" +checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" dependencies = [ "proc-macro2", "quote", From 692fd9e1fa4cb45b3179a5c7501499dbd93fdb60 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 04:05:36 +0000 Subject: [PATCH 182/271] Bump anyhow from 1.0.99 to 1.0.100 (#899) Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.99 to 1.0.100. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.99...1.0.100) --- updated-dependencies: - dependency-name: anyhow dependency-version: 1.0.100 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_common/Cargo.toml | 2 +- src/hyperlight_guest/Cargo.toml | 2 +- src/hyperlight_host/Cargo.toml | 2 +- src/hyperlight_testing/Cargo.toml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df1a46e09..8842588d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,9 +121,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arbitrary" diff --git a/src/hyperlight_common/Cargo.toml b/src/hyperlight_common/Cargo.toml index 06f6b8472..da6e90aaa 100644 --- a/src/hyperlight_common/Cargo.toml +++ b/src/hyperlight_common/Cargo.toml @@ -16,7 +16,7 @@ workspace = true [dependencies] flatbuffers = { version = "25.2.10", default-features = false } -anyhow = { version = "1.0.99", default-features = false } +anyhow = { version = "1.0.100", default-features = false } log = "0.4.28" tracing = { version = "0.1.41", optional = true } arbitrary = {version = "1.4.2", optional = true, features = ["derive"]} diff --git a/src/hyperlight_guest/Cargo.toml b/src/hyperlight_guest/Cargo.toml index ecc516241..31d872092 100644 --- a/src/hyperlight_guest/Cargo.toml +++ b/src/hyperlight_guest/Cargo.toml @@ -12,7 +12,7 @@ Provides only the essential building blocks for interacting with the host enviro """ [dependencies] -anyhow = { version = "1.0.99", default-features = false } +anyhow = { version = "1.0.100", default-features = false } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } hyperlight-common = { workspace = true } hyperlight-guest-tracing = { workspace = true, default-features = false } diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index a28e09cd2..6c0a3b51e 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -118,7 +118,7 @@ windows = { version = "0.62", features = [ proc-maps = "0.4.0" [build-dependencies] -anyhow = { version = "1.0.99" } +anyhow = { version = "1.0.100" } cfg_aliases = "0.2.1" built = { version = "0.8.0", optional = true, features = ["chrono", "git2"] } diff --git a/src/hyperlight_testing/Cargo.toml b/src/hyperlight_testing/Cargo.toml index 975397c47..b88f97895 100644 --- a/src/hyperlight_testing/Cargo.toml +++ b/src/hyperlight_testing/Cargo.toml @@ -3,7 +3,7 @@ name = "hyperlight-testing" edition = "2021" [dependencies] -anyhow = "1.0.99" +anyhow = "1.0.100" log = "0.4" once_cell = "1.21" tracing = { version = "0.1.41", features = ["log"] } From 9507774fa1794e5c7e80cd5d9598edb45cba4b37 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 04:05:42 +0000 Subject: [PATCH 183/271] Bump cc from 1.2.37 to 1.2.38 (#898) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.37 to 1.2.38. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.37...cc-v1.2.38) --- updated-dependencies: - dependency-name: cc dependency-version: 1.2.38 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8842588d9..d3eb348ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,9 +362,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.37" +version = "1.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44" +checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" dependencies = [ "find-msvc-tools", "jobserver", @@ -835,9 +835,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" [[package]] name = "flatbuffers" From daff1844fbf8fa95bbc710f7d08d4b8e0d353e7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 04:05:45 +0000 Subject: [PATCH 184/271] Bump serde from 1.0.225 to 1.0.226 (#897) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.225 to 1.0.226. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.225...v1.0.226) --- updated-dependencies: - dependency-name: serde dependency-version: 1.0.226 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3eb348ea..253a1aae5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3052,9 +3052,9 @@ checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.225" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" dependencies = [ "serde_core", "serde_derive", @@ -3062,18 +3062,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.225" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.225" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" +checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" dependencies = [ "proc-macro2", "quote", From 35bc5406dad0e54b0e8e13f44743f5548d0fef06 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 04:06:00 +0000 Subject: [PATCH 185/271] Bump proptest from 1.7.0 to 1.8.0 (#896) Bumps [proptest](https://github.com/proptest-rs/proptest) from 1.7.0 to 1.8.0. - [Release notes](https://github.com/proptest-rs/proptest/releases) - [Changelog](https://github.com/proptest-rs/proptest/blob/main/CHANGELOG.md) - [Commits](https://github.com/proptest-rs/proptest/compare/v1.7.0...v1.8.0) --- updated-dependencies: - dependency-name: proptest dependency-version: 1.8.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 253a1aae5..2aad7fd30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2645,9 +2645,9 @@ dependencies = [ [[package]] name = "proptest" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" +checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" dependencies = [ "bit-set", "bit-vec", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 6c0a3b51e..ab5c91388 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -86,7 +86,7 @@ uuid = { version = "1.18.1", features = ["v4"] } signal-hook-registry = "1.4.6" envy = { version = "0.4.2" } serde = "1.0" -proptest = "1.7.0" +proptest = "1.8.0" tempfile = "3.22.0" crossbeam-queue = "0.3.12" tracing-serde = "0.2.0" From 0172df1c0730631373e9865547e02e092815e302 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 04:05:10 +0000 Subject: [PATCH 186/271] Bump libc from 0.2.175 to 0.2.176 (#910) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.175 to 0.2.176. - [Release notes](https://github.com/rust-lang/libc/releases) - [Changelog](https://github.com/rust-lang/libc/blob/0.2.176/CHANGELOG.md) - [Commits](https://github.com/rust-lang/libc/compare/0.2.175...0.2.176) --- updated-dependencies: - dependency-name: libc dependency-version: 0.2.176 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2aad7fd30..858363f4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1802,9 +1802,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.175" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "libfuzzer-sys" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index ab5c91388..ce18b7555 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -26,7 +26,7 @@ gdbstub_arch = { version = "0.3.2", optional = true } goblin = { version = "0.10", default-features = false, features = ["std", "elf32", "elf64", "endian_fd"] } rand = { version = "0.9" } cfg-if = { version = "1.0.3" } -libc = { version = "0.2.175" } +libc = { version = "0.2.176" } flatbuffers = "25.2.10" framehop = { version = "0.15.0", optional = true } fallible-iterator = { version = "0.3.0", optional = true } From c6373ced4351cbf1c7c16b61c689bdc957b6a449 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 04:05:16 +0000 Subject: [PATCH 187/271] Bump tempfile from 3.22.0 to 3.23.0 (#909) Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.22.0 to 3.23.0. - [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md) - [Commits](https://github.com/Stebalien/tempfile/compare/v3.22.0...v3.23.0) --- updated-dependencies: - dependency-name: tempfile dependency-version: 3.23.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 858363f4c..82ade2096 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3287,9 +3287,9 @@ checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" [[package]] name = "tempfile" -version = "3.22.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", "getrandom 0.3.3", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index ce18b7555..2f83a4a06 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -87,7 +87,7 @@ signal-hook-registry = "1.4.6" envy = { version = "0.4.2" } serde = "1.0" proptest = "1.8.0" -tempfile = "3.22.0" +tempfile = "3.23.0" crossbeam-queue = "0.3.12" tracing-serde = "0.2.0" hyperlight-testing = { workspace = true } From 7b1452b34f1122c072d1cf1beb741178fd296334 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 04:05:18 +0000 Subject: [PATCH 188/271] Bump windows from 0.62.0 to 0.62.1 (#916) Bumps [windows](https://github.com/microsoft/windows-rs) from 0.62.0 to 0.62.1. - [Release notes](https://github.com/microsoft/windows-rs/releases) - [Commits](https://github.com/microsoft/windows-rs/commits) --- updated-dependencies: - dependency-name: windows dependency-version: 0.62.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 82ade2096..b6cd515eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1487,7 +1487,7 @@ dependencies = [ "tracing-tracy", "uuid", "vmm-sys-util", - "windows 0.62.0", + "windows 0.62.1", "windows-result 0.4.0", "windows-sys 0.61.0", "windows-version", @@ -4044,14 +4044,13 @@ dependencies = [ [[package]] name = "windows" -version = "0.62.0" +version = "0.62.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9579d0e6970fd5250aa29aba5994052385ff55cf7b28a059e484bb79ea842e42" +checksum = "49e6c4a1f363c8210c6f77ba24f645c61c6fb941eccf013da691f7e09515b8ac" dependencies = [ - "windows-collections 0.3.0", - "windows-core 0.62.0", - "windows-future 0.3.0", - "windows-link 0.2.0", + "windows-collections 0.3.1", + "windows-core 0.62.1", + "windows-future 0.3.1", "windows-numerics 0.3.0", ] @@ -4066,11 +4065,11 @@ dependencies = [ [[package]] name = "windows-collections" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90dd7a7b86859ec4cdf864658b311545ef19dbcf17a672b52ab7cefe80c336f" +checksum = "123e712f464a8a60ce1a13f4c446d2d43ab06464cb5842ff68f5c71b6fb7852e" dependencies = [ - "windows-core 0.62.0", + "windows-core 0.62.1", ] [[package]] @@ -4088,9 +4087,9 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.62.0" +version = "0.62.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" +checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" dependencies = [ "windows-implement", "windows-interface", @@ -4112,20 +4111,20 @@ dependencies = [ [[package]] name = "windows-future" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2194dee901458cb79e1148a4e9aac2b164cc95fa431891e7b296ff0b2f1d8a6" +checksum = "68f3db6b24b120200d649cd4811b4947188ed3a8d2626f7075146c5d178a9a4a" dependencies = [ - "windows-core 0.62.0", + "windows-core 0.62.1", "windows-link 0.2.0", "windows-threading 0.2.0", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" dependencies = [ "proc-macro2", "quote", @@ -4134,9 +4133,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" dependencies = [ "proc-macro2", "quote", @@ -4171,7 +4170,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ce3498fe0aba81e62e477408383196b4b0363db5e0c27646f932676283b43d8" dependencies = [ - "windows-core 0.62.0", + "windows-core 0.62.1", "windows-link 0.2.0", ] From 496e1a88d81998e46d60869adb46dd440d213fe6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 04:05:26 +0000 Subject: [PATCH 189/271] Bump windows-sys from 0.61.0 to 0.61.1 (#914) Bumps [windows-sys](https://github.com/microsoft/windows-rs) from 0.61.0 to 0.61.1. - [Release notes](https://github.com/microsoft/windows-rs/releases) - [Commits](https://github.com/microsoft/windows-rs/commits) --- updated-dependencies: - dependency-name: windows-sys dependency-version: 0.61.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6cd515eb..e20737294 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -703,7 +703,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.0", + "windows-sys 0.60.2", ] [[package]] @@ -1489,7 +1489,7 @@ dependencies = [ "vmm-sys-util", "windows 0.62.1", "windows-result 0.4.0", - "windows-sys 0.61.0", + "windows-sys 0.61.1", "windows-version", ] @@ -3295,7 +3295,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.61.0", + "windows-sys 0.60.2", ] [[package]] @@ -4239,9 +4239,9 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" dependencies = [ "windows-link 0.2.0", ] From 80584a85b44a201ae2c3dae670f2a8bdbcc277f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 04:05:44 +0000 Subject: [PATCH 190/271] Bump flatbuffers from 25.2.10 to 25.9.23 (#911) Bumps [flatbuffers](https://github.com/google/flatbuffers) from 25.2.10 to 25.9.23. - [Release notes](https://github.com/google/flatbuffers/releases) - [Changelog](https://github.com/google/flatbuffers/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/flatbuffers/compare/v25.2.10...v25.9.23) --- updated-dependencies: - dependency-name: flatbuffers dependency-version: 25.9.23 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_common/Cargo.toml | 2 +- src/hyperlight_guest/Cargo.toml | 2 +- src/hyperlight_host/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e20737294..1c79575a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -841,9 +841,9 @@ checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" [[package]] name = "flatbuffers" -version = "25.2.10" +version = "25.9.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1045398c1bfd89168b5fd3f1fc11f6e70b34f6f66300c87d44d3de849463abf1" +checksum = "09b6620799e7340ebd9968d2e0708eb82cf1971e9a16821e2091b6d6e475eed5" dependencies = [ "bitflags 2.9.4", "rustc_version", diff --git a/src/hyperlight_common/Cargo.toml b/src/hyperlight_common/Cargo.toml index da6e90aaa..93854f5d9 100644 --- a/src/hyperlight_common/Cargo.toml +++ b/src/hyperlight_common/Cargo.toml @@ -15,7 +15,7 @@ Hyperlight's components common to host and guest. workspace = true [dependencies] -flatbuffers = { version = "25.2.10", default-features = false } +flatbuffers = { version = "25.9.23", default-features = false } anyhow = { version = "1.0.100", default-features = false } log = "0.4.28" tracing = { version = "0.1.41", optional = true } diff --git a/src/hyperlight_guest/Cargo.toml b/src/hyperlight_guest/Cargo.toml index 31d872092..e15b1e996 100644 --- a/src/hyperlight_guest/Cargo.toml +++ b/src/hyperlight_guest/Cargo.toml @@ -16,7 +16,7 @@ anyhow = { version = "1.0.100", default-features = false } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } hyperlight-common = { workspace = true } hyperlight-guest-tracing = { workspace = true, default-features = false } -flatbuffers = { version= "25.2.10", default-features = false } +flatbuffers = { version= "25.9.23", default-features = false } [features] default = [] diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 2f83a4a06..6d6d529c2 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -27,7 +27,7 @@ goblin = { version = "0.10", default-features = false, features = ["std", "elf32 rand = { version = "0.9" } cfg-if = { version = "1.0.3" } libc = { version = "0.2.176" } -flatbuffers = "25.2.10" +flatbuffers = "25.9.23" framehop = { version = "0.15.0", optional = true } fallible-iterator = { version = "0.3.0", optional = true } blake3 = "1.8.2" From a68d2fb9d3fbe02bbfc33df18179e9c1d06f09d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 04:10:31 +0000 Subject: [PATCH 191/271] Bump opentelemetry-semantic-conventions from 0.30.0 to 0.31.0 (#915) Bumps [opentelemetry-semantic-conventions](https://github.com/open-telemetry/opentelemetry-rust) from 0.30.0 to 0.31.0. - [Release notes](https://github.com/open-telemetry/opentelemetry-rust/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-rust/blob/main/docs/release_0.30.md) - [Commits](https://github.com/open-telemetry/opentelemetry-rust/commits) --- updated-dependencies: - dependency-name: opentelemetry-semantic-conventions dependency-version: 0.31.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1c79575a9..bb1030f89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2251,9 +2251,9 @@ dependencies = [ [[package]] name = "opentelemetry-semantic-conventions" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d059a296a47436748557a353c5e6c5705b9470ef6c95cfc52c21a8814ddac2" +checksum = "e62e29dfe041afb8ed2a6c9737ab57db4907285d999ef8ad3a59092a36bdc846" [[package]] name = "opentelemetry_sdk" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 6d6d529c2..600108fe9 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -98,7 +98,7 @@ tracing-subscriber = {version = "0.3.20", features = ["std", "env-filter"]} tracing-opentelemetry = "0.31.0" opentelemetry = "0.30.0" opentelemetry-otlp = { version = "0.30.0", default-features = false, features = ["http-proto", "reqwest-blocking-client"] } -opentelemetry-semantic-conventions = "0.30" +opentelemetry-semantic-conventions = "0.31" opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio"] } tokio = { version = "1.47.1", features = ["full"] } criterion = "0.7.0" From c16f952e962ee14497a1a1d134b2e2d67b44d809 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 09:59:50 -0700 Subject: [PATCH 192/271] Bump crate-ci/typos from 1.36.2 to 1.36.3 (#912) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.36.2 to 1.36.3. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.36.2...v1.36.3) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.36.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ValidatePullRequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index e6b07ddac..0316f4862 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -65,7 +65,7 @@ jobs: steps: - uses: actions/checkout@v5 - name: Spell Check Repo - uses: crate-ci/typos@v1.36.2 + uses: crate-ci/typos@v1.36.3 license-headers: name: check license headers From 0c5488254d0d75f936aceb851d49f6b84231342d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 10:04:20 -0700 Subject: [PATCH 193/271] Bump windows-version from 0.1.5 to 0.1.6 (#918) Bumps [windows-version](https://github.com/microsoft/windows-rs) from 0.1.5 to 0.1.6. - [Release notes](https://github.com/microsoft/windows-rs/releases) - [Commits](https://github.com/microsoft/windows-rs/commits) --- updated-dependencies: - dependency-name: windows-version dependency-version: 0.1.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb1030f89..38ae72761 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -703,7 +703,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.60.2", + "windows-sys 0.61.1", ] [[package]] @@ -3295,7 +3295,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.1", ] [[package]] @@ -4299,9 +4299,9 @@ dependencies = [ [[package]] name = "windows-version" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e061eb0a22b4a1d778ad70f7575ec7845490abb35b08fa320df7895882cacb" +checksum = "700dad7c058606087f6fdc1f88da5841e06da40334413c6cd4367b25ef26d24e" dependencies = [ "windows-link 0.2.0", ] From 5cde3c44d077a0cd631ff85a1ba8c978e81161db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 10:04:39 -0700 Subject: [PATCH 194/271] Bump serde from 1.0.226 to 1.0.227 (#917) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.226 to 1.0.227. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.226...v1.0.227) --- updated-dependencies: - dependency-name: serde dependency-version: 1.0.227 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38ae72761..078293bcb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3052,9 +3052,9 @@ checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.226" +version = "1.0.227" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" +checksum = "80ece43fc6fbed4eb5392ab50c07334d3e577cbf40997ee896fe7af40bba4245" dependencies = [ "serde_core", "serde_derive", @@ -3062,18 +3062,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.226" +version = "1.0.227" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +checksum = "7a576275b607a2c86ea29e410193df32bc680303c82f31e275bbfcafe8b33be5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.226" +version = "1.0.227" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" +checksum = "51e694923b8824cf0e9b382adf0f60d4e05f348f357b38833a3fa5ed7c2ede04" dependencies = [ "proc-macro2", "quote", From 7152b04ef511a840e1dc96a5217cbd6ea47948d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 04:11:46 +0000 Subject: [PATCH 195/271] Bump serde from 1.0.227 to 1.0.228 (#920) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.227 to 1.0.228. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.227...v1.0.228) --- updated-dependencies: - dependency-name: serde dependency-version: 1.0.228 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 078293bcb..2d0fd7a5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3052,9 +3052,9 @@ checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.227" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80ece43fc6fbed4eb5392ab50c07334d3e577cbf40997ee896fe7af40bba4245" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -3062,18 +3062,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.227" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a576275b607a2c86ea29e410193df32bc680303c82f31e275bbfcafe8b33be5" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.227" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e694923b8824cf0e9b382adf0f60d4e05f348f357b38833a3fa5ed7c2ede04" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", From 8c9a447f4a3c61bad366c6806b75afc2af64c9f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 04:25:57 +0000 Subject: [PATCH 196/271] Bump cc from 1.2.38 to 1.2.39 (#919) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.38 to 1.2.39. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.38...cc-v1.2.39) --- updated-dependencies: - dependency-name: cc dependency-version: 1.2.39 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d0fd7a5c..e74e9a3ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,9 +362,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.38" +version = "1.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" dependencies = [ "find-msvc-tools", "jobserver", From 4b8cebc92bcdf91893c2781fb4bce58f68a535d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 04:33:03 +0000 Subject: [PATCH 197/271] Bump thiserror from 2.0.16 to 2.0.17 (#922) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 2.0.16 to 2.0.17. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/2.0.16...2.0.17) --- updated-dependencies: - dependency-name: thiserror dependency-version: 2.0.17 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 30 +++++++++++++++--------------- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e74e9a3ca..f635c840a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1474,7 +1474,7 @@ dependencies = [ "signal-hook-registry", "tempfile", "termcolor", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", "tracing-chrome", @@ -1927,7 +1927,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149" dependencies = [ - "thiserror 2.0.16", + "thiserror 2.0.17", "zerocopy 0.8.26", "zerocopy-derive 0.8.26", ] @@ -1989,7 +1989,7 @@ dependencies = [ "metrics", "metrics-util", "quanta", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -2083,7 +2083,7 @@ checksum = "fdbb879d6a9ca5359ae020c17ebf8587e0be309bf32beae636030e4408c2e481" dependencies = [ "libc", "mshv-bindings 0.6.1", - "thiserror 2.0.16", + "thiserror 2.0.17", "vmm-sys-util", ] @@ -2204,7 +2204,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", ] @@ -2234,7 +2234,7 @@ dependencies = [ "opentelemetry_sdk", "prost", "reqwest", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -2268,7 +2268,7 @@ dependencies = [ "percent-encoding", "rand", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", ] @@ -2385,7 +2385,7 @@ checksum = "97f6fccfd2d9d2df765ca23ff85fe5cc437fb0e6d3e164e4d3cbe09d14780c93" dependencies = [ "arrayvec", "bitflags 2.9.4", - "thiserror 2.0.16", + "thiserror 2.0.17", "zerocopy 0.8.26", "zerocopy-derive 0.8.26", ] @@ -2825,7 +2825,7 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -3318,11 +3318,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -3338,9 +3338,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -3587,7 +3587,7 @@ dependencies = [ "chrono", "serde", "smallvec", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "tracing-subscriber", "uuid", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 600108fe9..60585edb9 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -42,7 +42,7 @@ hyperlight-common = { workspace = true, default-features = true, features = [ "s hyperlight-guest-tracing = { workspace = true, default-features = true, optional = true } vmm-sys-util = "0.15.0" crossbeam-channel = "0.5.15" -thiserror = "2.0.16" +thiserror = "2.0.17" chrono = { version = "0.4", optional = true } anyhow = "1.0" metrics = "0.24.2" From 2c10e2e9b4a71c8017cf3f64fcfc600e1d4cb8d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 05:01:52 +0000 Subject: [PATCH 198/271] Bump quote from 1.0.40 to 1.0.41 (#921) Bumps [quote](https://github.com/dtolnay/quote) from 1.0.40 to 1.0.41. - [Release notes](https://github.com/dtolnay/quote/releases) - [Commits](https://github.com/dtolnay/quote/compare/1.0.40...1.0.41) --- updated-dependencies: - dependency-name: quote dependency-version: 1.0.41 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- src/hyperlight_guest_tracing_macro/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f635c840a..12205f6a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2709,9 +2709,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index 69eb27006..f82b9bb56 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] wasmparser = { version = "0.239.0" } -quote = { version = "1.0.38" } +quote = { version = "1.0.41" } proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } itertools = { version = "0.14.0" } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index 9abbdd845..1a03e25d0 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -16,7 +16,7 @@ name = "hyperlight_component_util" [dependencies] wasmparser = { version = "0.239.0" } -quote = { version = "1.0.38" } +quote = { version = "1.0.41" } proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } itertools = { version = "0.14.0" } diff --git a/src/hyperlight_guest_tracing_macro/Cargo.toml b/src/hyperlight_guest_tracing_macro/Cargo.toml index 2070e868f..7688232a4 100644 --- a/src/hyperlight_guest_tracing_macro/Cargo.toml +++ b/src/hyperlight_guest_tracing_macro/Cargo.toml @@ -11,7 +11,7 @@ description = """Provides the tracing macros for the hyperlight guest, enabling [dependencies] proc-macro2 = "1.0" -quote = "1.0.40" +quote = "1.0.41" syn = { version = "2.0.106", features = ["full"] } [features] From b672541d73c5028d1ae5f3661ba62eef7bcbd1a9 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Mon, 29 Sep 2025 16:20:11 -0700 Subject: [PATCH 199/271] Refactor evolve code to be simpler (#895) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- src/hyperlight_host/src/sandbox/mod.rs | 1 - .../src/sandbox/uninitialized.rs | 22 ++++---- .../src/sandbox/uninitialized_evolve.rs | 56 ++++--------------- 3 files changed, 22 insertions(+), 57 deletions(-) diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index 2f8bee004..b63357d40 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -58,7 +58,6 @@ pub use uninitialized::UninitializedSandbox; #[cfg(target_os = "windows")] use crate::hypervisor::windows_hypervisor_platform; -use crate::mem::shared_mem::HostSharedMemory; // In case its not obvious why there are separate is_supported_platform and is_hypervisor_present functions its because // Hyperlight is designed to be able to run on a host that doesn't have a hypervisor. diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index f952c6bd7..139e6aa2c 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -92,18 +92,6 @@ impl Debug for UninitializedSandbox { } } -impl UninitializedSandbox { - /// Creates and initializes the virtual machine, transforming this into a ready-to-use sandbox. - /// - /// This method consumes the `UninitializedSandbox` and performs the final initialization - /// steps to create the underlying virtual machine. Once evolved, the resulting - /// [`MultiUseSandbox`] can execute guest code and handle function calls. - #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - pub fn evolve(self) -> Result { - evolve_impl_multi_use(self) - } -} - /// A `GuestBinary` is either a buffer or the file path to some data (e.g., a guest binary). #[derive(Debug)] pub enum GuestBinary<'a> { @@ -265,6 +253,16 @@ impl UninitializedSandbox { Ok(sandbox) } + /// Creates and initializes the virtual machine, transforming this into a ready-to-use sandbox. + /// + /// This method consumes the `UninitializedSandbox` and performs the final initialization + /// steps to create the underlying virtual machine. Once evolved, the resulting + /// [`MultiUseSandbox`] can execute guest code and handle function calls. + #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] + pub fn evolve(self) -> Result { + evolve_impl_multi_use(self) + } + /// Load the file at `bin_path_str` into a PE file, then attempt to /// load the PE file into a `SandboxMemoryManager` and return it. /// diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index f73e334e8..637d71998 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +#[cfg(gdb)] use std::sync::{Arc, Mutex}; use rand::Rng; @@ -33,40 +34,16 @@ use crate::mem::ptr_offset::Offset; use crate::mem::shared_mem::GuestSharedMemory; #[cfg(any(feature = "init-paging", target_os = "windows"))] use crate::mem::shared_mem::SharedMemory; -use crate::sandbox::HostSharedMemory; #[cfg(feature = "trace_guest")] use crate::sandbox::TraceInfo; #[cfg(gdb)] use crate::sandbox::config::DebugInfo; -use crate::sandbox::host_funcs::FunctionRegistry; #[cfg(target_os = "linux")] use crate::signal_handlers::setup_signal_handlers; use crate::{MultiUseSandbox, Result, UninitializedSandbox, log_then_return, new_error}; -/// The implementation for evolving `UninitializedSandbox`es to -/// `Sandbox`es. -/// -/// Note that `cb_opt`'s type has been carefully considered. -/// Particularly, it's not using a constrained generic to define -/// the type of the callback because if it did, you'd have to provide -/// type hints to the compiler if you want to pass `None` to the function. -/// With this type signature, you can pass `None` without having to do that. -/// -/// If this doesn't make sense, and you want to change this type, -/// please reach out to a Hyperlight developer before making the change. -#[instrument(err(Debug), skip_all, , parent = Span::current(), level = "Trace")] -fn evolve_impl( - u_sbox: UninitializedSandbox, - transform: TransformFunc, -) -> Result -where - TransformFunc: Fn( - Arc>, - SandboxMemoryManager, - Box, - RawPtr, - ) -> Result, -{ +#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] +pub(super) fn evolve_impl_multi_use(u_sbox: UninitializedSandbox) -> Result { let (hshm, mut gshm) = u_sbox.mgr.build(); let mut vm = set_up_hypervisor_partition( &mut gshm, @@ -109,28 +86,19 @@ where return Err(new_error!("Dispatch function address is null")); } - transform( + let dispatch_ptr = RawPtr::from(dispatch_function_addr); + + #[cfg(gdb)] + let dbg_mem_wrapper = Arc::new(Mutex::new(hshm.clone())); + + Ok(MultiUseSandbox::from_uninit( u_sbox.host_funcs, hshm, vm, - RawPtr::from(dispatch_function_addr), - ) -} - -#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] -pub(super) fn evolve_impl_multi_use(u_sbox: UninitializedSandbox) -> Result { - evolve_impl(u_sbox, |hf, hshm, vm, dispatch_ptr| { + dispatch_ptr, #[cfg(gdb)] - let dbg_mem_wrapper = Arc::new(Mutex::new(hshm.clone())); - Ok(MultiUseSandbox::from_uninit( - hf, - hshm, - vm, - dispatch_ptr, - #[cfg(gdb)] - dbg_mem_wrapper, - )) - }) + dbg_mem_wrapper, + )) } pub(crate) fn set_up_hypervisor_partition( From f6d311862cad3146e759de770454034d9ac326ce Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Fri, 22 Aug 2025 20:17:49 +0000 Subject: [PATCH 200/271] Read the xmm registers while debugging Signed-off-by: James Sturtevant --- .../src/hypervisor/gdb/hyperv_debug.rs | 11 ++ .../src/hypervisor/gdb/kvm_debug.rs | 11 ++ src/hyperlight_host/src/hypervisor/gdb/mod.rs | 1 + .../src/hypervisor/gdb/mshv_debug.rs | 13 ++ .../src/hypervisor/gdb/x86_64_target.rs | 2 + .../hypervisor/windows_hypervisor_platform.rs | 119 ++++++++++++++++++ 6 files changed, 157 insertions(+) diff --git a/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs b/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs index 7a902d6de..301c23d5d 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs @@ -211,6 +211,17 @@ impl GuestDebug for HypervDebug { regs.rip = vcpu_regs.rip; regs.rflags = vcpu_regs.rflags; + // Fetch XMM from WHVP + if let Ok(fpu) = vcpu_fd.get_fpu() { + regs.xmm = [ + fpu.xmm0, fpu.xmm1, fpu.xmm2, fpu.xmm3, fpu.xmm4, fpu.xmm5, fpu.xmm6, fpu.xmm7, + fpu.xmm8, fpu.xmm9, fpu.xmm10, fpu.xmm11, fpu.xmm12, fpu.xmm13, fpu.xmm14, + fpu.xmm15, + ]; + } else { + log::warn!("Failed to read FPU/XMM via WHVP for debug registers"); + } + Ok(()) } diff --git a/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs b/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs index c20b3b279..98df8c373 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs @@ -193,6 +193,17 @@ impl GuestDebug for KvmDebug { regs.rip = vcpu_regs.rip; regs.rflags = vcpu_regs.rflags; + // Read XMM registers from FPU state + match vcpu_fd.get_fpu() { + Ok(fpu) => { + // Convert KVM XMM registers ([u8; 16] x 16) to [u128; 16] + regs.xmm = fpu.xmm.map(u128::from_le_bytes);; + }, + Err(e) => { + log::warn!("Failed to read FPU state for XMM registers: {:?}", e); + } + } + Ok(()) } diff --git a/src/hyperlight_host/src/hypervisor/gdb/mod.rs b/src/hyperlight_host/src/hypervisor/gdb/mod.rs index eac14f323..70e8c0723 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/mod.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/mod.rs @@ -109,6 +109,7 @@ pub(crate) struct X86_64Regs { pub(crate) r15: u64, pub(crate) rip: u64, pub(crate) rflags: u64, + pub(crate) xmm: [u128; 16], } /// Defines the possible reasons for which a vCPU can be stopped when debugging diff --git a/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs b/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs index 9688d9ed1..985a7ba84 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs @@ -220,6 +220,17 @@ impl GuestDebug for MshvDebug { regs.rip = vcpu_regs.rip; regs.rflags = vcpu_regs.rflags; + // Try to read XMM from the FPU state + match vcpu_fd.get_fpu() { + Ok(fpu) => { + // MSHV exposes XMM as [[u8; 16]; 16]. Convert to [u128; 16] + regs.xmm = fpu.xmm.map(u128::from_le_bytes); + } + Err(e) => { + log::warn!("Failed to read FPU state for XMM registers (MSHV): {:?}", e); + } + } + Ok(()) } @@ -258,6 +269,8 @@ impl GuestDebug for MshvDebug { rip: regs.rip, rflags: regs.rflags, + + }; vcpu_fd diff --git a/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs b/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs index a3e36ebb7..5a98b0bd1 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs @@ -227,6 +227,7 @@ impl SingleThreadBase for HyperlightSandboxTarget { regs.regs[15] = read_regs.r15; regs.rip = read_regs.rip; regs.eflags = read_regs.rflags as u32; + regs.xmm = read_regs.xmm; Ok(()) } @@ -267,6 +268,7 @@ impl SingleThreadBase for HyperlightSandboxTarget { r15: regs.regs[15], rip: regs.rip, rflags: u64::from(regs.eflags), + xmm: regs.xmm, }; match self.send_command(DebugMsg::WriteRegisters(regs))? { diff --git a/src/hyperlight_host/src/hypervisor/windows_hypervisor_platform.rs b/src/hyperlight_host/src/hypervisor/windows_hypervisor_platform.rs index 3d97de9ea..2212fd433 100644 --- a/src/hyperlight_host/src/hypervisor/windows_hypervisor_platform.rs +++ b/src/hyperlight_host/src/hypervisor/windows_hypervisor_platform.rs @@ -696,6 +696,125 @@ impl VMProcessor { Ok(()) } + #[cfg(gdb)] + pub(super) fn get_fpu(&self) -> Result { + use windows::Win32::System::Hypervisor::*; + + const LEN: usize = 26; + let names: [WHV_REGISTER_NAME; LEN] = [ + WHvX64RegisterXmm0, + WHvX64RegisterXmm1, + WHvX64RegisterXmm2, + WHvX64RegisterXmm3, + WHvX64RegisterXmm4, + WHvX64RegisterXmm5, + WHvX64RegisterXmm6, + WHvX64RegisterXmm7, + WHvX64RegisterXmm8, + WHvX64RegisterXmm9, + WHvX64RegisterXmm10, + WHvX64RegisterXmm11, + WHvX64RegisterXmm12, + WHvX64RegisterXmm13, + WHvX64RegisterXmm14, + WHvX64RegisterXmm15, + WHvX64RegisterFpMmx0, + WHvX64RegisterFpMmx1, + WHvX64RegisterFpMmx2, + WHvX64RegisterFpMmx3, + WHvX64RegisterFpMmx4, + WHvX64RegisterFpMmx5, + WHvX64RegisterFpMmx6, + WHvX64RegisterFpMmx7, + WHvX64RegisterFpControlStatus, + WHvX64RegisterXmmControlStatus, + ]; + + let mut out: [WHV_REGISTER_VALUE; LEN] = unsafe { std::mem::zeroed() }; + unsafe { + WHvGetVirtualProcessorRegisters( + self.get_partition_hdl(), + 0, + names.as_ptr(), + LEN as u32, + out.as_mut_ptr(), + )?; + + // Helper to read a WHV_UINT128 -> u128 + fn u128_from_whv(fp: WHV_REGISTER_VALUE) -> u128 { + unsafe { + let low = fp.Fp.AsUINT128.Anonymous.Low64 as u128; + let high = fp.Fp.AsUINT128.Anonymous.High64 as u128; + (high << 64) | low + } + } + + let xmm = [ + u128_from_whv(out[0]), + u128_from_whv(out[1]), + u128_from_whv(out[2]), + u128_from_whv(out[3]), + u128_from_whv(out[4]), + u128_from_whv(out[5]), + u128_from_whv(out[6]), + u128_from_whv(out[7]), + u128_from_whv(out[8]), + u128_from_whv(out[9]), + u128_from_whv(out[10]), + u128_from_whv(out[11]), + u128_from_whv(out[12]), + u128_from_whv(out[13]), + u128_from_whv(out[14]), + u128_from_whv(out[15]), + ]; + + let mmx = [ + out[16].Reg64, + out[17].Reg64, + out[18].Reg64, + out[19].Reg64, + out[20].Reg64, + out[21].Reg64, + out[22].Reg64, + out[23].Reg64, + ]; + + let fp_control_word = out[24].FpControlStatus.Anonymous.FpControl; + let fp_tag_word = out[24].FpControlStatus.Anonymous.FpTag; + let mxcsr = out[25].XmmControlStatus.Anonymous.XmmStatusControl; + + Ok(WHvFPURegisters { + xmm0: xmm[0], + xmm1: xmm[1], + xmm2: xmm[2], + xmm3: xmm[3], + xmm4: xmm[4], + xmm5: xmm[5], + xmm6: xmm[6], + xmm7: xmm[7], + xmm8: xmm[8], + xmm9: xmm[9], + xmm10: xmm[10], + xmm11: xmm[11], + xmm12: xmm[12], + xmm13: xmm[13], + xmm14: xmm[14], + xmm15: xmm[15], + mmx0: mmx[0], + mmx1: mmx[1], + mmx2: mmx[2], + mmx3: mmx[3], + mmx4: mmx[4], + mmx5: mmx[5], + mmx6: mmx[6], + mmx7: mmx[7], + fp_control_word, + fp_tag_word, + mxcsr, + }) + } + } + #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] pub(super) fn run(&mut self) -> Result { let partition_handle = self.get_partition_hdl(); From 0bd4ac23f8140887b81249f3a1c8f8920d288e81 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Fri, 22 Aug 2025 20:47:38 +0000 Subject: [PATCH 201/271] Read the mxcsr registers Signed-off-by: James Sturtevant --- .../src/hypervisor/gdb/hyperv_debug.rs | 1 + .../src/hypervisor/gdb/kvm_debug.rs | 17 +- src/hyperlight_host/src/hypervisor/gdb/mod.rs | 1 + .../src/hypervisor/gdb/mshv_debug.rs | 3 +- .../src/hypervisor/gdb/x86_64_target.rs | 2 + src/hyperlight_host/src/hypervisor/kvm.rs | 3 + .../rust_guests/callbackguest/Cargo.lock | 270 ++++++++++++++++++ 7 files changed, 293 insertions(+), 4 deletions(-) create mode 100644 src/tests/rust_guests/callbackguest/Cargo.lock diff --git a/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs b/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs index 301c23d5d..3835a2ff0 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs @@ -218,6 +218,7 @@ impl GuestDebug for HypervDebug { fpu.xmm8, fpu.xmm9, fpu.xmm10, fpu.xmm11, fpu.xmm12, fpu.xmm13, fpu.xmm14, fpu.xmm15, ]; + regs.mxcsr = fpu.mxcsr; } else { log::warn!("Failed to read FPU/XMM via WHVP for debug registers"); } diff --git a/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs b/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs index 98df8c373..9d3db9f22 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs @@ -193,17 +193,30 @@ impl GuestDebug for KvmDebug { regs.rip = vcpu_regs.rip; regs.rflags = vcpu_regs.rflags; - // Read XMM registers from FPU state + // Read XMM registers from FPU state + // note kvm get_fpu doesn't actually set or read the mxcsr value + // https://elixir.bootlin.com/linux/v6.16/source/arch/x86/kvm/x86.c#L12229 match vcpu_fd.get_fpu() { Ok(fpu) => { // Convert KVM XMM registers ([u8; 16] x 16) to [u128; 16] - regs.xmm = fpu.xmm.map(u128::from_le_bytes);; + regs.xmm = fpu.xmm.map(u128::from_le_bytes); }, Err(e) => { log::warn!("Failed to read FPU state for XMM registers: {:?}", e); } } + // Read MXCSR from XSAVE (MXCSR is at byte offset 24 -> u32 index 6) + // Todo maybe I could use xsave to read the registers too instead of a separate call to get_fpu + match vcpu_fd.get_xsave() { + Ok(xsave) => { + regs.mxcsr = xsave.region[6]; + } + Err(e) => { + log::warn!("Failed to read XSAVE for MXCSR: {:?}", e); + } + } + Ok(()) } diff --git a/src/hyperlight_host/src/hypervisor/gdb/mod.rs b/src/hyperlight_host/src/hypervisor/gdb/mod.rs index 70e8c0723..d81aa4d24 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/mod.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/mod.rs @@ -110,6 +110,7 @@ pub(crate) struct X86_64Regs { pub(crate) rip: u64, pub(crate) rflags: u64, pub(crate) xmm: [u128; 16], + pub(crate) mxcsr: u32, } /// Defines the possible reasons for which a vCPU can be stopped when debugging diff --git a/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs b/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs index 985a7ba84..1ec3f08ef 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs @@ -225,6 +225,7 @@ impl GuestDebug for MshvDebug { Ok(fpu) => { // MSHV exposes XMM as [[u8; 16]; 16]. Convert to [u128; 16] regs.xmm = fpu.xmm.map(u128::from_le_bytes); + regs.mxcsr = fpu.mxcsr; } Err(e) => { log::warn!("Failed to read FPU state for XMM registers (MSHV): {:?}", e); @@ -269,8 +270,6 @@ impl GuestDebug for MshvDebug { rip: regs.rip, rflags: regs.rflags, - - }; vcpu_fd diff --git a/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs b/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs index 5a98b0bd1..5379122e7 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs @@ -228,6 +228,7 @@ impl SingleThreadBase for HyperlightSandboxTarget { regs.rip = read_regs.rip; regs.eflags = read_regs.rflags as u32; regs.xmm = read_regs.xmm; + regs.mxcsr = read_regs.mxcsr; Ok(()) } @@ -269,6 +270,7 @@ impl SingleThreadBase for HyperlightSandboxTarget { rip: regs.rip, rflags: u64::from(regs.eflags), xmm: regs.xmm, + mxcsr: regs.mxcsr, }; match self.send_command(DebugMsg::WriteRegisters(regs))? { diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index a69b51f55..b6a2be297 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -586,6 +586,9 @@ impl Hypervisor for KVMDriver { mxcsr: MXCSR_DEFAULT, ..Default::default() // zero out the rest }; + + // note kvm set_fpu doesn't actually set or read the mxcsr value + // https://elixir.bootlin.com/linux/v6.16/source/arch/x86/kvm/x86.c#L12229 self.vcpu_fd.set_fpu(&fpu)?; // run diff --git a/src/tests/rust_guests/callbackguest/Cargo.lock b/src/tests/rust_guests/callbackguest/Cargo.lock new file mode 100644 index 000000000..21ba7c47d --- /dev/null +++ b/src/tests/rust_guests/callbackguest/Cargo.lock @@ -0,0 +1,270 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anyhow" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "buddy_system_allocator" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0108968a3a2dab95b089c0fc3f1afa7759aa5ebe6f1d86d206d6f7ba726eb" +dependencies = [ + "spin 0.9.8", +] + +[[package]] +name = "callbackguest" +version = "0.1.0" +dependencies = [ + "hyperlight-common", + "hyperlight-guest", + "hyperlight-guest-bin", + "hyperlight-guest-tracing", +] + +[[package]] +name = "cc" +version = "1.2.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "flatbuffers" +version = "25.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1045398c1bfd89168b5fd3f1fc11f6e70b34f6f66300c87d44d3de849463abf1" +dependencies = [ + "bitflags", + "rustc_version", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "hyperlight-common" +version = "0.8.0" +dependencies = [ + "anyhow", + "flatbuffers", + "log", + "spin 0.10.0", +] + +[[package]] +name = "hyperlight-guest" +version = "0.8.0" +dependencies = [ + "anyhow", + "hyperlight-common", + "hyperlight-guest-tracing", + "serde_json", +] + +[[package]] +name = "hyperlight-guest-bin" +version = "0.8.0" +dependencies = [ + "buddy_system_allocator", + "cc", + "cfg-if", + "glob", + "hyperlight-common", + "hyperlight-guest", + "hyperlight-guest-tracing", + "log", + "spin 0.10.0", +] + +[[package]] +name = "hyperlight-guest-tracing" +version = "0.8.0" +dependencies = [ + "hyperlight-common", + "hyperlight-guest-tracing-macro", + "spin 0.10.0", +] + +[[package]] +name = "hyperlight-guest-tracing-macro" +version = "0.8.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.141" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" From 08d4c6692d0b6f7f40bcebf20dbe40773819dc51 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Fri, 12 Sep 2025 23:32:23 +0000 Subject: [PATCH 202/271] Add test for additional registers Signed-off-by: James Sturtevant --- Cargo.lock | 57 +++++++++ src/hyperlight_host/Cargo.toml | 1 + .../examples/guest-debugging/main.rs | 119 +++++++++++++----- .../src/hypervisor/gdb/kvm_debug.rs | 33 ++++- src/tests/rust_guests/simpleguest/src/main.rs | 24 +++- 5 files changed, 197 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12205f6a7..0456cba83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -921,6 +921,21 @@ dependencies = [ "pe-unwind-info", ] +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.31" @@ -983,6 +998,7 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", @@ -1470,6 +1486,7 @@ dependencies = [ "seccompiler", "serde", "serde_json", + "serial_test", "sha256", "signal-hook-registry", "tempfile", @@ -3003,6 +3020,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scc" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" +dependencies = [ + "sdd", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -3035,6 +3061,12 @@ dependencies = [ "syn", ] +[[package]] +name = "sdd" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" + [[package]] name = "seccompiler" version = "0.5.0" @@ -3114,6 +3146,31 @@ dependencies = [ "serde", ] +[[package]] +name = "serial_test" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" +dependencies = [ + "futures", + "log", + "once_cell", + "parking_lot", + "scc", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sha2" version = "0.10.9" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 60585edb9..bce81f2e1 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -90,6 +90,7 @@ proptest = "1.8.0" tempfile = "3.23.0" crossbeam-queue = "0.3.12" tracing-serde = "0.2.0" +serial_test = "3.1.1" hyperlight-testing = { workspace = true } env_logger = "0.11.8" tracing-forest = { version = "0.2.0", features = ["uuid", "chrono", "smallvec", "serde", "env-filter"] } diff --git a/src/hyperlight_host/examples/guest-debugging/main.rs b/src/hyperlight_host/examples/guest-debugging/main.rs index e414b72d8..a44fa777e 100644 --- a/src/hyperlight_host/examples/guest-debugging/main.rs +++ b/src/hyperlight_host/examples/guest-debugging/main.rs @@ -20,6 +20,7 @@ use hyperlight_host::sandbox::SandboxConfiguration; #[cfg(gdb)] use hyperlight_host::sandbox::config::DebugInfo; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; +use serial_test::serial; /// Build a sandbox configuration that enables GDB debugging when the `gdb` feature is enabled. fn get_sandbox_cfg() -> Option { @@ -72,6 +73,13 @@ fn main() -> hyperlight_host::Result<()> { let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve()?; // Call guest function + multi_use_sandbox_dbg + .call::<()>( + "UseSSE2Registers", + (), + ) + .unwrap(); + let message = "Hello, World! I am executing inside of a VM with debugger attached :)\n".to_string(); multi_use_sandbox_dbg @@ -106,44 +114,23 @@ mod tests { use super::*; - fn write_cmds_file(cmd_file_path: &str, out_file_path: &str) -> io::Result<()> { - let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get manifest dir"); + fn write_cmds_file(cmd_file_path: &str, cmd: &str) -> io::Result<()> { + let file = File::create(cmd_file_path)?; let mut writer = BufWriter::new(file); // write from string to file writer.write_all( - format!( - "file {manifest_dir}/../tests/rust_guests/bin/debug/simpleguest - target remote :8080 - - set pagination off - set logging file {out_file_path} - set logging on - - break hyperlight_main - commands - echo \"Stopped at hyperlight_main breakpoint\\n\" - backtrace - continue - end - - continue - - set logging off - quit - " - ) - .as_bytes(), + cmd.as_bytes(), )?; writer.flush() } - fn run_guest_and_gdb(cmd_file_path: &str, out_file_path: &str) -> Result<()> { + fn run_guest_and_gdb(cmd_file_path: &str, out_file_path: &str, cmd: &str, checker: fn(String) -> bool) -> Result<()> { // write gdb commands to file - write_cmds_file(&cmd_file_path, &out_file_path) + write_cmds_file(&cmd_file_path, cmd) .expect("Failed to write gdb commands to file"); #[cfg(mshv2)] // mshv3 is a default feature is mutually exclusive with the mshv2 feature @@ -215,17 +202,17 @@ mod tests { } } - check_output(&out_file_path) + check_output(&out_file_path, checker) } - fn check_output(out_file_path: &str) -> Result<()> { + fn check_output(out_file_path: &str, checker: fn(contents: String) -> bool) -> Result<()> { let results = File::open(out_file_path) .map_err(|e| new_error!("Failed to open gdb.output file: {}", e))?; let mut reader = BufReader::new(results); let mut contents = String::new(); reader.read_to_string(&mut contents).unwrap(); - if contents.contains("Stopped at hyperlight_main breakpoint") { + if checker(contents) { Ok(()) } else { Err(new_error!( @@ -247,12 +234,84 @@ mod tests { } #[test] + #[serial] fn test_gdb_end_to_end() { let out_dir = std::env::var("OUT_DIR").expect("Failed to get out dir"); + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get manifest dir"); let out_file_path = format!("{out_dir}/gdb.output"); let cmd_file_path = format!("{out_dir}/gdb-commands.txt"); - let result = run_guest_and_gdb(&cmd_file_path, &out_file_path); + let cmd = format!( + "file {manifest_dir}/../tests/rust_guests/bin/debug/simpleguest + target remote :8080 + + set pagination off + set logging file {out_file_path} + set logging on + + break hyperlight_main + commands + echo \"Stopped at hyperlight_main breakpoint\\n\" + backtrace + + continue + end + + continue + + set logging off + quit + " + ); + + let checker = |contents: String| {contents.contains("Stopped at hyperlight_main breakpoint")}; + + let result = run_guest_and_gdb(&cmd_file_path, &out_file_path, &cmd, checker); + + // cleanup + let cleanup_result = cleanup(&out_file_path, &cmd_file_path); + assert!(cleanup_result.is_ok(), "{}", cleanup_result.unwrap_err()); + // check if the test passed - done at the end to ensure cleanup is done + assert!(result.is_ok(), "{}", result.unwrap_err()); + } + + #[test] + #[serial] + fn test_gdb_sse_check() { + let out_dir = std::env::var("OUT_DIR").expect("Failed to get out dir"); + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get manifest dir"); + let out_file_path = format!("{out_dir}/gdb-sse.output"); + let cmd_file_path = format!("{out_dir}/gdb-sse--commands.txt"); + + let cmd = format!( + "file {manifest_dir}/../tests/rust_guests/bin/debug/simpleguest + target remote :8080 + + set pagination off + set logging file {out_file_path} + set logging on + + break main.rs:simpleguest::use_sse2_registers + commands 1 + print $xmm1.v4_float + break +2 + commands 2 + print $xmm1.v4_float + continue + end + continue + end + + + continue + + set logging off + quit + " + ); + + let checker = |contents: String| {contents.contains("$2 = [1.20000005, 0, 0, 0]")}; + let result = run_guest_and_gdb(&cmd_file_path, &out_file_path, &cmd, checker); // cleanup let cleanup_result = cleanup(&out_file_path, &cmd_file_path); diff --git a/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs b/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs index 9d3db9f22..840f43abc 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs @@ -207,7 +207,6 @@ impl GuestDebug for KvmDebug { } // Read MXCSR from XSAVE (MXCSR is at byte offset 24 -> u32 index 6) - // Todo maybe I could use xsave to read the registers too instead of a separate call to get_fpu match vcpu_fd.get_xsave() { Ok(xsave) => { regs.mxcsr = xsave.region[6]; @@ -262,6 +261,36 @@ impl GuestDebug for KvmDebug { vcpu_fd .set_regs(&new_regs) - .map_err(|e| new_error!("Could not write guest registers: {:?}", e)) + .map_err(|e| new_error!("Could not write guest registers: {:?}", e))?; + + // load existing values and replace the xmm registers + let mut fpu = match vcpu_fd.get_fpu() { + Ok(fpu) => { + fpu + }, + Err(e) => { + return Err(new_error!("Could not write guest registers: {:?}", e)); + } + }; + + // Convert XMM registers from [u128; 16] (our internal representation) + // to [[u8; 16]; 16] (KVM FPU representation) using little-endian byte order. + fpu.xmm = regs.xmm.map(u128::to_le_bytes); + vcpu_fd.set_fpu(&fpu).map_err(|e| new_error!("Could not write guest registers: {:?}", e))?; + + // Update MXCSR using XSAVE region entry 6 (MXCSR) if available. + let mut xsave = match vcpu_fd.get_xsave() { + Ok(xsave) => { + xsave + } + Err(e) => { + return Err(new_error!("Could not write guest registers: {:?}", e)); + } + }; + + xsave.region[6] = regs.mxcsr; + unsafe { vcpu_fd.set_xsave(&xsave).map_err(|e| new_error!("Could not write guest registers: {:?}", e))? }; + + Ok(()) } } diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index aabe74dc5..9b22d6cb0 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -787,6 +787,15 @@ fn call_given_paramless_hostfunc_that_returns_i64(function_call: &FunctionCall) } } +#[hyperlight_guest_tracing::trace_function] +fn use_sse2_registers(_: &FunctionCall) -> Result> { + unsafe { + let val: f32 = 1.2f32; + core::arch::asm!("movss xmm1, DWORD PTR [{0}]", in(reg) &val); + } + Ok(get_flatbuffer_result(())) +} + #[hyperlight_guest_tracing::trace_function] fn add(function_call: &FunctionCall) -> Result> { if let (ParameterValue::Int(a), ParameterValue::Int(b)) = ( @@ -947,7 +956,6 @@ pub extern "C" fn hyperlight_main() { ReturnType::VecBytes, read_from_user_memory as usize, ); - register_function(read_from_user_memory_def); let read_mapped_buffer_def = GuestFunctionDefinition::new( @@ -956,7 +964,6 @@ pub extern "C" fn hyperlight_main() { ReturnType::VecBytes, read_mapped_buffer as usize, ); - register_function(read_mapped_buffer_def); let write_mapped_buffer_def = GuestFunctionDefinition::new( @@ -965,7 +972,6 @@ pub extern "C" fn hyperlight_main() { ReturnType::Bool, write_mapped_buffer as usize, ); - register_function(write_mapped_buffer_def); let exec_mapped_buffer_def = GuestFunctionDefinition::new( @@ -974,7 +980,6 @@ pub extern "C" fn hyperlight_main() { ReturnType::Bool, exec_mapped_buffer as usize, ); - register_function(exec_mapped_buffer_def); let set_static_def = GuestFunctionDefinition::new( @@ -983,7 +988,6 @@ pub extern "C" fn hyperlight_main() { ReturnType::Int, set_static as usize, ); - register_function(set_static_def); let simple_print_output_def = GuestFunctionDefinition::new( @@ -1477,8 +1481,18 @@ pub extern "C" fn hyperlight_main() { call_given_paramless_hostfunc_that_returns_i64 as usize, ); register_function(call_given_hostfunc_def); + + let use_sse2_registers = GuestFunctionDefinition::new( + "UseSSE2Registers".to_string(), + Vec::new(), + ReturnType::Void, + use_sse2_registers as usize, + ); + register_function(use_sse2_registers); } + + #[hyperlight_guest_tracing::trace_function] fn send_message_to_host_method( method_name: &str, From 0a55ab2ae11b6eb0d894b6bcddc52c12ef32c3b7 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Sat, 13 Sep 2025 00:00:31 +0000 Subject: [PATCH 203/271] Set register xmm and mxcsr values Signed-off-by: James Sturtevant --- .../src/hypervisor/gdb/hyperv_debug.rs | 34 +++++++++++++++++-- .../src/hypervisor/gdb/kvm_debug.rs | 1 + .../src/hypervisor/gdb/mshv_debug.rs | 15 ++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs b/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs index 3835a2ff0..c6528f8ab 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs @@ -238,7 +238,7 @@ impl GuestDebug for HypervDebug { fn write_regs(&self, vcpu_fd: &Self::Vcpu, regs: &X86_64Regs) -> Result<()> { log::debug!("Write registers"); - let regs = WHvGeneralRegisters { + let gprs = WHvGeneralRegisters { rax: regs.rax, rbx: regs.rbx, rcx: regs.rcx, @@ -261,7 +261,37 @@ impl GuestDebug for HypervDebug { }; vcpu_fd - .set_general_purpose_registers(®s) + .set_general_purpose_registers(&gprs) + .map_err(|e| new_error!("Could not write guest registers: {:?}", e))?; + + // Load existing FPU state, replace XMM and MXCSR, and write it back. + let mut fpu = match vcpu_fd.get_fpu() { + Ok(f) => f, + Err(e) => { + return Err(new_error!("Could not write guest registers: {:?}", e)); + } + }; + + fpu.xmm0 = regs.xmm[0]; + fpu.xmm1 = regs.xmm[1]; + fpu.xmm2 = regs.xmm[2]; + fpu.xmm3 = regs.xmm[3]; + fpu.xmm4 = regs.xmm[4]; + fpu.xmm5 = regs.xmm[5]; + fpu.xmm6 = regs.xmm[6]; + fpu.xmm7 = regs.xmm[7]; + fpu.xmm8 = regs.xmm[8]; + fpu.xmm9 = regs.xmm[9]; + fpu.xmm10 = regs.xmm[10]; + fpu.xmm11 = regs.xmm[11]; + fpu.xmm12 = regs.xmm[12]; + fpu.xmm13 = regs.xmm[13]; + fpu.xmm14 = regs.xmm[14]; + fpu.xmm15 = regs.xmm[15]; + fpu.mxcsr = regs.mxcsr; + + vcpu_fd + .set_fpu(&fpu) .map_err(|e| new_error!("Could not write guest registers: {:?}", e)) } } diff --git a/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs b/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs index 840f43abc..8a8c2261d 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs @@ -207,6 +207,7 @@ impl GuestDebug for KvmDebug { } // Read MXCSR from XSAVE (MXCSR is at byte offset 24 -> u32 index 6) + // 11.5.10 Mode-Specific XSAVE/XRSTOR State Management match vcpu_fd.get_xsave() { Ok(xsave) => { regs.mxcsr = xsave.region[6]; diff --git a/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs b/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs index 1ec3f08ef..540581426 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs @@ -274,6 +274,21 @@ impl GuestDebug for MshvDebug { vcpu_fd .set_regs(&new_regs) + .map_err(|e| new_error!("Could not write guest registers: {:?}", e))?; + + // Load existing FPU state, replace XMM and MXCSR, and write it back. + let mut fpu = match vcpu_fd.get_fpu() { + Ok(f) => f, + Err(e) => { + return Err(new_error!("Could not write guest registers: {:?}", e)); + } + }; + + fpu.xmm = regs.xmm.map(u128::to_le_bytes); + fpu.mxcsr = regs.mxcsr; + + vcpu_fd + .set_fpu(&fpu) .map_err(|e| new_error!("Could not write guest registers: {:?}", e)) } } From c8bdd6fa60c3b764350d49ba1b1ddc15ada8c5b3 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Sat, 13 Sep 2025 00:05:23 +0000 Subject: [PATCH 204/271] Add some helper files Signed-off-by: James Sturtevant --- .gitignore | 1 + .vscode/settings.json | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2abe2940f..dbd55529f 100644 --- a/.gitignore +++ b/.gitignore @@ -472,3 +472,4 @@ hyperlight_guest.h # gdb .gdbinit trace/* +.gdbguest diff --git a/.vscode/settings.json b/.vscode/settings.json index 3d6d12789..f8cea4474 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,10 @@ "Cargo.toml", // guest crates for testing, not part of the workspace "src/tests/rust_guests/simpleguest/Cargo.toml", - ] + ], + // Enable features in rust analyzer here + "rust-analyzer.cargo.features": [ + // "gdb", + // "kvm" + ], } \ No newline at end of file From 42109441ae307a65e7c387189d5dc9f84ec80795 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Sat, 13 Sep 2025 00:07:23 +0000 Subject: [PATCH 205/271] Clippy updates Signed-off-by: James Sturtevant --- fuzz/fuzz_targets/host_call.rs | 23 ++++++------- .../examples/guest-debugging/main.rs | 33 +++++++++---------- .../src/hypervisor/gdb/kvm_debug.rs | 22 +++++++------ src/tests/rust_guests/simpleguest/src/main.rs | 4 +-- src/trace_dump/main.rs | 25 +++++++------- 5 files changed, 49 insertions(+), 58 deletions(-) diff --git a/fuzz/fuzz_targets/host_call.rs b/fuzz/fuzz_targets/host_call.rs index 8011c7314..2bf241673 100644 --- a/fuzz/fuzz_targets/host_call.rs +++ b/fuzz/fuzz_targets/host_call.rs @@ -57,21 +57,18 @@ fuzz_target!( sandbox.restore(&snapshot).unwrap(); host_func_params.insert(0, ParameterValue::String(host_func_name)); - match sandbox.call_type_erased_guest_function_by_name("FuzzHostFunc", host_func_return, host_func_params) { - Err(e) => { - match e { - // the following are expected errors and occur frequently since - // we are randomly generating the function name and parameters - // to call with. - HyperlightError::HostFunctionNotFound(_) => {} - HyperlightError::UnexpectedNoOfArguments(_, _) => {}, - HyperlightError::ParameterValueConversionFailure(_, _) => {}, + if let Err(e) = sandbox.call_type_erased_guest_function_by_name("FuzzHostFunc", host_func_return, host_func_params) { + match e { + // the following are expected errors and occur frequently since + // we are randomly generating the function name and parameters + // to call with. + HyperlightError::HostFunctionNotFound(_) => {} + HyperlightError::UnexpectedNoOfArguments(_, _) => {}, + HyperlightError::ParameterValueConversionFailure(_, _) => {}, - // any other error should be reported - _ => panic!("Guest Aborted with Unexpected Error: {:?}", e), - } + // any other error should be reported + _ => panic!("Guest Aborted with Unexpected Error: {:?}", e), } - _ => {} } } ); diff --git a/src/hyperlight_host/examples/guest-debugging/main.rs b/src/hyperlight_host/examples/guest-debugging/main.rs index a44fa777e..132297fbd 100644 --- a/src/hyperlight_host/examples/guest-debugging/main.rs +++ b/src/hyperlight_host/examples/guest-debugging/main.rs @@ -20,7 +20,6 @@ use hyperlight_host::sandbox::SandboxConfiguration; #[cfg(gdb)] use hyperlight_host::sandbox::config::DebugInfo; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; -use serial_test::serial; /// Build a sandbox configuration that enables GDB debugging when the `gdb` feature is enabled. fn get_sandbox_cfg() -> Option { @@ -74,10 +73,7 @@ fn main() -> hyperlight_host::Result<()> { // Call guest function multi_use_sandbox_dbg - .call::<()>( - "UseSSE2Registers", - (), - ) + .call::<()>("UseSSE2Registers", ()) .unwrap(); let message = @@ -115,23 +111,24 @@ mod tests { use super::*; fn write_cmds_file(cmd_file_path: &str, cmd: &str) -> io::Result<()> { - let file = File::create(cmd_file_path)?; let mut writer = BufWriter::new(file); // write from string to file - writer.write_all( - cmd.as_bytes(), - )?; + writer.write_all(cmd.as_bytes())?; writer.flush() } - fn run_guest_and_gdb(cmd_file_path: &str, out_file_path: &str, cmd: &str, checker: fn(String) -> bool) -> Result<()> { + fn run_guest_and_gdb( + cmd_file_path: &str, + out_file_path: &str, + cmd: &str, + checker: fn(String) -> bool, + ) -> Result<()> { // write gdb commands to file - write_cmds_file(&cmd_file_path, cmd) - .expect("Failed to write gdb commands to file"); + write_cmds_file(&cmd_file_path, cmd).expect("Failed to write gdb commands to file"); #[cfg(mshv2)] // mshv3 is a default feature is mutually exclusive with the mshv2 feature let features = "gdb,mshv2"; @@ -242,7 +239,7 @@ mod tests { let cmd_file_path = format!("{out_dir}/gdb-commands.txt"); let cmd = format!( - "file {manifest_dir}/../tests/rust_guests/bin/debug/simpleguest + "file {manifest_dir}/../tests/rust_guests/bin/debug/simpleguest target remote :8080 set pagination off @@ -262,9 +259,9 @@ mod tests { set logging off quit " - ); + ); - let checker = |contents: String| {contents.contains("Stopped at hyperlight_main breakpoint")}; + let checker = |contents: String| contents.contains("Stopped at hyperlight_main breakpoint"); let result = run_guest_and_gdb(&cmd_file_path, &out_file_path, &cmd, checker); @@ -284,7 +281,7 @@ mod tests { let cmd_file_path = format!("{out_dir}/gdb-sse--commands.txt"); let cmd = format!( - "file {manifest_dir}/../tests/rust_guests/bin/debug/simpleguest + "file {manifest_dir}/../tests/rust_guests/bin/debug/simpleguest target remote :8080 set pagination off @@ -308,9 +305,9 @@ mod tests { set logging off quit " - ); + ); - let checker = |contents: String| {contents.contains("$2 = [1.20000005, 0, 0, 0]")}; + let checker = |contents: String| contents.contains("$2 = [1.20000005, 0, 0, 0]"); let result = run_guest_and_gdb(&cmd_file_path, &out_file_path, &cmd, checker); // cleanup diff --git a/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs b/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs index 8a8c2261d..fdd6943fa 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs @@ -200,7 +200,7 @@ impl GuestDebug for KvmDebug { Ok(fpu) => { // Convert KVM XMM registers ([u8; 16] x 16) to [u128; 16] regs.xmm = fpu.xmm.map(u128::from_le_bytes); - }, + } Err(e) => { log::warn!("Failed to read FPU state for XMM registers: {:?}", e); } @@ -265,10 +265,8 @@ impl GuestDebug for KvmDebug { .map_err(|e| new_error!("Could not write guest registers: {:?}", e))?; // load existing values and replace the xmm registers - let mut fpu = match vcpu_fd.get_fpu() { - Ok(fpu) => { - fpu - }, + let mut fpu = match vcpu_fd.get_fpu() { + Ok(fpu) => fpu, Err(e) => { return Err(new_error!("Could not write guest registers: {:?}", e)); } @@ -277,20 +275,24 @@ impl GuestDebug for KvmDebug { // Convert XMM registers from [u128; 16] (our internal representation) // to [[u8; 16]; 16] (KVM FPU representation) using little-endian byte order. fpu.xmm = regs.xmm.map(u128::to_le_bytes); - vcpu_fd.set_fpu(&fpu).map_err(|e| new_error!("Could not write guest registers: {:?}", e))?; + vcpu_fd + .set_fpu(&fpu) + .map_err(|e| new_error!("Could not write guest registers: {:?}", e))?; // Update MXCSR using XSAVE region entry 6 (MXCSR) if available. let mut xsave = match vcpu_fd.get_xsave() { - Ok(xsave) => { - xsave - } + Ok(xsave) => xsave, Err(e) => { return Err(new_error!("Could not write guest registers: {:?}", e)); } }; xsave.region[6] = regs.mxcsr; - unsafe { vcpu_fd.set_xsave(&xsave).map_err(|e| new_error!("Could not write guest registers: {:?}", e))? }; + unsafe { + vcpu_fd + .set_xsave(&xsave) + .map_err(|e| new_error!("Could not write guest registers: {:?}", e))? + }; Ok(()) } diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index 9b22d6cb0..681165a60 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -792,7 +792,7 @@ fn use_sse2_registers(_: &FunctionCall) -> Result> { unsafe { let val: f32 = 1.2f32; core::arch::asm!("movss xmm1, DWORD PTR [{0}]", in(reg) &val); - } + } Ok(get_flatbuffer_result(())) } @@ -1491,8 +1491,6 @@ pub extern "C" fn hyperlight_main() { register_function(use_sse2_registers); } - - #[hyperlight_guest_tracing::trace_function] fn send_message_to_host_method( method_name: &str, diff --git a/src/trace_dump/main.rs b/src/trace_dump/main.rs index 4f8416769..e6d205eb9 100644 --- a/src/trace_dump/main.rs +++ b/src/trace_dump/main.rs @@ -120,10 +120,8 @@ fn dump_trace_record( // With the exception of `> halt`, which decreases the indent (because `> entrypoint` does not // have a corresponding `< entrypoint`) let msg = if msg.starts_with('>') { - if msg == "> halt" { - if *indent > 0 { - *indent -= 1; - } + if msg == "> halt" && *indent > 0 { + *indent -= 1; } let indent_str = " ".repeat(*indent as usize); let msg = format!("{}{}", indent_str, &msg); @@ -174,7 +172,7 @@ impl TraceTrie { let mut node = self; for frame in trace { f(&mut node.value); - node = (*node).children.entry(*frame).or_insert(Self::new()) + node = node.children.entry(*frame).or_insert(Self::new()) } f(&mut node.value); } @@ -185,7 +183,7 @@ struct SymbolCache { symbol_cache: HashMap)>>, } impl SymbolCache { - fn resolve_symbol<'c>(&'c mut self, addr: u64) -> &'c Option<(String, Option)> { + fn resolve_symbol(&mut self, addr: u64) -> &Option<(String, Option)> { self.symbol_cache.entry(addr).or_insert_with(|| { let frame = &self.loader.find_frames(addr).ok()?.next().ok()??; let function = frame.function.as_ref()?; @@ -382,7 +380,7 @@ impl ViewParams { bar_start: width / 4.0, bar_height: 12.0, bar_leading: 4.0, - bar_brush: bar_brush, + bar_brush, } } } @@ -391,7 +389,7 @@ struct BarRenderer<'r> { state: &'r mut State, now: Duration, } -impl<'r, 'a, 's> RenderWrapper for BarRenderer<'r> { +impl<'a, 's> RenderWrapper for BarRenderer<'_> { fn render(&mut self, ctx: &mut R, wd: u64, ht: u64) -> Option<()> { let v = ViewParams::new(ctx, ht, wd); draw_bg(ctx, &v); @@ -422,7 +420,7 @@ impl<'r, 'a, 's> RenderWrapper for BarRenderer<'r> { &v, false, (3 + i) as u64, - (&mut self.state.symbol_cache).format_symbol(**site), + self.state.symbol_cache.format_symbol(**site), **size, self.state.total, )?; @@ -488,7 +486,7 @@ fn draw_flame( } Some(()) } -impl<'r, 'a, 's> RenderWrapper for FlameRenderer<'r> { +impl<'a, 's> RenderWrapper for FlameRenderer<'_> { fn render(&mut self, ctx: &mut R, wd: u64, ht: u64) -> Option<()> { let mut v = ViewParams::new(ctx, ht, wd); v.bar_start = v.width / 8.0; @@ -745,7 +743,7 @@ fn spawn_render_thread( let mut bar_ffmpeg = ffmpeg_for(&out_dir, Visualisation::Bar, interval.0)?; let mut flame_ffmpeg = ffmpeg_for(&out_dir, Visualisation::Flame, interval.0)?; let mut job_state = State { - inf: inf, + inf, symbol_cache: SymbolCache { loader, symbol_cache: HashMap::new(), @@ -801,9 +799,9 @@ fn main() { }; let inf = File::open(args[2].clone()).expect("could not open trace file"); let state = State { - inf: inf, + inf, symbol_cache: SymbolCache { - loader: loader, + loader, symbol_cache: HashMap::new(), }, start_time: None, @@ -854,7 +852,6 @@ fn plot_mem(args: Vec, mut state: State) { Some(()) => (), None => { eprintln!("i/o error encountered"); - () } } eprintln!("max total memory used is {}", state.max_total); From e33aee742ec4a5ce52dd878a8efc535e25d90f4e Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Thu, 18 Sep 2025 23:34:52 +0000 Subject: [PATCH 206/271] Use box now that the enum contains xmm registers which are large Signed-off-by: James Sturtevant --- src/hyperlight_host/examples/guest-debugging/main.rs | 1 + src/hyperlight_host/src/hypervisor/gdb/mod.rs | 6 +++--- src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs | 4 ++-- src/hyperlight_host/src/hypervisor/hyperv_linux.rs | 2 +- src/hyperlight_host/src/hypervisor/hyperv_windows.rs | 2 +- src/hyperlight_host/src/hypervisor/kvm.rs | 2 +- src/tests/rust_guests/simpleguest/Cargo.lock | 4 ++-- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/hyperlight_host/examples/guest-debugging/main.rs b/src/hyperlight_host/examples/guest-debugging/main.rs index 132297fbd..d89bc263c 100644 --- a/src/hyperlight_host/examples/guest-debugging/main.rs +++ b/src/hyperlight_host/examples/guest-debugging/main.rs @@ -107,6 +107,7 @@ mod tests { use hyperlight_host::{Result, new_error}; use io::{BufReader, BufWriter, Read, Write}; + use serial_test::serial; use super::*; diff --git a/src/hyperlight_host/src/hypervisor/gdb/mod.rs b/src/hyperlight_host/src/hypervisor/gdb/mod.rs index d81aa4d24..e8daf5aa9 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/mod.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/mod.rs @@ -142,7 +142,7 @@ pub(crate) enum DebugMsg { RemoveSwBreakpoint(u64), Step, WriteAddr(u64, Vec), - WriteRegisters(X86_64Regs), + WriteRegisters(Box), } /// Enumerates the possible responses that a hypervisor can provide to a debugger @@ -157,7 +157,7 @@ pub(crate) enum DebugResponse { NotAllowed, InterruptHandle(Arc), ReadAddr(Vec), - ReadRegisters(X86_64Regs), + ReadRegisters(Box), RemoveHwBreakpoint(bool), RemoveSwBreakpoint(bool), Step, @@ -451,7 +451,7 @@ mod tests { let res = gdb_conn.try_recv(); assert!(res.is_err()); - let res = hyp_conn.send(DebugResponse::ReadRegisters(X86_64Regs::default())); + let res = hyp_conn.send(DebugResponse::ReadRegisters(Box::default())); assert!(res.is_ok()); let res = gdb_conn.recv(); diff --git a/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs b/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs index 5379122e7..3a67d3017 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs @@ -273,7 +273,7 @@ impl SingleThreadBase for HyperlightSandboxTarget { mxcsr: regs.mxcsr, }; - match self.send_command(DebugMsg::WriteRegisters(regs))? { + match self.send_command(DebugMsg::WriteRegisters(Box::new(regs)))? { DebugResponse::WriteRegisters => Ok(()), DebugResponse::NotAllowed => { log::error!("Action not allowed at this time, crash might have occurred"); @@ -486,7 +486,7 @@ mod tests { // Check response to read registers - send the response first to not be blocked // by the recv call in the target - let msg = DebugResponse::ReadRegisters(X86_64Regs::default()); + let msg = DebugResponse::ReadRegisters(Box::default()); let res = gdb_conn.send(msg); assert!(res.is_ok()); diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index aaef9316d..5a009823e 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -202,7 +202,7 @@ mod debug { e }) - .map(|_| DebugResponse::ReadRegisters(regs)) + .map(|_| DebugResponse::ReadRegisters(Box::new(regs))) } DebugMsg::RemoveHwBreakpoint(addr) => Ok(DebugResponse::RemoveHwBreakpoint( debug diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index 620910004..e9aa45703 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -185,7 +185,7 @@ mod debug { e }) - .map(|_| DebugResponse::ReadRegisters(regs)) + .map(|_| DebugResponse::ReadRegisters(Box::new(regs))) } DebugMsg::RemoveHwBreakpoint(addr) => Ok(DebugResponse::RemoveHwBreakpoint( debug diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index b6a2be297..36a7066b6 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -194,7 +194,7 @@ mod debug { e }) - .map(|_| DebugResponse::ReadRegisters(regs)) + .map(|_| DebugResponse::ReadRegisters(Box::new(regs))) } DebugMsg::RemoveHwBreakpoint(addr) => Ok(DebugResponse::RemoveHwBreakpoint( debug diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index 9081da46b..a327588e9 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "autocfg" From 69aa7eefb9cb5550d1bca6e67b5af4efa1579bdc Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Fri, 19 Sep 2025 14:04:47 -0700 Subject: [PATCH 207/271] Enable gdb tests on Windows Signed-off-by: James Sturtevant --- .github/workflows/dep_rust.yml | 3 +-- Justfile | 4 ++-- .../examples/guest-debugging/main.rs | 22 ++++++++++++++++--- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index ffa79aa8c..02756701d 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -157,8 +157,7 @@ jobs: RUST_LOG: debug run: just run-rust-examples-linux ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} - - name: Run Rust Gdb tests - linux - if: runner.os == 'Linux' + - name: Run Rust Gdb tests env: CARGO_TERM_COLOR: always RUST_LOG: debug diff --git a/Justfile b/Justfile index 9d7b62dfe..9c02585a6 100644 --- a/Justfile +++ b/Justfile @@ -126,8 +126,8 @@ like-ci config=default-target hypervisor="kvm": @# Run Rust examples - linux {{ if os() == "linux" { "just run-rust-examples-linux " + config + " " + if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } } else { "" } }} - @# Run Rust Gdb tests - linux - {{ if os() == "linux" { "just test-rust-gdb-debugging " + config + " " + if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } } else { "" } }} + @# Run Rust Gdb tests + just test-rust-gdb-debugging {{ config }} {{ if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } }} @# Run Rust Crashdump tests just test-rust-crashdump {{config}} {{ if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } }} diff --git a/src/hyperlight_host/examples/guest-debugging/main.rs b/src/hyperlight_host/examples/guest-debugging/main.rs index d89bc263c..8dd0e3f79 100644 --- a/src/hyperlight_host/examples/guest-debugging/main.rs +++ b/src/hyperlight_host/examples/guest-debugging/main.rs @@ -111,6 +111,11 @@ mod tests { use super::*; + #[cfg(not(windows))] + const GDB_COMMAND: &str = "rust-gdb"; + #[cfg(windows)] + const GDB_COMMAND: &str = "gdb"; + fn write_cmds_file(cmd_file_path: &str, cmd: &str) -> io::Result<()> { let file = File::create(cmd_file_path)?; let mut writer = BufWriter::new(file); @@ -150,7 +155,7 @@ mod tests { // wait 3 seconds for the gdb to connect thread::sleep(Duration::from_secs(3)); - let mut gdb = Command::new("rust-gdb") + let mut gdb = Command::new(GDB_COMMAND) .arg("--nw") .arg("--batch") .arg("-x") @@ -235,7 +240,9 @@ mod tests { #[serial] fn test_gdb_end_to_end() { let out_dir = std::env::var("OUT_DIR").expect("Failed to get out dir"); - let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get manifest dir"); + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR") + .expect("Failed to get manifest dir") + .replace('\\', "/"); let out_file_path = format!("{out_dir}/gdb.output"); let cmd_file_path = format!("{out_dir}/gdb-commands.txt"); @@ -262,6 +269,9 @@ mod tests { " ); + #[cfg(windows)] + let cmd = format!("set osabi none\n{}", cmd); + let checker = |contents: String| contents.contains("Stopped at hyperlight_main breakpoint"); let result = run_guest_and_gdb(&cmd_file_path, &out_file_path, &cmd, checker); @@ -277,7 +287,10 @@ mod tests { #[serial] fn test_gdb_sse_check() { let out_dir = std::env::var("OUT_DIR").expect("Failed to get out dir"); - let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get manifest dir"); + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR") + .expect("Failed to get manifest dir") + .replace('\\', "/"); + println!("manifest dir {manifest_dir}"); let out_file_path = format!("{out_dir}/gdb-sse.output"); let cmd_file_path = format!("{out_dir}/gdb-sse--commands.txt"); @@ -308,6 +321,9 @@ mod tests { " ); + #[cfg(windows)] + let cmd = format!("set osabi none\n{}", cmd); + let checker = |contents: String| contents.contains("$2 = [1.20000005, 0, 0, 0]"); let result = run_guest_and_gdb(&cmd_file_path, &out_file_path, &cmd, checker); From 3e45ca5163e770ce4de5a4646580c2049b176710 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Fri, 29 Aug 2025 22:49:26 +0000 Subject: [PATCH 208/271] Add target triple support to justfile Signed-off-by: James Sturtevant --- Cross.toml | 9 ++ Justfile | 110 ++++++++++++---------- hack/clippy-package-features.sh | 28 ++++-- src/hyperlight_host/src/mem/shared_mem.rs | 11 ++- 4 files changed, 98 insertions(+), 60 deletions(-) create mode 100644 Cross.toml diff --git a/Cross.toml b/Cross.toml new file mode 100644 index 000000000..7fa77eac0 --- /dev/null +++ b/Cross.toml @@ -0,0 +1,9 @@ +[build] +pre-build = [ + "apt-get update && apt-get -y install gdb" +] + +[build.env] +passthrough = [ + "TARGET_TRIPLE", # Some tests invoke Cargo directly and need this to run correctly +] \ No newline at end of file diff --git a/Justfile b/Justfile index 9c02585a6..1c884f9fa 100644 --- a/Justfile +++ b/Justfile @@ -6,6 +6,20 @@ set dotenv-load := true set-env-command := if os() == "windows" { "$env:" } else { "export " } bin-suffix := if os() == "windows" { ".bat" } else { ".sh" } +################ +### cross-rs ### +################ +target-triple := env('TARGET_TRIPLE', "") +docker := if target-triple != "" { require("docker") } else { "" } +# this command is only used host side not for guests +# include the --target-dir for the cross builds. This ensures that the builds are separated and avoid any conflicts with the guest builds +cargo-cmd := if target-triple != "" { require("cross") } else { "cargo" } +target-triple-flag := if target-triple != "" { "--target " + target-triple + " --target-dir ./target/host"} else { "" } +# set up cross to use the devices +kvm-gid := if path_exists("/dev/kvm") == "true" { `getent group kvm | cut -d: -f3` } else { "" } +export CROSS_CONTAINER_OPTS := if path_exists("/dev/kvm") == "true" { "--device=/dev/kvm" } else if path_exists("/dev/mshv") == "true" { "--device=/dev/mshv" } else { "" } +export CROSS_CONTAINER_GID := if path_exists("/dev/kvm") == "true" { kvm-gid } else {"1000"} # required to have ownership of the mapped in device on kvm + root := justfile_directory() default-target := "debug" @@ -23,12 +37,7 @@ alias cg := build-and-move-c-guests # build host library build target=default-target: - cargo build --profile={{ if target == "debug" { "dev" } else { target } }} - -# build host library -build-with-musl-libc target=default-target: - cargo build --profile={{ if target == "debug" { "dev" } else { target } }} --target x86_64-unknown-linux-musl - + {{ cargo-cmd }} build --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} # build testing guest binaries guests: build-and-move-rust-guests build-and-move-c-guests @@ -75,10 +84,7 @@ test-like-ci config=default-target hypervisor="kvm": just test {{config}} seccomp,build-metadata,init-paging,{{ if hypervisor == "mshv" {"mshv2"} else if hypervisor == "mshv3" {"mshv3"} else {"kvm"} }} @# make sure certain cargo features compile - cargo check -p hyperlight-host --features crashdump - cargo check -p hyperlight-host --features print_debug - cargo check -p hyperlight-host --features gdb - cargo check -p hyperlight-host --features trace_guest,unwind_guest,mem_profile + just check @# without any driver (should fail to compile) just test-compilation-no-default-features {{config}} @@ -143,64 +149,65 @@ test target=default-target features="": (test-unit target features) (test-isolat # runs unit tests test-unit target=default-target features="": - cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} --lib + {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --lib # runs tests that requires being run separately, for example due to global state -test-isolated target=default-target features="": - cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- sandbox::uninitialized::tests::test_trace_trace --exact --ignored - cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- sandbox::uninitialized::tests::test_log_trace --exact --ignored - cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::create_1000_sandboxes --exact --ignored - cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- sandbox::outb::tests::test_log_outb_log --exact --ignored - cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- mem::shared_mem::tests::test_drop --exact --ignored - cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --test integration_test -- log_message --exact --ignored +test-isolated target=default-target features="" : + {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::uninitialized::tests::test_trace_trace --exact --ignored + {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::uninitialized::tests::test_log_trace --exact --ignored + {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::create_1000_sandboxes --exact --ignored + {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::outb::tests::test_log_outb_log --exact --ignored + {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- mem::shared_mem::tests::test_drop --exact --ignored + {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --test integration_test -- log_message --exact --ignored @# metrics tests - cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F function_call_metrics,init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- metrics::tests::test_metrics_are_emitted --exact + {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F function_call_metrics,init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- metrics::tests::test_metrics_are_emitted --exact # runs integration tests. Guest can either be "rust" or "c" test-integration guest target=default-target features="": @# run execute_on_heap test with feature "executable_heap" on and off - {{if os() == "windows" { "$env:" } else { "" } }}GUEST="{{guest}}"{{if os() == "windows" { ";" } else { "" } }} cargo test --profile={{ if target == "debug" { "dev" } else { target } }} --test integration_test execute_on_heap {{ if features =="" {" --features executable_heap"} else {"--features executable_heap," + features} }} -- --ignored - {{if os() == "windows" { "$env:" } else { "" } }}GUEST="{{guest}}"{{if os() == "windows" { ";" } else { "" } }} cargo test --profile={{ if target == "debug" { "dev" } else { target } }} --test integration_test execute_on_heap {{ if features =="" {""} else {"--features " + features} }} -- --ignored + {{if os() == "windows" { "$env:" } else { "" } }}GUEST="{{guest}}"{{if os() == "windows" { ";" } else { "" } }} {{ cargo-cmd }} test --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --test integration_test execute_on_heap {{ if features =="" {" --features executable_heap"} else {"--features executable_heap," + features} }} -- --ignored + {{if os() == "windows" { "$env:" } else { "" } }}GUEST="{{guest}}"{{if os() == "windows" { ";" } else { "" } }} {{ cargo-cmd }} test --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --test integration_test execute_on_heap {{ if features =="" {""} else {"--features " + features} }} -- --ignored @# run the rest of the integration tests - {{if os() == "windows" { "$env:" } else { "" } }}GUEST="{{guest}}"{{if os() == "windows" { ";" } else { "" } }} cargo test -p hyperlight-host {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} --test '*' + {{if os() == "windows" { "$env:" } else { "" } }}GUEST="{{guest}}"{{if os() == "windows" { ";" } else { "" } }} {{ cargo-cmd }} test -p hyperlight-host {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --test '*' # runs seccomp tests test-seccomp target=default-target features="": @# run seccomp test with feature "seccomp" on and off - cargo test --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host test_violate_seccomp_filters --lib {{ if features =="" {''} else { "--features " + features } }} -- --ignored - cargo test --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host test_violate_seccomp_filters --no-default-features {{ if features =~"mshv2" {"--features init-paging,mshv2"} else {"--features mshv3,init-paging,kvm" } }} --lib -- --ignored + {{ cargo-cmd }} test --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host test_violate_seccomp_filters --lib {{ if features =="" {''} else { "--features " + features } }} -- --ignored + {{ cargo-cmd }} test --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host test_violate_seccomp_filters --no-default-features {{ if features =~"mshv2" {"--features init-paging,mshv2"} else {"--features mshv3,init-paging,kvm" } }} --lib -- --ignored # tests compilation with no default features on different platforms test-compilation-no-default-features target=default-target: @# Linux should fail without a hypervisor feature (kvm, mshv, or mshv3) - {{ if os() == "linux" { "! cargo check -p hyperlight-host --no-default-features 2> /dev/null" } else { "" } }} + {{ if os() == "linux" { "! " + cargo-cmd + " check -p hyperlight-host --no-default-features "+target-triple-flag+" 2> /dev/null" } else { "" } }} @# Windows should succeed even without default features - {{ if os() == "windows" { "cargo check -p hyperlight-host --no-default-features" } else { "" } }} + {{ if os() == "windows" { cargo-cmd + " check -p hyperlight-host --no-default-features" } else { "" } }} @# Linux should succeed with a hypervisor driver but without init-paging - {{ if os() == "linux" { "cargo check -p hyperlight-host --no-default-features --features kvm" } else { "" } }} - {{ if os() == "linux" { "cargo check -p hyperlight-host --no-default-features --features mshv2" } else { "" } }} - {{ if os() == "linux" { "cargo check -p hyperlight-host --no-default-features --features mshv3" } else { "" } }} + {{ if os() == "linux" { cargo-cmd + " check -p hyperlight-host --no-default-features --features kvm" } else { "" } }} {{ target-triple-flag }} + {{ if os() == "linux" { cargo-cmd + " check -p hyperlight-host --no-default-features --features mshv2" } else { "" } }} {{ target-triple-flag }} + {{ if os() == "linux" { cargo-cmd + " check -p hyperlight-host --no-default-features --features mshv3" } else { "" } }} {{ target-triple-flag }} # runs tests that exercise gdb debugging test-rust-gdb-debugging target=default-target features="": - cargo test --profile={{ if target == "debug" { "dev" } else { target } }} --example guest-debugging {{ if features =="" {'--features gdb'} else { "--features gdb," + features } }} - cargo test --profile={{ if target == "debug" { "dev" } else { target } }} {{ if features =="" {'--features gdb'} else { "--features gdb," + features } }} -- test_gdb + {{ cargo-cmd }} test --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --example guest-debugging {{ if features =="" {'--features gdb'} else { "--features gdb," + features } }} + {{ cargo-cmd }} test --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} {{ if features =="" {'--features gdb'} else { "--features gdb," + features } }} -- test_gdb # rust test for crashdump test-rust-crashdump target=default-target features="": - cargo test --profile={{ if target == "debug" { "dev" } else { target } }} {{ if features =="" {'--features crashdump'} else { "--features crashdump," + features } }} -- test_crashdump + {{ cargo-cmd }} test --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} {{ if features =="" {'--features crashdump'} else { "--features crashdump," + features } }} -- test_crashdump # rust test for tracing test-rust-tracing target=default-target features="": # Run tests for the tracing guest and macro - cargo test -p hyperlight-guest-tracing --profile={{ if target == "debug" { "dev" } else { target } }} - cargo test -p hyperlight-guest-tracing-macro --profile={{ if target == "debug" { "dev" } else { target } }} + {{ cargo-cmd }} test -p hyperlight-guest-tracing --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} + {{ cargo-cmd }} test -p hyperlight-guest-tracing-macro --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} # Prepare the tracing guest for testing just build-rust-guests {{ target }} trace_guest just move-rust-guests {{ target }} # Run hello-world example with tracing enabled to get the trace output - TRACE_OUTPUT="$(cargo run --profile={{ if target == "debug" { "dev" } else { target } }} --example hello-world --features {{ if features =="" {"trace_guest"} else { "trace_guest," + features } }})" && \ + # note that trace-dump doesn't run on MUSL target as of now + TRACE_OUTPUT="$({{ cargo-cmd }} run --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --example hello-world --features {{ if features =="" {"trace_guest"} else { "trace_guest," + features } }})" && \ TRACE_FILE="$(echo "$TRACE_OUTPUT" | grep -oE 'Creating trace file at: [^ ]+' | awk -F': ' '{print $2}')" && \ echo "$TRACE_OUTPUT" && \ if [ -z "$TRACE_FILE" ]; then \ @@ -215,13 +222,18 @@ test-rust-tracing target=default-target features="": just move-rust-guests {{ target }} test-doc target=default-target features="": - cargo test --profile={{ if target == "debug" { "dev" } else { target } }} {{ if features =="" {''} else { "--features " + features } }} --doc + {{ cargo-cmd }} test --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} {{ if features =="" {''} else { "--features " + features } }} --doc + ################ ### LINTING #### ################ check: - cargo check + {{ cargo-cmd }} check {{ target-triple-flag }} + {{ cargo-cmd }} check -p hyperlight-host --features crashdump {{ target-triple-flag }} + {{ cargo-cmd }} check -p hyperlight-host --features print_debug {{ target-triple-flag }} + {{ cargo-cmd }} check -p hyperlight-host --features gdb {{ target-triple-flag }} + {{ cargo-cmd }} check -p hyperlight-host --features trace_guest,unwind_guest,mem_profile {{ target-triple-flag }} fmt-check: cargo +nightly fmt --all -- --check @@ -241,7 +253,7 @@ fmt-apply: cargo +nightly fmt --manifest-path src/hyperlight_guest_capi/Cargo.toml clippy target=default-target: (witguest-wit) - cargo clippy --all-targets --all-features --profile={{ if target == "debug" { "dev" } else { target } }} -- -D warnings + {{ cargo-cmd }} clippy --all-targets --all-features --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -- -D warnings clippy-guests target=default-target: (witguest-wit) cd src/tests/rust_guests/simpleguest && cargo clippy --profile={{ if target == "debug" { "dev" } else { target } }} -- -D warnings @@ -255,13 +267,13 @@ clippy-apply-fix-windows: # Run clippy with feature combinations for all packages clippy-exhaustive target=default-target: (witguest-wit) - ./hack/clippy-package-features.sh hyperlight-host {{ target }} - ./hack/clippy-package-features.sh hyperlight-guest {{ target }} + ./hack/clippy-package-features.sh hyperlight-host {{ target }} {{ target-triple }} + ./hack/clippy-package-features.sh hyperlight-guest {{ target }} ./hack/clippy-package-features.sh hyperlight-guest-bin {{ target }} - ./hack/clippy-package-features.sh hyperlight-common {{ target }} - ./hack/clippy-package-features.sh hyperlight-testing {{ target }} - ./hack/clippy-package-features.sh hyperlight-component-macro {{ target }} - ./hack/clippy-package-features.sh hyperlight-component-util {{ target }} + ./hack/clippy-package-features.sh hyperlight-common {{ target }} {{ target-triple }} + ./hack/clippy-package-features.sh hyperlight-testing {{ target }} {{ target-triple }} + ./hack/clippy-package-features.sh hyperlight-component-macro {{ target }} {{ target-triple }} + ./hack/clippy-package-features.sh hyperlight-component-util {{ target }} {{ target-triple }} ./hack/clippy-package-features.sh hyperlight-guest-tracing-macro {{ target }} ./hack/clippy-package-features.sh hyperlight-guest-tracing {{ target }} just clippy-guests {{ target }} @@ -279,14 +291,14 @@ verify-msrv: ##################### run-rust-examples target=default-target features="": - cargo run --profile={{ if target == "debug" { "dev" } else { target } }} --example metrics {{ if features =="" {''} else { "--features " + features } }} - cargo run --profile={{ if target == "debug" { "dev" } else { target } }} --example metrics {{ if features =="" {"--features function_call_metrics"} else {"--features function_call_metrics," + features} }} - cargo run --profile={{ if target == "debug" { "dev" } else { target } }} --example logging {{ if features =="" {''} else { "--features " + features } }} + {{ cargo-cmd }} run --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --example metrics {{ if features =="" {''} else { "--features " + features } }} + {{ cargo-cmd }} run --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --example metrics {{ if features =="" {"--features function_call_metrics"} else {"--features function_call_metrics," + features} }} + {{ cargo-cmd }} run --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --example logging {{ if features =="" {''} else { "--features " + features } }} # The two tracing examples are flaky on windows so we run them on linux only for now, need to figure out why as they run fine locally on windows run-rust-examples-linux target=default-target features="": (run-rust-examples target features) - cargo run --profile={{ if target == "debug" { "dev" } else { target } }} --example tracing {{ if features =="" {''} else { "--features " + features } }} - cargo run --profile={{ if target == "debug" { "dev" } else { target } }} --example tracing {{ if features =="" {"--features function_call_metrics" } else {"--features function_call_metrics," + features} }} + {{ cargo-cmd }} run --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --example tracing {{ if features =="" {''} else { "--features " + features } }} + {{ cargo-cmd }} run --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --example tracing {{ if features =="" {"--features function_call_metrics" } else {"--features function_call_metrics," + features} }} ######################### diff --git a/hack/clippy-package-features.sh b/hack/clippy-package-features.sh index dddf582d8..e769700ff 100755 --- a/hack/clippy-package-features.sh +++ b/hack/clippy-package-features.sh @@ -4,13 +4,23 @@ set -euo pipefail # Check for required arguments if [[ $# -lt 2 ]]; then - echo "Usage: $0 " >&2 - echo "Example: $0 hyperlight-host debug" >&2 + echo "Usage: $0 [target_triple]" >&2 + echo "Example: $0 hyperlight-host debug x86_64-unknown-linux-musl" >&2 exit 1 fi PACKAGE="$1" TARGET="$2" +TARGET_TRIPLE="${3:-}" + +CARGO="cargo" + +# Cargo target argument to append to cargo calls (empty if not provided) +TRIPLE_ARG="" +if [[ -n "${TARGET_TRIPLE}" ]]; then + TRIPLE_ARG="--target ${TARGET_TRIPLE} --target-dir ./target/host" + CARGO="cross" +fi # Convert target for cargo profile PROFILE=$([ "$TARGET" = "debug" ] && echo "dev" || echo "$TARGET") @@ -38,23 +48,23 @@ fi # Test with minimal features if [[ ${#REQUIRED_FEATURES[@]} -gt 0 ]]; then echo "Testing $PACKAGE with required features only ($required_features_str)..." - (set -x; cargo clippy -p "$PACKAGE" --all-targets --no-default-features --features "$required_features_str" --profile="$PROFILE" -- -D warnings) + (set -x; "$CARGO" clippy -p "$PACKAGE" --all-targets --no-default-features --features "$required_features_str" --profile="$PROFILE" ${TRIPLE_ARG} -- -D warnings) else echo "Testing $PACKAGE with no features..." - (set -x; cargo clippy -p "$PACKAGE" --all-targets --no-default-features --profile="$PROFILE" -- -D warnings) + (set -x; "$CARGO" clippy -p "$PACKAGE" --all-targets --no-default-features --profile="$PROFILE" ${TRIPLE_ARG} -- -D warnings) fi echo "Testing $PACKAGE with default features..." -(set -x; cargo clippy -p "$PACKAGE" --all-targets --profile="$PROFILE" -- -D warnings) +(set -x; "$CARGO" clippy -p "$PACKAGE" --all-targets --profile="$PROFILE" ${TRIPLE_ARG} -- -D warnings) # Test each additional feature individually for feature in $features; do if [[ ${#REQUIRED_FEATURES[@]} -gt 0 ]]; then echo "Testing $PACKAGE with feature: $required_features_str,$feature" - (set -x; cargo clippy -p "$PACKAGE" --all-targets --no-default-features --features "$required_features_str,$feature" --profile="$PROFILE" -- -D warnings) + (set -x; "$CARGO" clippy -p "$PACKAGE" --all-targets --no-default-features --features "$required_features_str,$feature" --profile="$PROFILE" ${TRIPLE_ARG} -- -D warnings) else echo "Testing $PACKAGE with feature: $feature" - (set -x; cargo clippy -p "$PACKAGE" --all-targets --no-default-features --features "$feature" --profile="$PROFILE" -- -D warnings) + (set -x; "$CARGO" clippy -p "$PACKAGE" --all-targets --no-default-features --features "$feature" --profile="$PROFILE" ${TRIPLE_ARG} -- -D warnings) fi done @@ -63,9 +73,9 @@ if [[ -n "$features" ]]; then all_features=$(echo $features | tr '\n' ',' | sed 's/,$//') if [[ ${#REQUIRED_FEATURES[@]} -gt 0 ]]; then echo "Testing $PACKAGE with all features: $required_features_str,$all_features" - (set -x; cargo clippy -p "$PACKAGE" --all-targets --no-default-features --features "$required_features_str,$all_features" --profile="$PROFILE" -- -D warnings) + (set -x; "$CARGO" clippy -p "$PACKAGE" --all-targets --no-default-features --features "$required_features_str,$all_features" --profile="$PROFILE" ${TRIPLE_ARG} -- -D warnings) else echo "Testing $PACKAGE with all features: $all_features" - (set -x; cargo clippy -p "$PACKAGE" --all-targets --no-default-features --features "$all_features" --profile="$PROFILE" -- -D warnings) + (set -x; "$CARGO" clippy -p "$PACKAGE" --all-targets --no-default-features --features "$all_features" --profile="$PROFILE" ${TRIPLE_ARG} -- -D warnings) fi fi \ No newline at end of file diff --git a/src/hyperlight_host/src/mem/shared_mem.rs b/src/hyperlight_host/src/mem/shared_mem.rs index 84cbb4c8e..030c2c958 100644 --- a/src/hyperlight_host/src/mem/shared_mem.rs +++ b/src/hyperlight_host/src/mem/shared_mem.rs @@ -1230,10 +1230,17 @@ mod tests { #[test] fn guard_page_testing_shim() { let tests = vec!["read", "write", "exec"]; - for test in tests { + let triple = std::env::var("TARGET_TRIPLE").ok(); + let target_args = if let Some(triple) = triple.filter(|t| !t.is_empty()) { + vec!["--target".to_string(), triple.to_string()] + } else { + vec![] + }; let status = std::process::Command::new("cargo") - .args(["test", "-p", "hyperlight-host", "--", "--ignored", test]) + .args(["test", "-p", "hyperlight-host"]) + .args(target_args) + .args(["--", "--ignored", test]) .stdin(std::process::Stdio::null()) .stdout(std::process::Stdio::null()) .stderr(std::process::Stdio::null()) From 0b48c00ea113e30de172a925875d0915b89514aa Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Fri, 29 Aug 2025 22:51:13 +0000 Subject: [PATCH 209/271] Disable seccomp for musl target Signed-off-by: James Sturtevant --- src/hyperlight_host/build.rs | 1 + src/hyperlight_host/src/error.rs | 6 +++--- src/hyperlight_host/src/func/host_functions.rs | 4 ++-- src/hyperlight_host/src/lib.rs | 2 +- src/hyperlight_host/src/metrics/mod.rs | 4 ++-- src/hyperlight_host/src/sandbox/host_funcs.rs | 4 ++-- .../src/sandbox/initialized_multi_use.rs | 10 +++++----- src/hyperlight_host/src/sandbox/uninitialized.rs | 12 ++++++------ src/hyperlight_host/src/signal_handlers/mod.rs | 4 ++-- .../src/signal_handlers/sigsys_signal_handler.rs | 2 +- src/hyperlight_host/tests/integration_test.rs | 4 ++-- 11 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/hyperlight_host/build.rs b/src/hyperlight_host/build.rs index 6c90a485f..bef001b22 100644 --- a/src/hyperlight_host/build.rs +++ b/src/hyperlight_host/build.rs @@ -101,6 +101,7 @@ fn main() -> Result<()> { // the other features they want. mshv2: { all(feature = "mshv2", target_os = "linux") }, mshv3: { all(feature = "mshv3", not(feature="mshv2"), target_os = "linux") }, + seccomp: { all(feature = "seccomp", target_os = "linux", not(target_env = "musl")) }, } #[cfg(feature = "build-metadata")] diff --git a/src/hyperlight_host/src/error.rs b/src/hyperlight_host/src/error.rs index d2fb382a0..9ecce9968 100644 --- a/src/hyperlight_host/src/error.rs +++ b/src/hyperlight_host/src/error.rs @@ -71,7 +71,7 @@ pub enum HyperlightError { /// A disallowed syscall was caught #[error("Seccomp filter trapped on disallowed syscall (check STDERR for offending syscall)")] - #[cfg(all(feature = "seccomp", target_os = "linux"))] + #[cfg(seccomp)] DisallowedSyscall, /// A generic error with a message @@ -218,12 +218,12 @@ pub enum HyperlightError { /// a backend error occurred with seccomp filters #[error("Backend Error with Seccomp Filter {0:?}")] - #[cfg(all(feature = "seccomp", target_os = "linux"))] + #[cfg(seccomp)] SeccompFilterBackendError(#[from] seccompiler::BackendError), /// an error occurred with seccomp filters #[error("Error with Seccomp Filter {0:?}")] - #[cfg(all(feature = "seccomp", target_os = "linux"))] + #[cfg(seccomp)] SeccompFilterError(#[from] seccompiler::Error), /// Tried to restore snapshot to a sandbox that is not the same as the one the snapshot was taken from diff --git a/src/hyperlight_host/src/func/host_functions.rs b/src/hyperlight_host/src/func/host_functions.rs index 871d04c97..a0fcbb52f 100644 --- a/src/hyperlight_host/src/func/host_functions.rs +++ b/src/hyperlight_host/src/func/host_functions.rs @@ -35,7 +35,7 @@ pub trait Registerable { ) -> Result<()>; /// Register a primitive host function whose worker thread has /// extra permissive seccomp filters installed - #[cfg(all(feature = "seccomp", target_os = "linux"))] + #[cfg(seccomp)] fn register_host_function_with_syscalls( &mut self, name: &str, @@ -63,7 +63,7 @@ impl Registerable for UninitializedSandbox { (*hfs).register_host_function(name.to_string(), entry, &mut self.mgr) } - #[cfg(all(feature = "seccomp", target_os = "linux"))] + #[cfg(seccomp)] fn register_host_function_with_syscalls( &mut self, name: &str, diff --git a/src/hyperlight_host/src/lib.rs b/src/hyperlight_host/src/lib.rs index 34c7ddd2a..10e8a898a 100644 --- a/src/hyperlight_host/src/lib.rs +++ b/src/hyperlight_host/src/lib.rs @@ -76,7 +76,7 @@ pub mod metrics; /// outside this file. Types from this module needed for public consumption are /// re-exported below. pub mod sandbox; -#[cfg(all(feature = "seccomp", target_os = "linux"))] +#[cfg(seccomp)] pub(crate) mod seccomp; /// Signal handling for Linux #[cfg(target_os = "linux")] diff --git a/src/hyperlight_host/src/metrics/mod.rs b/src/hyperlight_host/src/metrics/mod.rs index 76e9b93a3..67a7b0eca 100644 --- a/src/hyperlight_host/src/metrics/mod.rs +++ b/src/hyperlight_host/src/metrics/mod.rs @@ -133,7 +133,7 @@ mod tests { if #[cfg(feature = "function_call_metrics")] { use metrics::Label; - let expected_num_metrics = if cfg!(all(feature = "seccomp", target_os = "linux")) { + let expected_num_metrics = if cfg!(all(seccomp)) { 3 // if seccomp enabled, the host call duration metric is emitted on a separate thread which this local recorder doesn't capture } else { 4 @@ -186,7 +186,7 @@ mod tests { "Histogram metric does not match expected value" ); - if !cfg!(all(feature = "seccomp", target_os = "linux")) { + if !cfg!(all(seccomp)) { // 4. Host call duration let histogram_key = CompositeKey::new( metrics_util::MetricKind::Histogram, diff --git a/src/hyperlight_host/src/sandbox/host_funcs.rs b/src/hyperlight_host/src/sandbox/host_funcs.rs index 6d3c8d98a..b61a2cd77 100644 --- a/src/hyperlight_host/src/sandbox/host_funcs.rs +++ b/src/hyperlight_host/src/sandbox/host_funcs.rs @@ -154,7 +154,7 @@ pub(super) fn default_writer_func(s: String) -> Result { } } -#[cfg(all(feature = "seccomp", target_os = "linux"))] +#[cfg(seccomp)] fn maybe_with_seccomp( name: &str, syscalls: Option<&[ExtraAllowedSyscall]>, @@ -199,7 +199,7 @@ fn maybe_with_seccomp( }) } -#[cfg(not(all(feature = "seccomp", target_os = "linux")))] +#[cfg(not(seccomp))] fn maybe_with_seccomp( _name: &str, _syscalls: Option<&[ExtraAllowedSyscall]>, diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index fc860caf6..b80a7c960 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -625,7 +625,7 @@ mod tests { let res: Result = sbox.call("ViolateSeccompFilters", ()); - #[cfg(feature = "seccomp")] + #[cfg(seccomp)] match res { Ok(_) => panic!("Expected to fail due to seccomp violation"), Err(e) => match e { @@ -634,7 +634,7 @@ mod tests { }, } - #[cfg(not(feature = "seccomp"))] + #[cfg(not(seccomp))] match res { Ok(_) => (), Err(e) => panic!("Expected to succeed without seccomp: {}", e), @@ -642,7 +642,7 @@ mod tests { } // Second, run with allowing `SYS_getpid` - #[cfg(feature = "seccomp")] + #[cfg(seccomp)] { let mut usbox = UninitializedSandbox::new( GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")), @@ -719,7 +719,7 @@ mod tests { ) .expect("Expected to call host function that returns i64"); - if cfg!(feature = "seccomp") { + if cfg!(seccomp) { // If seccomp is enabled, we expect the syscall to return EACCES, as setup by our seccomp filter assert_eq!(host_func_result, -libc::EACCES as i64); } else { @@ -728,7 +728,7 @@ mod tests { } } - #[cfg(feature = "seccomp")] + #[cfg(seccomp)] { // Now let's make sure if we register the `openat` syscall as an extra allowed syscall, it will succeed let mut ubox = UninitializedSandbox::new( diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index 139e6aa2c..c4b08da2f 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -35,7 +35,7 @@ use crate::mem::shared_mem::ExclusiveSharedMemory; use crate::sandbox::SandboxConfiguration; use crate::{MultiUseSandbox, Result, new_error}; -#[cfg(all(target_os = "linux", feature = "seccomp"))] +#[cfg(seccomp)] const EXTRA_ALLOWED_SYSCALLS_FOR_WRITER_FUNC: &[super::ExtraAllowedSyscall] = &[ // Fuzzing fails without `mmap` being an allowed syscall on our seccomp filter. // All fuzzing does is call `PrintOutput` (which calls `HostPrint` ). Thing is, `println!` @@ -311,7 +311,7 @@ impl UninitializedSandbox { /// /// Unlike [`register`](Self::register), this variant allows specifying extra syscalls /// that will be permitted when the function handler runs. - #[cfg(all(feature = "seccomp", target_os = "linux"))] + #[cfg(seccomp)] pub fn register_with_extra_allowed_syscalls< Args: ParameterTuple, Output: SupportedReturnType, @@ -334,10 +334,10 @@ impl UninitializedSandbox { &mut self, print_func: impl Into>, ) -> Result<()> { - #[cfg(not(all(target_os = "linux", feature = "seccomp")))] + #[cfg(not(seccomp))] self.register("HostPrint", print_func)?; - #[cfg(all(target_os = "linux", feature = "seccomp"))] + #[cfg(seccomp)] self.register_with_extra_allowed_syscalls( "HostPrint", print_func, @@ -351,13 +351,13 @@ impl UninitializedSandbox { /// /// Like [`register_print`](Self::register_print), but allows specifying extra syscalls /// that will be permitted during function execution. - #[cfg(all(feature = "seccomp", target_os = "linux"))] + #[cfg(seccomp)] pub fn register_print_with_extra_allowed_syscalls( &mut self, print_func: impl Into>, extra_allowed_syscalls: impl IntoIterator, ) -> Result<()> { - #[cfg(all(target_os = "linux", feature = "seccomp"))] + #[cfg(seccomp)] self.register_with_extra_allowed_syscalls( "HostPrint", print_func, diff --git a/src/hyperlight_host/src/signal_handlers/mod.rs b/src/hyperlight_host/src/signal_handlers/mod.rs index 1644a7206..43a58977b 100644 --- a/src/hyperlight_host/src/signal_handlers/mod.rs +++ b/src/hyperlight_host/src/signal_handlers/mod.rs @@ -18,7 +18,7 @@ use libc::c_int; use crate::sandbox::SandboxConfiguration; -#[cfg(feature = "seccomp")] +#[cfg(seccomp)] pub mod sigsys_signal_handler; pub(crate) fn setup_signal_handlers(config: &SandboxConfiguration) -> crate::Result<()> { @@ -27,7 +27,7 @@ pub(crate) fn setup_signal_handlers(config: &SandboxConfiguration) -> crate::Res // Anything that performs memory allocations, locks, and others are non-async-signal-safe. // Hyperlight signal handlers are all designed to be async-signal-safe, so this function // should be safe to call. - #[cfg(feature = "seccomp")] + #[cfg(seccomp)] { use std::sync::Once; diff --git a/src/hyperlight_host/src/signal_handlers/sigsys_signal_handler.rs b/src/hyperlight_host/src/signal_handlers/sigsys_signal_handler.rs index 1bab82e1e..0202873f5 100644 --- a/src/hyperlight_host/src/signal_handlers/sigsys_signal_handler.rs +++ b/src/hyperlight_host/src/signal_handlers/sigsys_signal_handler.rs @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -#[cfg(feature = "seccomp")] +#[cfg(seccomp)] pub(super) extern "C" fn handle_sigsys( signal: i32, info: *mut libc::siginfo_t, diff --git a/src/hyperlight_host/tests/integration_test.rs b/src/hyperlight_host/tests/integration_test.rs index 8b2077a19..be3ead190 100644 --- a/src/hyperlight_host/tests/integration_test.rs +++ b/src/hyperlight_host/tests/integration_test.rs @@ -49,10 +49,10 @@ fn interrupt_host_call() { Ok(()) }; - #[cfg(any(target_os = "windows", not(feature = "seccomp")))] + #[cfg(any(target_os = "windows", not(seccomp)))] usbox.register("Spin", spin).unwrap(); - #[cfg(all(target_os = "linux", feature = "seccomp"))] + #[cfg(seccomp)] usbox .register_with_extra_allowed_syscalls("Spin", spin, vec![libc::SYS_clock_nanosleep]) .unwrap(); From 2d65dcf76f90d41d72f8063ff2616870292f5ff5 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Fri, 29 Aug 2025 23:58:48 +0000 Subject: [PATCH 210/271] Fix a race condition in this test Signed-off-by: James Sturtevant --- src/hyperlight_host/examples/guest-debugging/main.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/hyperlight_host/examples/guest-debugging/main.rs b/src/hyperlight_host/examples/guest-debugging/main.rs index 8dd0e3f79..9d9ac230e 100644 --- a/src/hyperlight_host/examples/guest-debugging/main.rs +++ b/src/hyperlight_host/examples/guest-debugging/main.rs @@ -141,6 +141,18 @@ mod tests { #[cfg(not(mshv2))] let features = "gdb"; + // build it before running to avoid a race condition below + let mut guest_child = Command::new("cargo") + .arg("build") + .arg("--example") + .arg("guest-debugging") + .arg("--features") + .arg(features) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .status() + .map_err(|e| new_error!("Failed to build guest process: {}", e))?; + let mut guest_child = Command::new("cargo") .arg("run") .arg("--example") From 511f34e95819462063fc24ac05729dfcc855a39d Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Thu, 11 Sep 2025 02:38:32 +0000 Subject: [PATCH 211/271] Refactor dep_rust so it is re-usable in new nightly job Signed-off-by: James Sturtevant --- .github/workflows/RustNightly.yml | 27 ++++++ .github/workflows/ValidatePullRequest.yml | 9 ++ .github/workflows/dep_rust.yml | 103 +++++++++++++--------- 3 files changed, 97 insertions(+), 42 deletions(-) create mode 100644 .github/workflows/RustNightly.yml diff --git a/.github/workflows/RustNightly.yml b/.github/workflows/RustNightly.yml new file mode 100644 index 000000000..ad4604bad --- /dev/null +++ b/.github/workflows/RustNightly.yml @@ -0,0 +1,27 @@ +# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json + +name: Nightly + +on: + workflow_dispatch: + schedule: + - cron: '0 0 */2 * *' + +jobs: + musl: + strategy: + fail-fast: true + matrix: + hypervisor: [kvm, mshv3] + cpu: [amd, intel] + config: [debug, release] + uses: ./.github/workflows/dep_rust.yml + secrets: inherit + with: + hypervisor: ${{ matrix.hypervisor }} + cpu: ${{ matrix.cpu }} + config: ${{ matrix.config }} + target_triple: x86_64-unknown-linux-musl + +# TODO: using notification script + diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index 0316f4862..726f73e80 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -44,10 +44,19 @@ jobs: rust: needs: - docs-pr + strategy: + fail-fast: true + matrix: + hypervisor: [hyperv, 'hyperv-ws2025', mshv, mshv3, kvm] + cpu: [amd, intel] + config: [debug, release] uses: ./.github/workflows/dep_rust.yml secrets: inherit with: docs_only: ${{needs.docs-pr.outputs.docs-only}} + hypervisor: ${{ matrix.hypervisor }} + cpu: ${{ matrix.cpu }} + config: ${{ matrix.config }} fuzzing: needs: diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index 02756701d..a6acefd1c 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -11,6 +11,26 @@ on: required: false type: string default: "false" + target_triple: + description: Target triple for cross-compilation + required: false + type: string + default: "" + hypervisor: + description: Hypervisor for this run (passed from caller matrix) + required: false + type: string + default: "kvm" + config: + description: Build configuration for this run (passed from caller matrix) + required: false + type: string + default: "debug" + cpu: + description: CPU architecture for the build (passed from caller matrix) + required: false + type: string + default: "amd" env: CARGO_TERM_COLOR: always @@ -32,17 +52,12 @@ defaults: jobs: code-checks: - if: ${{ inputs.docs_only == 'false' }} + if: ${{ inputs.docs_only == 'false' && (inputs.hypervisor == 'hyperv-ws2025' || inputs.hypervisor == 'kvm') }} timeout-minutes: 60 - strategy: - fail-fast: true - matrix: - hypervisor: ['hyperv-ws2025', kvm] - config: [debug, release] runs-on: ${{ fromJson( format('["self-hosted", "{0}", "X64", "1ES.Pool=hld-{1}-amd"]', - (matrix.hypervisor == 'hyperv-ws2025') && 'Windows' || 'Linux', - matrix.hypervisor == 'hyperv-ws2025' && 'win2025' || 'kvm')) }} + (inputs.hypervisor == 'hyperv-ws2025') && 'Windows' || 'Linux', + inputs.hypervisor == 'hyperv-ws2025' && 'win2025' || 'kvm')) }} steps: - uses: actions/checkout@v5 @@ -63,13 +78,17 @@ jobs: - name: clippy if: ${{ (runner.os == 'Windows' )}} run: | - just clippy ${{ matrix.config }} - just clippy-guests ${{ matrix.config }} + just clippy ${{ inputs.config }} + just clippy-guests ${{ inputs.config }} + env: + TARGET_TRIPLE: ${{ inputs.target_triple }} - name: clippy exhaustive check if: ${{ (runner.os == 'Linux' )}} run: | - just clippy-exhaustive ${{ matrix.config }} + just clippy-exhaustive ${{ inputs.config }} + env: + TARGET_TRIPLE: ${{ inputs.target_triple }} - name: Verify MSRV run: ./dev/verify-msrv.sh hyperlight-host hyperlight-guest hyperlight-guest-bin hyperlight-common @@ -77,18 +96,11 @@ jobs: build: if: ${{ inputs.docs_only == 'false' }} timeout-minutes: 60 - strategy: - fail-fast: true - matrix: - hypervisor: [hyperv, 'hyperv-ws2025', mshv, mshv3, kvm] # hyperv is windows, mshv and kvm are linux - cpu: [amd, intel] - config: [debug, release] - runs-on: ${{ fromJson( format('["self-hosted", "{0}", "X64", "1ES.Pool=hld-{1}-{2}"]', - (matrix.hypervisor == 'hyperv' || matrix.hypervisor == 'hyperv-ws2025') && 'Windows' || 'Linux', - matrix.hypervisor == 'hyperv' && 'win2022' || matrix.hypervisor == 'hyperv-ws2025' && 'win2025' || matrix.hypervisor == 'mshv3' && 'azlinux3-mshv' || matrix.hypervisor, - matrix.cpu)) }} + (inputs.hypervisor == 'hyperv' || inputs.hypervisor == 'hyperv-ws2025') && 'Windows' || 'Linux', + inputs.hypervisor == 'hyperv' && 'win2022' || inputs.hypervisor == 'hyperv-ws2025' && 'win2025' || inputs.hypervisor == 'mshv3' && 'azlinux3-mshv' || inputs.hypervisor, + inputs.cpu)) }} steps: - uses: actions/checkout@v5 @@ -112,35 +124,36 @@ jobs: - name: Build and move Rust guests run: | # use these commands in favor of build-and-move-rust-guests to avoid building both configs - just build-rust-guests ${{ matrix.config }} - just move-rust-guests ${{ matrix.config }} + just build-rust-guests ${{ inputs.config }} + just move-rust-guests ${{ inputs.config }} - name: Build c guests run: | # use these commands in favor of build-and-move-c-guests to avoid building both configs - just build-c-guests ${{ matrix.config }} - just move-c-guests ${{ matrix.config }} + just build-c-guests ${{ inputs.config }} + just move-c-guests ${{ inputs.config }} + - name: Build - run: just build ${{ matrix.config }} + run: just build ${{ inputs.config }} + env: + TARGET_TRIPLE: ${{ inputs.target_triple }} - name: Run Rust tests env: CARGO_TERM_COLOR: always + TARGET_TRIPLE: ${{ inputs.target_triple }} run: | # with default features - just test ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} + just test ${{ inputs.config }} ${{ inputs.hypervisor == 'mshv' && 'mshv2' || '""'}} # with only one driver enabled (driver mshv/kvm feature is ignored on windows) + seccomp - just test ${{ matrix.config }} seccomp,${{ matrix.hypervisor == 'mshv' && 'mshv2' || matrix.hypervisor == 'mshv3' && 'mshv3' || 'kvm' }} + just test ${{ inputs.config }} seccomp,${{ inputs.hypervisor == 'mshv' && 'mshv2' || inputs.hypervisor == 'mshv3' && 'mshv3' || 'kvm' }} # make sure certain cargo features compile - cargo check -p hyperlight-host --features crashdump - cargo check -p hyperlight-host --features print_debug - cargo check -p hyperlight-host --features gdb - cargo check -p hyperlight-host --features trace_guest,unwind_guest,mem_profile + just check # without any features - just test-compilation-no-default-features ${{ matrix.config }} + just test-compilation-no-default-features ${{ inputs.config }} # One of the examples is flaky on Windows GH runners, so this allows us to disable it for now - name: Run Rust examples - windows @@ -148,42 +161,48 @@ jobs: env: CARGO_TERM_COLOR: always RUST_LOG: debug - run: just run-rust-examples ${{ matrix.config }} + TARGET_TRIPLE: ${{ inputs.target_triple }} + run: just run-rust-examples ${{ inputs.config }} + - name: Run Rust examples - linux if: ${{ (runner.os != 'Windows') }} env: CARGO_TERM_COLOR: always RUST_LOG: debug - run: just run-rust-examples-linux ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} + TARGET_TRIPLE: ${{ inputs.target_triple }} + run: just run-rust-examples-linux ${{ inputs.config }} ${{ inputs.hypervisor == 'mshv' && 'mshv2' || '""'}} - name: Run Rust Gdb tests env: CARGO_TERM_COLOR: always RUST_LOG: debug - run: just test-rust-gdb-debugging ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} + TARGET_TRIPLE: ${{ inputs.target_triple }} + run: just test-rust-gdb-debugging ${{ inputs.config }} ${{ inputs.hypervisor == 'mshv' && 'mshv2' || '""'}} - name: Run Rust Crashdump tests env: CARGO_TERM_COLOR: always RUST_LOG: debug - run: just test-rust-crashdump ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} + TARGET_TRIPLE: ${{ inputs.target_triple }} + run: just test-rust-crashdump ${{ inputs.config }} ${{ inputs.hypervisor == 'mshv' && 'mshv2' || '""'}} - name: Run Rust Tracing tests - linux if: runner.os == 'Linux' env: CARGO_TERM_COLOR: always RUST_LOG: debug - run: just test-rust-tracing ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} + TARGET_TRIPLE: ${{ inputs.target_triple }} + run: just test-rust-tracing ${{ inputs.config }} ${{ inputs.hypervisor == 'mshv' && 'mshv2' || '""'}} - name: Download benchmarks from "latest" - run: just bench-download ${{ runner.os }} ${{ matrix.hypervisor }} ${{ matrix.cpu}} dev-latest # compare to prerelease + run: just bench-download ${{ runner.os }} ${{ inputs.hypervisor }} ${{ inputs.cpu}} dev-latest # compare to prerelease env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} continue-on-error: true - if: ${{ matrix.config == 'release' }} + if: ${{ inputs.config == 'release' && inputs.target_triple == '' }} - name: Run benchmarks run: | - just bench-ci main ${{ matrix.hypervisor == 'mshv' && 'mshv2' || ''}} - if: ${{ matrix.config == 'release' }} + just bench-ci main ${{ inputs.hypervisor == 'mshv' && 'mshv2' || ''}} + if: ${{ inputs.config == 'release' && inputs.target_triple == '' }} From 31b2ad995b881359e8699468a4bf655da11dbf10 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Wed, 10 Sep 2025 22:58:17 +0000 Subject: [PATCH 212/271] Refactor CI failure and add to nightly job Signed-off-by: James Sturtevant --- .github/workflows/Fuzzing.yml | 2 +- .github/workflows/RustNightly.yml | 15 ++- dev/notify-ci-failure.sh | 169 ++++++++++++++++++++++++++++++ dev/notify-fuzzing-failure.sh | 153 --------------------------- 4 files changed, 184 insertions(+), 155 deletions(-) create mode 100755 dev/notify-ci-failure.sh delete mode 100755 dev/notify-fuzzing-failure.sh diff --git a/.github/workflows/Fuzzing.yml b/.github/workflows/Fuzzing.yml index a3c19778a..d586a659a 100644 --- a/.github/workflows/Fuzzing.yml +++ b/.github/workflows/Fuzzing.yml @@ -28,6 +28,6 @@ jobs: uses: actions/checkout@v5 - name: Notify Fuzzing Failure - run: ./dev/notify-fuzzing-failure.sh "fuzz_host_print,fuzz_guest_call,fuzz_host_call" + run: ./dev/notify-ci-failure.sh --labels="area/fuzzing,kind/bug,area/testing,lifecycle/needs-review" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/RustNightly.yml b/.github/workflows/RustNightly.yml index ad4604bad..fce399b31 100644 --- a/.github/workflows/RustNightly.yml +++ b/.github/workflows/RustNightly.yml @@ -5,6 +5,7 @@ name: Nightly on: workflow_dispatch: schedule: + # 12:00 AM, every 2 days - cron: '0 0 */2 * *' jobs: @@ -23,5 +24,17 @@ jobs: config: ${{ matrix.config }} target_triple: x86_64-unknown-linux-musl -# TODO: using notification script + notify-failure: + runs-on: ubuntu-latest + needs: musl + if: always() && needs.musl.result == 'failure' + permissions: + issues: write + steps: + - name: Checkout code + uses: actions/checkout@v5 + - name: Notify Nightly Failure + run: ./dev/notify-ci-failure.sh --title="Nightly musl Failure - ${{ github.run_number }}" --labels="area/ci-periodics,area/testing,kind/bug,lifecycle/needs-review" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/dev/notify-ci-failure.sh b/dev/notify-ci-failure.sh new file mode 100755 index 000000000..69be564c1 --- /dev/null +++ b/dev/notify-ci-failure.sh @@ -0,0 +1,169 @@ +#!/bin/bash +set -e +set -u +set -o pipefail + +## DESCRIPTION: +## +# Generic notifier for CI job failures that can create or update GitHub issues. +## This script creates or updates GitHub issues when a jobs fail. +## It checks for existing open failure issues and either creates +## a new one or adds a comment to an existing one. +## +## PRE-REQS: +## +## This script assumes that the gh cli is installed and in the PATH +## and that there is a GitHub PAT in the GITHUB_TOKEN env var +## with the following permissions: +## - issues (read/write) +## or that the user is logged into the gh cli with an account with those permissions +## +## Usage examples: +## ./dev/notify-fuzzing-failure.sh +## ./dev/notify-fuzzing-failure.sh --title="Nightly Failure" --labels="area/testing,kind/bug" +## ./dev/notify-fuzzing-failure.sh --test +## Run this script locally like: +## GITHUB_REPOSITORY="fork/hyperlight" GITHUB_RUN_ID=1 ./dev/notify-fuzzing-failure.sh --title="Nightly Failure" --labels="area/testing,kind/bug" + +REPO="${GITHUB_REPOSITORY:-hyperlight-dev/hyperlight}" +WORKFLOW_RUN_URL="${GITHUB_SERVER_URL:-https://github.com}/${REPO}/actions/runs/${GITHUB_RUN_ID:-unknown}" +TEST_MODE=false +ISSUE_TITLE="" +LABELS="area/testing,kind/bug,area/fuzzing,lifecycle/needs-review" + +for arg in "$@"; do + case $arg in + --test) + TEST_MODE=true + shift + ;; + --title=*) + ISSUE_TITLE="${arg#*=}" + shift + ;; + --labels=*) + LABELS="${arg#*=}" + shift + ;; + *) + esac +done + +# Normalize labels into an array +IFS=',' read -r -a LABEL_ARRAY <<< "$LABELS" + +# Choose a label to search existing issues for; prefer the first label if present +SEARCH_LABEL="${LABEL_ARRAY[0]:-area/fuzzing}" + +# Build issue title if not provided +if [ -z "$ISSUE_TITLE" ]; then + ISSUE_TITLE="Job Failure - $(date '+%Y-%m-%d')" +fi + + +if [ "$TEST_MODE" = true ]; then + echo "✅ Running in test mode - script structure is valid" + echo "Would check for issues in $REPO" + echo "Workflow URL would be: $WORKFLOW_RUN_URL" + echo "Issue Title would be: $ISSUE_TITLE" + echo "Labels would be: $LABELS" + echo "Search Label would be: $SEARCH_LABEL" + exit 0 +fi + +# Extract owner and repo name from the repository +OWNER=$(echo "$REPO" | cut -d'/' -f1) +REPO_NAME=$(echo "$REPO" | cut -d'/' -f2) + +echo "Checking for existing issues in $REPO with label '$SEARCH_LABEL'..." +EXISTING_ISSUES=$(gh api graphql -f query=' + query($owner: String!, $repo: String!, $label: String!) { + repository(owner: $owner, name: $repo) { + issues(first: 10, states: OPEN, labels: [$label]) { + totalCount + nodes { + number + title + url + labels(first: 20) { + nodes { + name + } + } + } + } + } + }' -f owner="$OWNER" -f repo="$REPO_NAME" -f label="$SEARCH_LABEL" --jq '.data.repository.issues') || EXISTING_ISSUES="" + +FUZZING_ISSUES=$(echo "$EXISTING_ISSUES" | jq '.nodes[]' 2>/dev/null || echo "") +FUZZING_ISSUE_COUNT=0 +if [ -n "$FUZZING_ISSUES" ]; then + FUZZING_ISSUE_COUNT=$(echo "$FUZZING_ISSUES" | jq -s 'length' 2>/dev/null || echo "0") +fi + +echo "Found $FUZZING_ISSUE_COUNT existing issue(s) matching label '$SEARCH_LABEL'" + +if [ "$FUZZING_ISSUE_COUNT" -gt 0 ]; then + ISSUE_NUMBER=$(echo "$FUZZING_ISSUES" | jq -r '.number' | head -1) + ISSUE_URL=$(echo "$FUZZING_ISSUES" | jq -r '.url' | head -1) + if [ "$ISSUE_NUMBER" = "null" ] || [ -z "$ISSUE_NUMBER" ]; then + echo "⚠️ Could not parse issue number from search results; will create a new issue" + FUZZING_ISSUE_COUNT=0 + else + echo "Adding comment to existing issue #$ISSUE_NUMBER" + COMMENT_BODY="## Job Failed Again + +**Date:** $(date '+%Y-%m-%d %H:%M:%S UTC') +**Workflow Run:** [$WORKFLOW_RUN_URL]($WORKFLOW_RUN_URL) + +The scheduled job has failed again. Please check the workflow logs and artifacts for details." + + if gh issue comment "$ISSUE_NUMBER" --body "$COMMENT_BODY" --repo "$REPO"; then + echo "✅ Added comment to existing issue #$ISSUE_NUMBER: $ISSUE_URL" + exit 0 + else + echo "❌ Failed to add comment to existing issue. Will attempt to create a new issue instead." + FUZZING_ISSUE_COUNT=0 + fi + fi +fi + +if [ "$FUZZING_ISSUE_COUNT" -eq 0 ]; then + echo "No existing matching issues found. Creating a new issue..." + + ISSUE_BODY="## Job Failure Report + +**Date:** $(date '+%Y-%m-%d %H:%M:%S UTC') +**Workflow Run:** [$WORKFLOW_RUN_URL]($WORKFLOW_RUN_URL) + +### Details +The scheduled job failed during execution. This issue was automatically created to track the failure. Please check the workflow logs and any uploaded artifacts for more details. + +### Next Steps +- [ ] Review the workflow logs for error details +- [ ] Download and analyze any crash artifacts if available +- [ ] Determine the root cause of the failure +- [ ] Fix the underlying issue + +--- +*This issue was automatically created by the CI failure notification system.*" + + # Build label args for gh issue create + LABEL_ARGS=() + for lbl in "${LABEL_ARRAY[@]}"; do + LABEL_ARGS+=("--label" "$lbl") + done + + if ISSUE_URL=$(gh issue create \ + --title "$ISSUE_TITLE" \ + --body "$ISSUE_BODY" \ + "${LABEL_ARGS[@]}" \ + --repo "$REPO"); then + echo "✅ Created new issue: $ISSUE_URL" + else + echo "❌ Failed to create new issue" + exit 1 + fi +fi + +echo "Notification script completed successfully" \ No newline at end of file diff --git a/dev/notify-fuzzing-failure.sh b/dev/notify-fuzzing-failure.sh deleted file mode 100755 index f4a6ac04f..000000000 --- a/dev/notify-fuzzing-failure.sh +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/bash -set -e -set -u -set -o pipefail - -## DESCRIPTION: -## -## This script creates or updates GitHub issues when fuzzing jobs fail. -## It checks for existing open fuzzing failure issues and either creates -## a new one or adds a comment to an existing one. -## -## PRE-REQS: -## -## This script assumes that the gh cli is installed and in the PATH -## and that there is a GitHub PAT in the GITHUB_TOKEN env var -## with the following permissions: -## - issues (read/write) -## or that the user is logged into the gh cli with an account with those permissions -## -## Run this script locally like: -## GITHUB_REPOSITORY="fork/hyperlight" GITHUB_RUN_ID=1 ./dev/notify-fuzzing-failure.sh "fuzz_host_print,fuzz_guest_call,fuzz_host_call" - -REPO="${GITHUB_REPOSITORY:-hyperlight-dev/hyperlight}" -WORKFLOW_RUN_URL="${GITHUB_SERVER_URL:-https://github.com}/${REPO}/actions/runs/${GITHUB_RUN_ID:-unknown}" -FUZZING_TARGETS="${1:-unknown}" - -# Check if running in test mode (handle both first and second arguments) -if [ "${1:-}" = "--test" ] || [ "${2:-}" = "--test" ]; then - echo "✅ Running in test mode - script structure is valid" - echo "Would check for fuzzing failure issues in $REPO" - echo "Would create issue or comment for fuzzing targets: ${1:-unknown}" - echo "Workflow URL would be: $WORKFLOW_RUN_URL" - exit 0 -fi - -echo "Checking for existing fuzzing failure issues in $REPO..." - -# Extract owner and repo name from the repository -OWNER=$(echo "$REPO" | cut -d'/' -f1) -REPO_NAME=$(echo "$REPO" | cut -d'/' -f2) - -# Define the issue title and labels -ISSUE_TITLE="Fuzzing Job Failure - $(date '+%Y-%m-%d')" -TESTING_LABEL="area/testing" -FAILURE_LABEL="kind/bug" -FUZZING_LABEL="area/fuzzing" -LIFECYCLE_LABEL="lifecycle/needs-review" - -# Search for existing open fuzzing failure issues -echo "Searching for existing open fuzzing failure issues..." -EXISTING_ISSUES=$(gh api graphql -f query=' - query($owner: String!, $repo: String!) { - repository(owner: $owner, name: $repo) { - issues(first: 10, states: OPEN, labels: ["area/fuzzing"]) { - totalCount - nodes { - number - title - url - labels(first: 20) { - nodes { - name - } - } - } - } - } - }' -f owner="$OWNER" -f repo="$REPO_NAME" --jq '.data.repository.issues') - -# Filter for fuzzing-related issues (now all results should be fuzzing issues due to label filter) -FUZZING_ISSUES=$(echo "$EXISTING_ISSUES" | jq '.nodes[]' 2>/dev/null || echo "") -FUZZING_ISSUE_COUNT=0 -if [ -n "$FUZZING_ISSUES" ]; then - FUZZING_ISSUE_COUNT=$(echo "$FUZZING_ISSUES" | jq -s 'length' 2>/dev/null || echo "0") -fi - -echo "Found $FUZZING_ISSUE_COUNT existing fuzzing failure issue(s)" - -if [ "$FUZZING_ISSUE_COUNT" -gt 0 ]; then - # Get the most recent fuzzing failure issue - ISSUE_NUMBER=$(echo "$FUZZING_ISSUES" | jq -r '.number' | head -1) - ISSUE_URL=$(echo "$FUZZING_ISSUES" | jq -r '.url' | head -1) - - if [ "$ISSUE_NUMBER" = "null" ] || [ -z "$ISSUE_NUMBER" ]; then - echo "⚠️ Could not parse issue number from fuzzing issues, creating new issue instead" - FUZZING_ISSUE_COUNT=0 - else - echo "Adding comment to existing issue #$ISSUE_NUMBER" - - # Create comment body - COMMENT_BODY="## Fuzzing Job Failed Again - -**Date:** $(date '+%Y-%m-%d %H:%M:%S UTC') -**Workflow Run:** [$WORKFLOW_RUN_URL]($WORKFLOW_RUN_URL) -**Fuzzing Targets:** $FUZZING_TARGETS - -The scheduled fuzzing job has failed again. Please check the workflow logs and artifacts for details." - - # Add comment to the existing issue - if gh issue comment "$ISSUE_NUMBER" --body "$COMMENT_BODY" --repo "$REPO"; then - echo "✅ Added comment to existing issue #$ISSUE_NUMBER: $ISSUE_URL" - else - echo "❌ Failed to add comment to existing issue. Creating new issue instead." - FUZZING_ISSUE_COUNT=0 - fi - fi -fi - -if [ "$FUZZING_ISSUE_COUNT" -eq 0 ]; then - echo "No existing fuzzing failure issues found. Creating new issue..." - - # Create issue body - ISSUE_BODY="## Fuzzing Job Failure Report - -**Date:** $(date '+%Y-%m-%d %H:%M:%S UTC') -**Workflow Run:** [$WORKFLOW_RUN_URL]($WORKFLOW_RUN_URL) -**Fuzzing Targets:** $FUZZING_TARGETS - -The scheduled fuzzing job has failed. This issue was automatically created to track the failure. - -### Details -The fuzzing workflow failed during execution. Please check the workflow logs and any uploaded artifacts for more details. - -### Next Steps -- [ ] Review the workflow logs for error details -- [ ] Download and analyze any crash artifacts if available -- [ ] Determine the root cause of the failure -- [ ] Fix the underlying issue - -### Related Documentation -- [Fuzzing README](https://github.com/$REPO/blob/main/fuzz/README.md) -- [Security Guidance](https://github.com/$REPO/blob/main/docs/security-guidance-for-developers.md) - ---- -*This issue was automatically created by the fuzzing failure notification system.*" - - # Create the new issue - if ISSUE_URL=$(gh issue create \ - --title "$ISSUE_TITLE" \ - --body "$ISSUE_BODY" \ - --label "$TESTING_LABEL" \ - --label "$FAILURE_LABEL" \ - --label "$FUZZING_LABEL" \ - --label "$LIFECYCLE_LABEL" \ - --repo "$REPO"); then - echo "✅ Created new fuzzing failure issue: $ISSUE_URL" - else - echo "❌ Failed to create new fuzzing failure issue" - exit 1 - fi -fi - -echo "Fuzzing failure notification completed successfully" \ No newline at end of file From 46d17c2453c657e81b30e130d57224a673d33b08 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Wed, 10 Sep 2025 23:23:28 +0000 Subject: [PATCH 213/271] Filter the location to a local path relative to the project this helps in ci when using the musl container which will end up with the wrong path Signed-off-by: James Sturtevant --- Justfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Justfile b/Justfile index 1c884f9fa..f0cb57a5c 100644 --- a/Justfile +++ b/Justfile @@ -209,6 +209,7 @@ test-rust-tracing target=default-target features="": # note that trace-dump doesn't run on MUSL target as of now TRACE_OUTPUT="$({{ cargo-cmd }} run --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --example hello-world --features {{ if features =="" {"trace_guest"} else { "trace_guest," + features } }})" && \ TRACE_FILE="$(echo "$TRACE_OUTPUT" | grep -oE 'Creating trace file at: [^ ]+' | awk -F': ' '{print $2}')" && \ + TRACE_FILE="$(echo "$TRACE_OUTPUT" | grep -oE 'Creating trace file at: [^ ]+' | awk -F': ' '{print $2}' | sed -E 's|^(trace/[^ ]+\.trace)$|./\1|; s|.*/(trace/[^ ]+\.trace)$|./\1|')" && \ echo "$TRACE_OUTPUT" && \ if [ -z "$TRACE_FILE" ]; then \ echo "Error: Could not extract trace file path from output." >&2 ; \ From d4d4b9a594df2268c2817967091cc9dc1dbe0ce3 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Fri, 12 Sep 2025 16:56:05 +0000 Subject: [PATCH 214/271] Update devcontainer with tools for musl Signed-off-by: James Sturtevant --- .devcontainer/Dockerfile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index d4191b5b2..8aef28cdd 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -22,7 +22,8 @@ RUN apt-get update \ make \ software-properties-common \ sudo \ - wget + wget \ + musl-tools ARG LLVM_VERSION=18 @@ -54,7 +55,9 @@ ARG RUST_TOOLCHAIN=1.89 RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \ && rustup default ${RUST_TOOLCHAIN} \ && rustup target add x86_64-unknown-linux-gnu \ + && rustup target add x86_64-unknown-linux-musl \ && rustup target add x86_64-unknown-none \ && rustup toolchain add nightly-x86_64-unknown-linux-gnu \ - && cargo install just - + && rustup toolchain add nightly-x86_64-unknown-linux-musl \ + && cargo install just \ + cargo install cross --locked --version 0.2.5 From 3cd8b26a22bade809a9372e3dd8d16ad829a2f93 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Mon, 29 Sep 2025 21:57:59 +0000 Subject: [PATCH 215/271] Add Release blocker label Signed-off-by: James Sturtevant --- .github/workflows/Fuzzing.yml | 2 +- .github/workflows/RustNightly.yml | 2 +- src/tests/rust_guests/simpleguest/Cargo.lock | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/Fuzzing.yml b/.github/workflows/Fuzzing.yml index d586a659a..006afe0b7 100644 --- a/.github/workflows/Fuzzing.yml +++ b/.github/workflows/Fuzzing.yml @@ -28,6 +28,6 @@ jobs: uses: actions/checkout@v5 - name: Notify Fuzzing Failure - run: ./dev/notify-ci-failure.sh --labels="area/fuzzing,kind/bug,area/testing,lifecycle/needs-review" + run: ./dev/notify-ci-failure.sh --labels="area/fuzzing,kind/bug,area/testing,lifecycle/needs-review,release-blocker" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/RustNightly.yml b/.github/workflows/RustNightly.yml index fce399b31..744a0f2f8 100644 --- a/.github/workflows/RustNightly.yml +++ b/.github/workflows/RustNightly.yml @@ -35,6 +35,6 @@ jobs: uses: actions/checkout@v5 - name: Notify Nightly Failure - run: ./dev/notify-ci-failure.sh --title="Nightly musl Failure - ${{ github.run_number }}" --labels="area/ci-periodics,area/testing,kind/bug,lifecycle/needs-review" + run: ./dev/notify-ci-failure.sh --title="Nightly musl Failure - ${{ github.run_number }}" --labels="area/ci-periodics,area/testing,kind/bug,lifecycle/needs-review,release-blocker" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index a327588e9..b9380c8e0 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -46,9 +46,9 @@ checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "flatbuffers" -version = "25.2.10" +version = "25.9.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1045398c1bfd89168b5fd3f1fc11f6e70b34f6f66300c87d44d3de849463abf1" +checksum = "09b6620799e7340ebd9968d2e0708eb82cf1971e9a16821e2091b6d6e475eed5" dependencies = [ "bitflags", "rustc_version", @@ -153,9 +153,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] From 2e5a751a8294dc93f1bd9bcf121797989d47f60e Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Tue, 30 Sep 2025 15:27:32 -0700 Subject: [PATCH 216/271] Pin to Debian 12 (bookworm) for Dev image and fix for Nightly (#923) * Pin to Debian 12 (bookworm) The Dev images jumped to trixie in the latest release which doesn't have some packages yet Signed-off-by: James Sturtevant * Add correct permissions for nightly job Signed-off-by: James Sturtevant --------- Signed-off-by: James Sturtevant --- .devcontainer/Dockerfile | 2 +- .github/workflows/RustNightly.yml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 8aef28cdd..d0e07cbee 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,6 +1,6 @@ ## Dockerfile for devcontainer -FROM mcr.microsoft.com/devcontainers/base:debian AS base +FROM mcr.microsoft.com/devcontainers/base:bookworm AS base ARG USER=vscode ARG GROUP=vscode diff --git a/.github/workflows/RustNightly.yml b/.github/workflows/RustNightly.yml index 744a0f2f8..71aad6dba 100644 --- a/.github/workflows/RustNightly.yml +++ b/.github/workflows/RustNightly.yml @@ -8,6 +8,10 @@ on: # 12:00 AM, every 2 days - cron: '0 0 */2 * *' +permissions: + id-token: write + contents: read + jobs: musl: strategy: From 43078f153fe9e8df81c2f9487da82b467e18d47b Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Tue, 30 Sep 2025 17:06:40 -0700 Subject: [PATCH 217/271] Fix dev container and labels for periodic failures (#925) Signed-off-by: James Sturtevant --- .devcontainer/Dockerfile | 3 +-- .github/workflows/Fuzzing.yml | 2 +- .github/workflows/RustNightly.yml | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index d0e07cbee..6006d0ce5 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -58,6 +58,5 @@ RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \ && rustup target add x86_64-unknown-linux-musl \ && rustup target add x86_64-unknown-none \ && rustup toolchain add nightly-x86_64-unknown-linux-gnu \ - && rustup toolchain add nightly-x86_64-unknown-linux-musl \ && cargo install just \ - cargo install cross --locked --version 0.2.5 + && cargo install cross --locked --version 0.2.5 diff --git a/.github/workflows/Fuzzing.yml b/.github/workflows/Fuzzing.yml index 006afe0b7..f1b96e0bb 100644 --- a/.github/workflows/Fuzzing.yml +++ b/.github/workflows/Fuzzing.yml @@ -28,6 +28,6 @@ jobs: uses: actions/checkout@v5 - name: Notify Fuzzing Failure - run: ./dev/notify-ci-failure.sh --labels="area/fuzzing,kind/bug,area/testing,lifecycle/needs-review,release-blocker" + run: ./dev/notify-ci-failure.sh --labels="area/fuzzing,area/testing,lifecycle/needs-review,release-blocker" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/RustNightly.yml b/.github/workflows/RustNightly.yml index 71aad6dba..ff5b1880e 100644 --- a/.github/workflows/RustNightly.yml +++ b/.github/workflows/RustNightly.yml @@ -39,6 +39,6 @@ jobs: uses: actions/checkout@v5 - name: Notify Nightly Failure - run: ./dev/notify-ci-failure.sh --title="Nightly musl Failure - ${{ github.run_number }}" --labels="area/ci-periodics,area/testing,kind/bug,lifecycle/needs-review,release-blocker" + run: ./dev/notify-ci-failure.sh --title="Nightly musl Failure - ${{ github.run_number }}" --labels="area/ci-periodics,area/testing,lifecycle/needs-review,release-blocker" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} From e30246934e25ff04c666ca87192f1a1fcfebbb7c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 09:39:43 -0700 Subject: [PATCH 218/271] Bump crate-ci/typos from 1.36.3 to 1.37.0 (#927) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.36.3 to 1.37.0. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.36.3...v1.37.0) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.37.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ValidatePullRequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index 726f73e80..d03c9e18b 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -74,7 +74,7 @@ jobs: steps: - uses: actions/checkout@v5 - name: Spell Check Repo - uses: crate-ci/typos@v1.36.3 + uses: crate-ci/typos@v1.37.0 license-headers: name: check license headers From 55cf38e5febba845ecabc612a33c76a0d1470ad6 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Wed, 1 Oct 2025 12:59:25 -0700 Subject: [PATCH 219/271] Install the latest gdb in cross (#929) Signed-off-by: James Sturtevant --- Cross.toml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Cross.toml b/Cross.toml index 7fa77eac0..da3c48089 100644 --- a/Cross.toml +++ b/Cross.toml @@ -1,9 +1,14 @@ [build] pre-build = [ - "apt-get update && apt-get -y install gdb" + "apt-get update && apt-get -y install wget build-essential libgmp-dev libmpfr-dev", + "cd /tmp && curl https://sourceware.org/pub/gdb/releases/gdb-16.3.tar.gz -o /tmp/gdb-16.3.tar.gz", + "cd /tmp && tar -xf gdb-16.3.tar.gz", + "cd /tmp/gdb-16.3 && ./configure --prefix=/usr/local", + "cd /tmp/gdb-16.3 && make -j$(nproc)", + "cd /tmp/gdb-16.3 && make install", ] [build.env] passthrough = [ "TARGET_TRIPLE", # Some tests invoke Cargo directly and need this to run correctly -] \ No newline at end of file +] From 28394fdad86678c18d990de6fdeb58f17503e809 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 07:42:06 +0000 Subject: [PATCH 220/271] Bump crate-ci/typos from 1.37.0 to 1.37.1 (#930) --- .github/workflows/ValidatePullRequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index d03c9e18b..ccd7a276b 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -74,7 +74,7 @@ jobs: steps: - uses: actions/checkout@v5 - name: Spell Check Repo - uses: crate-ci/typos@v1.37.0 + uses: crate-ci/typos@v1.37.1 license-headers: name: check license headers From 7647dcea60971780a4df483684810b70da2fdb7c Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Fri, 3 Oct 2025 14:12:33 -0700 Subject: [PATCH 221/271] Bump v0.10.0 in preparation for release (#932) * Bump version to 0.10.0 Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Update changelog for v0.10.0 Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --------- Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- CHANGELOG.md | 16 ++++++++++- Cargo.lock | 20 +++++++------- Cargo.toml | 18 ++++++------- src/tests/rust_guests/dummyguest/Cargo.lock | 24 ++++++++--------- src/tests/rust_guests/dummyguest/Cargo.toml | 2 +- src/tests/rust_guests/simpleguest/Cargo.lock | 12 ++++----- src/tests/rust_guests/simpleguest/Cargo.toml | 2 +- src/tests/rust_guests/witguest/Cargo.lock | 28 ++++++++++---------- src/tests/rust_guests/witguest/Cargo.toml | 2 +- src/trace_dump/Cargo.toml | 2 +- 10 files changed, 70 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a774369a4..084090a51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Prerelease] - Unreleased +## [v0.10.0] - 2025-10-02 + +### Fixed + +- Fix error code conversion for Exception enum TryFrom implementation by @vshailesh in https://github.com/hyperlight-dev/hyperlight/pull/869 +- Remove Allocations from Panic Handler by @adamperlin in https://github.com/hyperlight-dev/hyperlight/pull/818 + +### Changed + +- Update rust to 1.89 by @simongdavies in https://github.com/hyperlight-dev/hyperlight/pull/883 +- Update mshv crates for Azure Linux to v0.6.1 (from v0.3.2) by @simongdavies in https://github.com/hyperlight-dev/hyperlight/pull/891 +- Only clear io buffer after unsuccessful guest call by @ludfjig in https://github.com/hyperlight-dev/hyperlight/pull/811 + ## [v0.9.0] - 2025-08-28 ### Fixed @@ -188,7 +201,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). The Initial Hyperlight Release 🎉 -[Prerelease]: +[Prerelease]: +[v0.10.0]: [v0.9.0]: [v0.8.0]: [v0.7.0]: diff --git a/Cargo.lock b/Cargo.lock index 0456cba83..2adb00180 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1344,7 +1344,7 @@ dependencies = [ [[package]] name = "hyperlight-common" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "arbitrary", @@ -1357,7 +1357,7 @@ dependencies = [ [[package]] name = "hyperlight-component-macro" -version = "0.9.0" +version = "0.10.0" dependencies = [ "env_logger", "hyperlight-component-util", @@ -1371,7 +1371,7 @@ dependencies = [ [[package]] name = "hyperlight-component-util" -version = "0.9.0" +version = "0.10.0" dependencies = [ "itertools 0.14.0", "log", @@ -1393,7 +1393,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "flatbuffers", @@ -1404,7 +1404,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.9.0" +version = "0.10.0" dependencies = [ "buddy_system_allocator", "cc", @@ -1419,7 +1419,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing" -version = "0.9.0" +version = "0.10.0" dependencies = [ "hyperlight-common", "hyperlight-guest-tracing-macro", @@ -1428,7 +1428,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing-macro" -version = "0.9.0" +version = "0.10.0" dependencies = [ "proc-macro2", "quote", @@ -1437,7 +1437,7 @@ dependencies = [ [[package]] name = "hyperlight-host" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "bitflags 2.9.4", @@ -1527,7 +1527,7 @@ dependencies = [ [[package]] name = "hyperlight_guest_capi" -version = "0.9.0" +version = "0.10.0" dependencies = [ "cbindgen", "hyperlight-common", @@ -3584,7 +3584,7 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "trace_dump" -version = "0.9.0" +version = "0.10.0" dependencies = [ "addr2line 0.25.1", "blake3", diff --git a/Cargo.toml b/Cargo.toml index dcf5f8f7b..7e8133bcf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ exclude = [ ] [workspace.package] -version = "0.9.0" +version = "0.10.0" edition = "2024" rust-version = "1.88" license = "Apache-2.0" @@ -36,15 +36,15 @@ repository = "https://github.com/hyperlight-dev/hyperlight" readme = "README.md" [workspace.dependencies] -hyperlight-common = { path = "src/hyperlight_common", version = "0.9.0", default-features = false } -hyperlight-host = { path = "src/hyperlight_host", version = "0.9.0", default-features = false } -hyperlight-guest = { path = "src/hyperlight_guest", version = "0.9.0", default-features = false } -hyperlight-guest-bin = { path = "src/hyperlight_guest_bin", version = "0.9.0", default-features = false } +hyperlight-common = { path = "src/hyperlight_common", version = "0.10.0", default-features = false } +hyperlight-host = { path = "src/hyperlight_host", version = "0.10.0", default-features = false } +hyperlight-guest = { path = "src/hyperlight_guest", version = "0.10.0", default-features = false } +hyperlight-guest-bin = { path = "src/hyperlight_guest_bin", version = "0.10.0", default-features = false } hyperlight-testing = { path = "src/hyperlight_testing", default-features = false } -hyperlight-guest-tracing = { path = "src/hyperlight_guest_tracing", version = "0.9.0", default-features = false } -hyperlight-guest-tracing-macro = { path = "src/hyperlight_guest_tracing_macro", version = "0.9.0", default-features = false } -hyperlight-component-util = { path = "src/hyperlight_component_util", version = "0.9.0", default-features = false } -hyperlight-component-macro = { path = "src/hyperlight_component_macro", version = "0.9.0", default-features = false } +hyperlight-guest-tracing = { path = "src/hyperlight_guest_tracing", version = "0.10.0", default-features = false } +hyperlight-guest-tracing-macro = { path = "src/hyperlight_guest_tracing_macro", version = "0.10.0", default-features = false } +hyperlight-component-util = { path = "src/hyperlight_component_util", version = "0.10.0", default-features = false } +hyperlight-component-macro = { path = "src/hyperlight_component_macro", version = "0.10.0", default-features = false } [workspace.lints.rust] unsafe_op_in_unsafe_fn = "deny" diff --git a/src/tests/rust_guests/dummyguest/Cargo.lock b/src/tests/rust_guests/dummyguest/Cargo.lock index fa3de189b..12437e491 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.lock +++ b/src/tests/rust_guests/dummyguest/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "autocfg" @@ -46,7 +46,7 @@ checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "dummyguest" -version = "0.9.0" +version = "0.10.0" dependencies = [ "hyperlight-common", "hyperlight-guest-bin", @@ -54,9 +54,9 @@ dependencies = [ [[package]] name = "flatbuffers" -version = "25.2.10" +version = "25.9.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1045398c1bfd89168b5fd3f1fc11f6e70b34f6f66300c87d44d3de849463abf1" +checksum = "09b6620799e7340ebd9968d2e0708eb82cf1971e9a16821e2091b6d6e475eed5" dependencies = [ "bitflags", "rustc_version", @@ -70,7 +70,7 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hyperlight-common" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "flatbuffers", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "flatbuffers", @@ -91,7 +91,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.9.0" +version = "0.10.0" dependencies = [ "buddy_system_allocator", "cc", @@ -106,7 +106,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing" -version = "0.9.0" +version = "0.10.0" dependencies = [ "hyperlight-common", "hyperlight-guest-tracing-macro", @@ -115,7 +115,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing-macro" -version = "0.9.0" +version = "0.10.0" dependencies = [ "proc-macro2", "quote", @@ -161,9 +161,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] diff --git a/src/tests/rust_guests/dummyguest/Cargo.toml b/src/tests/rust_guests/dummyguest/Cargo.toml index 9a35944ec..6c39889b1 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.toml +++ b/src/tests/rust_guests/dummyguest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dummyguest" -version = "0.9.0" +version = "0.10.0" edition = "2021" diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index b9380c8e0..5f9e34407 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -62,7 +62,7 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hyperlight-common" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "flatbuffers", @@ -72,7 +72,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "flatbuffers", @@ -83,7 +83,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.9.0" +version = "0.10.0" dependencies = [ "buddy_system_allocator", "cc", @@ -98,7 +98,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing" -version = "0.9.0" +version = "0.10.0" dependencies = [ "hyperlight-common", "hyperlight-guest-tracing-macro", @@ -107,7 +107,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing-macro" -version = "0.9.0" +version = "0.10.0" dependencies = [ "proc-macro2", "quote", @@ -227,7 +227,7 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "simpleguest" -version = "0.9.0" +version = "0.10.0" dependencies = [ "hyperlight-common", "hyperlight-guest", diff --git a/src/tests/rust_guests/simpleguest/Cargo.toml b/src/tests/rust_guests/simpleguest/Cargo.toml index 34925b9fc..7700a0758 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.toml +++ b/src/tests/rust_guests/simpleguest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "simpleguest" -version = "0.9.0" +version = "0.10.0" edition = "2021" [dependencies] diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index 6a33cb503..8ab31004c 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -63,9 +63,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "autocfg" @@ -146,9 +146,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "flatbuffers" -version = "25.2.10" +version = "25.9.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1045398c1bfd89168b5fd3f1fc11f6e70b34f6f66300c87d44d3de849463abf1" +checksum = "09b6620799e7340ebd9968d2e0708eb82cf1971e9a16821e2091b6d6e475eed5" dependencies = [ "bitflags", "rustc_version", @@ -178,7 +178,7 @@ dependencies = [ [[package]] name = "hyperlight-common" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "flatbuffers", @@ -188,7 +188,7 @@ dependencies = [ [[package]] name = "hyperlight-component-macro" -version = "0.9.0" +version = "0.10.0" dependencies = [ "env_logger", "hyperlight-component-util", @@ -202,7 +202,7 @@ dependencies = [ [[package]] name = "hyperlight-component-util" -version = "0.9.0" +version = "0.10.0" dependencies = [ "itertools", "log", @@ -215,7 +215,7 @@ dependencies = [ [[package]] name = "hyperlight-guest" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "flatbuffers", @@ -226,7 +226,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-bin" -version = "0.9.0" +version = "0.10.0" dependencies = [ "buddy_system_allocator", "cc", @@ -241,7 +241,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing" -version = "0.9.0" +version = "0.10.0" dependencies = [ "hyperlight-common", "hyperlight-guest-tracing-macro", @@ -250,7 +250,7 @@ dependencies = [ [[package]] name = "hyperlight-guest-tracing-macro" -version = "0.9.0" +version = "0.10.0" dependencies = [ "proc-macro2", "quote", @@ -377,9 +377,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -614,7 +614,7 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "witguest" -version = "0.9.0" +version = "0.10.0" dependencies = [ "hyperlight-common", "hyperlight-component-macro", diff --git a/src/tests/rust_guests/witguest/Cargo.toml b/src/tests/rust_guests/witguest/Cargo.toml index 82f87b9f5..fbdb6b15e 100644 --- a/src/tests/rust_guests/witguest/Cargo.toml +++ b/src/tests/rust_guests/witguest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "witguest" -version = "0.9.0" +version = "0.10.0" edition = "2021" [dependencies] diff --git a/src/trace_dump/Cargo.toml b/src/trace_dump/Cargo.toml index f98c2c251..d72631198 100644 --- a/src/trace_dump/Cargo.toml +++ b/src/trace_dump/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "trace_dump" -version = "0.9.0" +version = "0.10.0" publish = false edition = "2021" From 728da7c3f3d33b980887eadd181e864944f9b0fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 04:05:08 +0000 Subject: [PATCH 222/271] Bump goblin from 0.10.1 to 0.10.2 (#936) Bumps [goblin](https://github.com/m4b/goblin) from 0.10.1 to 0.10.2. - [Changelog](https://github.com/m4b/goblin/blob/master/CHANGELOG.md) - [Commits](https://github.com/m4b/goblin/commits) --- updated-dependencies: - dependency-name: goblin dependency-version: 0.10.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2adb00180..ac630593e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1216,9 +1216,9 @@ dependencies = [ [[package]] name = "goblin" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6a80adfd63bd7ffd94fefc3d22167880c440a724303080e5aa686fa36abaa96" +checksum = "7be320f077239a0361c20d608b4768c62a1b77aa4946dd76395aa4cd502cba7d" dependencies = [ "log", "plain", From 494a5a256686c93467460b3aa31c59b70e01dc26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 04:05:14 +0000 Subject: [PATCH 223/271] Bump cc from 1.2.39 to 1.2.40 (#935) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.39 to 1.2.40. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.39...cc-v1.2.40) --- updated-dependencies: - dependency-name: cc dependency-version: 1.2.40 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac630593e..302b6311d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,9 +362,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.39" +version = "1.2.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" +checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" dependencies = [ "find-msvc-tools", "jobserver", @@ -835,9 +835,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" [[package]] name = "flatbuffers" From 5c3e80d067b8f8e0625ece1db2d47542ee188190 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 09:04:12 -0700 Subject: [PATCH 224/271] Bump crate-ci/typos from 1.37.1 to 1.37.2 (#934) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.37.1 to 1.37.2. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.37.1...v1.37.2) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.37.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ValidatePullRequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index ccd7a276b..46033261d 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -74,7 +74,7 @@ jobs: steps: - uses: actions/checkout@v5 - name: Spell Check Repo - uses: crate-ci/typos@v1.37.1 + uses: crate-ci/typos@v1.37.2 license-headers: name: check license headers From f964525673547318df62563f360e3087f6e1e37b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 04:16:17 +0000 Subject: [PATCH 225/271] Bump windows-sys from 0.61.1 to 0.61.2 (#939) Bumps [windows-sys](https://github.com/microsoft/windows-rs) from 0.61.1 to 0.61.2. - [Release notes](https://github.com/microsoft/windows-rs/releases) - [Commits](https://github.com/microsoft/windows-rs/commits) --- updated-dependencies: - dependency-name: windows-sys dependency-version: 0.61.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 302b6311d..793f5c733 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -413,7 +413,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -703,7 +703,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.1", + "windows-sys 0.60.2", ] [[package]] @@ -1506,7 +1506,7 @@ dependencies = [ "vmm-sys-util", "windows 0.62.1", "windows-result 0.4.0", - "windows-sys 0.61.1", + "windows-sys 0.61.2", "windows-version", ] @@ -3352,7 +3352,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.61.1", + "windows-sys 0.60.2", ] [[package]] @@ -4150,7 +4150,7 @@ checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.2.0", + "windows-link 0.2.1", "windows-result 0.4.0", "windows-strings 0.5.0", ] @@ -4173,7 +4173,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68f3db6b24b120200d649cd4811b4947188ed3a8d2626f7075146c5d178a9a4a" dependencies = [ "windows-core 0.62.1", - "windows-link 0.2.0", + "windows-link 0.2.1", "windows-threading 0.2.0", ] @@ -4207,9 +4207,9 @@ checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-numerics" @@ -4228,7 +4228,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ce3498fe0aba81e62e477408383196b4b0363db5e0c27646f932676283b43d8" dependencies = [ "windows-core 0.62.1", - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -4246,7 +4246,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -4264,7 +4264,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -4296,11 +4296,11 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.61.1" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -4351,7 +4351,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab47f085ad6932defa48855254c758cdd0e2f2d48e62a34118a268d8f345e118" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -4360,7 +4360,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "700dad7c058606087f6fdc1f88da5841e06da40334413c6cd4367b25ef26d24e" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] From 353009138fe7c36b140df2f09ecf5027e6c3bf69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 09:34:37 -0700 Subject: [PATCH 226/271] Bump crate-ci/typos from 1.37.2 to 1.38.0 (#938) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.37.2 to 1.38.0. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.37.2...v1.38.0) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.38.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ValidatePullRequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index 46033261d..ae05e5fd0 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -74,7 +74,7 @@ jobs: steps: - uses: actions/checkout@v5 - name: Spell Check Repo - uses: crate-ci/typos@v1.37.2 + uses: crate-ci/typos@v1.38.0 license-headers: name: check license headers From e5e10a3ac10b6971134eb7b523b614a8dd3a9e7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 04:05:12 +0000 Subject: [PATCH 227/271] Bump windows-result from 0.4.0 to 0.4.1 (#942) Bumps [windows-result](https://github.com/microsoft/windows-rs) from 0.4.0 to 0.4.1. - [Release notes](https://github.com/microsoft/windows-rs/releases) - [Commits](https://github.com/microsoft/windows-rs/commits) --- updated-dependencies: - dependency-name: windows-result dependency-version: 0.4.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 793f5c733..0efabc6e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -703,7 +703,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1505,7 +1505,7 @@ dependencies = [ "uuid", "vmm-sys-util", "windows 0.62.1", - "windows-result 0.4.0", + "windows-result 0.4.1", "windows-sys 0.61.2", "windows-version", ] @@ -3352,7 +3352,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4151,7 +4151,7 @@ dependencies = [ "windows-implement", "windows-interface", "windows-link 0.2.1", - "windows-result 0.4.0", + "windows-result 0.4.1", "windows-strings 0.5.0", ] @@ -4242,9 +4242,9 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link 0.2.1", ] From 3b707ec5b1a0d8c8961e72b387c80e71c4074899 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 04:05:29 +0000 Subject: [PATCH 228/271] Bump windows-version from 0.1.6 to 0.1.7 (#940) Bumps [windows-version](https://github.com/microsoft/windows-rs) from 0.1.6 to 0.1.7. - [Release notes](https://github.com/microsoft/windows-rs/releases) - [Commits](https://github.com/microsoft/windows-rs/commits) --- updated-dependencies: - dependency-name: windows-version dependency-version: 0.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0efabc6e8..e0b04af0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4356,9 +4356,9 @@ dependencies = [ [[package]] name = "windows-version" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "700dad7c058606087f6fdc1f88da5841e06da40334413c6cd4367b25ef26d24e" +checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" dependencies = [ "windows-link 0.2.1", ] From 8ad812eee5a37236deea89d138429d12ce4bb2c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 15:38:55 +0300 Subject: [PATCH 229/271] Bump crate-ci/typos from 1.38.0 to 1.38.1 (#945) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.38.0 to 1.38.1. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.38.0...v1.38.1) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.38.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ValidatePullRequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index ae05e5fd0..0a00bbb8e 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -74,7 +74,7 @@ jobs: steps: - uses: actions/checkout@v5 - name: Spell Check Repo - uses: crate-ci/typos@v1.38.0 + uses: crate-ci/typos@v1.38.1 license-headers: name: check license headers From 813527111580a0504c2f031126c212bc76760d73 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Wed, 8 Oct 2025 16:25:13 -0700 Subject: [PATCH 230/271] Restructure guest/host error handling (#868) * Add test that fails due memory leaking when host function error occurs Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Update FlatBuffer schema and generation process - Add all.fbs to include all schema files in one place - Restructure function_call_result.fbs to use Result-like union - Add HostError variant to ErrorCode enum in guest_error.fbs - Update flatbuffer generation command in Justfile to use all.fbs - Update documentation for new generation process Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Regenerate FlatBuffer generated code Update all generated Rust code based on the new schema definitions. This includes new types for error handling and result structures. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Refactor error handling types and utilities - Update function_types.rs to handle Result-like return values - Simplify guest_error.rs wrapper implementation - Update util.rs for new generated types - Update mod.rs for new generated types Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Remove obsolete guest error handling - Remove guest_err.rs from hyperlight_host (replaced by new error handling) - Remove guest_err.rs from hyperlight_guest_bin (replaced by new error handling) - Update func/mod.rs to remove obsolete import Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Update host-side error handling - Update initialized_multi_use.rs to use new Result-like error handling - Update mem/mgr.rs to handle host function errors properly - Update sandbox/outb.rs for new error propagation pattern Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Update guest-side error handling - Update guest/host_comm.rs to use new Result-like return values - Update guest_bin/call.rs to properly handle host function errors - Update guest_bin/lib.rs to remove obsolete error handling import and make GUEST_HANDLE public (for use in C-API) - Update guest_capi/error.rs to support new error types Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Fix up test to work with new error handling Update sandbox_host_tests.rs to use the new Result-like error handling pattern. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Update Cargo dependencies Update Cargo.lock and Cargo.toml files to reflect the dependency changes needed for the new error handling implementation. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Fix test so it passes Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * First round of PR feedback Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Unignore forgotten test Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Update flatc version in docs Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --------- Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- Cargo.lock | 2 + Justfile | 2 +- docs/how-to-use-flatbuffers.md | 8 +- .../src/flatbuffer_wrappers/function_types.rs | 423 ++++++++++++---- .../src/flatbuffer_wrappers/guest_error.rs | 51 +- .../src/flatbuffer_wrappers/util.rs | 171 ++++--- .../generated/error_code_generated.rs | 10 +- .../generated/function_call_generated.rs | 77 --- .../function_call_result_generated.rs | 426 +++-------------- .../function_call_result_type_generated.rs | 110 +++++ .../generated/guest_error_generated.rs | 77 --- .../generated/guest_log_data_generated.rs | 77 --- .../host_function_definition_generated.rs | 85 ---- .../host_function_details_generated.rs | 81 ---- .../generated/return_value_box_generated.rs | 451 ++++++++++++++++++ src/hyperlight_common/src/flatbuffers/mod.rs | 33 +- .../src/guest_handle/host_comm.rs | 50 +- src/hyperlight_guest_bin/Cargo.toml | 2 + src/hyperlight_guest_bin/src/guest_err.rs | 45 -- .../src/guest_function/call.rs | 32 +- src/hyperlight_guest_bin/src/lib.rs | 3 +- src/hyperlight_guest_capi/Cargo.toml | 2 + src/hyperlight_guest_capi/src/error.rs | 25 +- src/hyperlight_host/src/func/guest_err.rs | 50 -- src/hyperlight_host/src/func/mod.rs | 2 - src/hyperlight_host/src/mem/mgr.rs | 36 +- .../src/sandbox/initialized_multi_use.rs | 71 ++- src/hyperlight_host/src/sandbox/outb.rs | 12 +- .../tests/sandbox_host_tests.rs | 15 +- src/schema/all.fbs | 7 + src/schema/function_call_result.fbs | 14 +- src/schema/guest_error.fbs | 3 +- src/tests/rust_guests/dummyguest/Cargo.lock | 1 + src/tests/rust_guests/simpleguest/Cargo.lock | 1 + src/tests/rust_guests/simpleguest/src/main.rs | 36 ++ src/tests/rust_guests/witguest/Cargo.lock | 1 + 36 files changed, 1330 insertions(+), 1162 deletions(-) create mode 100644 src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_result_type_generated.rs create mode 100644 src/hyperlight_common/src/flatbuffers/hyperlight/generated/return_value_box_generated.rs delete mode 100644 src/hyperlight_guest_bin/src/guest_err.rs delete mode 100644 src/hyperlight_host/src/func/guest_err.rs create mode 100644 src/schema/all.fbs diff --git a/Cargo.lock b/Cargo.lock index e0b04af0a..9491f3183 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1409,6 +1409,7 @@ dependencies = [ "buddy_system_allocator", "cc", "cfg-if", + "flatbuffers", "glob", "hyperlight-common", "hyperlight-guest", @@ -1530,6 +1531,7 @@ name = "hyperlight_guest_capi" version = "0.10.0" dependencies = [ "cbindgen", + "flatbuffers", "hyperlight-common", "hyperlight-guest", "hyperlight-guest-bin", diff --git a/Justfile b/Justfile index f0cb57a5c..ac664c72a 100644 --- a/Justfile +++ b/Justfile @@ -372,7 +372,7 @@ build-fuzzer fuzz-target: ################### gen-all-fbs-rust-code: - for fbs in `find src -name "*.fbs"`; do flatc -r --rust-module-root-file --gen-all -o ./src/hyperlight_common/src/flatbuffers/ $fbs; done + flatc --rust --rust-module-root-file --gen-all -o ./src/hyperlight_common/src/flatbuffers/ ./src/schema/all.fbs just fmt-apply install-vcpkg: diff --git a/docs/how-to-use-flatbuffers.md b/docs/how-to-use-flatbuffers.md index dc26b58c7..c541b0406 100644 --- a/docs/how-to-use-flatbuffers.md +++ b/docs/how-to-use-flatbuffers.md @@ -1,6 +1,6 @@ # How to use FlatBuffers -> Note: the last generation of the flatbuffer code was with done with flatc version 25.2.10 (i.e., the last version as of May 1st, 2025). +> Note: the last generation of the flatbuffer code was with done with flatc version 25.9.23 (i.e., the last version as of Oct 2nd, 2025). Flatbuffers is used to serialize and deserialize some data structures. @@ -19,9 +19,3 @@ We recommend building `flatc` from source. To generate rust code, use ```console just gen-all-fbs-rust-code ``` - -### Note about generated code - -Because we invoke `flatc` multiple times when generating the Rust code, the `mod.rs` generated in `./src/hyperlight_common/src/flatbuffers` is overwritten multiple times and will likely be incorrect. Make sure to manually inspect and if necessary update this file before continuing with your changes as certain modules might be missing. After fixing `mod.rs`, you might need to re-run `just fmt`, since it might not have applied to all generated files if your `mod.rs` was invalid. - ->`flatc` does support passing multiple schema files (e.g. it is possible to pass `.\src\schema\*.fbs`), so we could regenerate all the files each time a change was made, however that generates incorrect code (see [here](https://github.com/google/flatbuffers/issues/6800) for details). diff --git a/src/hyperlight_common/src/flatbuffer_wrappers/function_types.rs b/src/hyperlight_common/src/flatbuffer_wrappers/function_types.rs index 16bd91bc0..42c7ff823 100644 --- a/src/hyperlight_common/src/flatbuffer_wrappers/function_types.rs +++ b/src/hyperlight_common/src/flatbuffer_wrappers/function_types.rs @@ -22,15 +22,166 @@ use flatbuffers::size_prefixed_root; #[cfg(feature = "tracing")] use tracing::{Span, instrument}; +use super::guest_error::GuestError; use crate::flatbuffers::hyperlight::generated::{ FunctionCallResult as FbFunctionCallResult, FunctionCallResultArgs as FbFunctionCallResultArgs, - Parameter, ParameterType as FbParameterType, ParameterValue as FbParameterValue, - ReturnType as FbReturnType, ReturnValue as FbReturnValue, hlbool, hlboolArgs, hldouble, - hldoubleArgs, hlfloat, hlfloatArgs, hlint, hlintArgs, hllong, hllongArgs, hlsizeprefixedbuffer, + FunctionCallResultType, Parameter, ParameterType as FbParameterType, + ParameterValue as FbParameterValue, ReturnType as FbReturnType, ReturnValue as FbReturnValue, + ReturnValueBox, ReturnValueBoxArgs, hlbool, hlboolArgs, hldouble, hldoubleArgs, hlfloat, + hlfloatArgs, hlint, hlintArgs, hllong, hllongArgs, hlsizeprefixedbuffer, hlsizeprefixedbufferArgs, hlstring, hlstringArgs, hluint, hluintArgs, hlulong, hlulongArgs, hlvoid, hlvoidArgs, }; +pub struct FunctionCallResult(core::result::Result); + +impl FunctionCallResult { + /// Encodes self into the given builder and returns the encoded data. + /// + /// # Notes + /// + /// The builder should not be reused after a call to encode, since this function + /// does not reset the state of the builder. If you want to reuse the builder, + /// you'll need to reset it first. + pub fn encode<'a>(&self, builder: &'a mut flatbuffers::FlatBufferBuilder) -> &'a [u8] { + match &self.0 { + Ok(rv) => { + // Encode ReturnValue as ReturnValueBox + let (value, value_type) = match rv { + ReturnValue::Int(i) => { + let off = hlint::create(builder, &hlintArgs { value: *i }); + (Some(off.as_union_value()), FbReturnValue::hlint) + } + ReturnValue::UInt(ui) => { + let off = hluint::create(builder, &hluintArgs { value: *ui }); + (Some(off.as_union_value()), FbReturnValue::hluint) + } + ReturnValue::Long(l) => { + let off = hllong::create(builder, &hllongArgs { value: *l }); + (Some(off.as_union_value()), FbReturnValue::hllong) + } + ReturnValue::ULong(ul) => { + let off = hlulong::create(builder, &hlulongArgs { value: *ul }); + (Some(off.as_union_value()), FbReturnValue::hlulong) + } + ReturnValue::Float(f) => { + let off = hlfloat::create(builder, &hlfloatArgs { value: *f }); + (Some(off.as_union_value()), FbReturnValue::hlfloat) + } + ReturnValue::Double(d) => { + let off = hldouble::create(builder, &hldoubleArgs { value: *d }); + (Some(off.as_union_value()), FbReturnValue::hldouble) + } + ReturnValue::Bool(b) => { + let off = hlbool::create(builder, &hlboolArgs { value: *b }); + (Some(off.as_union_value()), FbReturnValue::hlbool) + } + ReturnValue::String(s) => { + let val = builder.create_string(s.as_str()); + let off = hlstring::create(builder, &hlstringArgs { value: Some(val) }); + (Some(off.as_union_value()), FbReturnValue::hlstring) + } + ReturnValue::VecBytes(v) => { + let val = builder.create_vector(v); + let off = hlsizeprefixedbuffer::create( + builder, + &hlsizeprefixedbufferArgs { + value: Some(val), + size: v.len() as i32, + }, + ); + ( + Some(off.as_union_value()), + FbReturnValue::hlsizeprefixedbuffer, + ) + } + ReturnValue::Void(()) => { + let off = hlvoid::create(builder, &hlvoidArgs {}); + (Some(off.as_union_value()), FbReturnValue::hlvoid) + } + }; + let rv_box = + ReturnValueBox::create(builder, &ReturnValueBoxArgs { value, value_type }); + let fcr = FbFunctionCallResult::create( + builder, + &FbFunctionCallResultArgs { + result: Some(rv_box.as_union_value()), + result_type: FunctionCallResultType::ReturnValueBox, + }, + ); + builder.finish_size_prefixed(fcr, None); + builder.finished_data() + } + Err(ge) => { + // Encode GuestError + let code: crate::flatbuffers::hyperlight::generated::ErrorCode = ge.code.into(); + let msg = builder.create_string(&ge.message); + let guest_error = crate::flatbuffers::hyperlight::generated::GuestError::create( + builder, + &crate::flatbuffers::hyperlight::generated::GuestErrorArgs { + code, + message: Some(msg), + }, + ); + let fcr = FbFunctionCallResult::create( + builder, + &FbFunctionCallResultArgs { + result: Some(guest_error.as_union_value()), + result_type: FunctionCallResultType::GuestError, + }, + ); + builder.finish_size_prefixed(fcr, None); + builder.finished_data() + } + } + } + pub fn new(value: core::result::Result) -> Self { + FunctionCallResult(value) + } + + pub fn into_inner(self) -> core::result::Result { + self.0 + } +} + +impl TryFrom<&[u8]> for FunctionCallResult { + type Error = Error; + + fn try_from(value: &[u8]) -> Result { + let function_call_result_fb = size_prefixed_root::(value) + .map_err(|e| anyhow!("Failed to get FunctionCallResult from bytes: {:?}", e))?; + + match function_call_result_fb.result_type() { + FunctionCallResultType::ReturnValueBox => { + let boxed = function_call_result_fb + .result_as_return_value_box() + .ok_or_else(|| { + anyhow!("Failed to get ReturnValueBox from function call result") + })?; + let return_value = ReturnValue::try_from(boxed)?; + Ok(FunctionCallResult(Ok(return_value))) + } + FunctionCallResultType::GuestError => { + let guest_error_table = function_call_result_fb + .result_as_guest_error() + .ok_or_else(|| anyhow!("Failed to get GuestError from function call result"))?; + let code = guest_error_table.code(); + let message = guest_error_table + .message() + .map(|s| s.to_string()) + .unwrap_or_default(); + Ok(FunctionCallResult(Err(GuestError::new( + code.into(), + message, + )))) + } + other => { + bail!("Unexpected function call result type: {:?}", other) + } + } + } +} + /// Supported parameter types with values for function calling. #[cfg_attr(feature = "fuzzing", derive(arbitrary::Arbitrary))] #[derive(Debug, Clone, PartialEq)] @@ -516,55 +667,55 @@ impl TryFrom for () { } } -impl TryFrom> for ReturnValue { +impl TryFrom> for ReturnValue { type Error = Error; #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))] - fn try_from(function_call_result_fb: FbFunctionCallResult<'_>) -> Result { - match function_call_result_fb.return_value_type() { + fn try_from(return_value_box: ReturnValueBox<'_>) -> Result { + match return_value_box.value_type() { FbReturnValue::hlint => { - let hlint = function_call_result_fb - .return_value_as_hlint() + let hlint = return_value_box + .value_as_hlint() .ok_or_else(|| anyhow!("Failed to get hlint from return value"))?; Ok(ReturnValue::Int(hlint.value())) } FbReturnValue::hluint => { - let hluint = function_call_result_fb - .return_value_as_hluint() + let hluint = return_value_box + .value_as_hluint() .ok_or_else(|| anyhow!("Failed to get hluint from return value"))?; Ok(ReturnValue::UInt(hluint.value())) } FbReturnValue::hllong => { - let hllong = function_call_result_fb - .return_value_as_hllong() + let hllong = return_value_box + .value_as_hllong() .ok_or_else(|| anyhow!("Failed to get hllong from return value"))?; Ok(ReturnValue::Long(hllong.value())) } FbReturnValue::hlulong => { - let hlulong = function_call_result_fb - .return_value_as_hlulong() + let hlulong = return_value_box + .value_as_hlulong() .ok_or_else(|| anyhow!("Failed to get hlulong from return value"))?; Ok(ReturnValue::ULong(hlulong.value())) } FbReturnValue::hlfloat => { - let hlfloat = function_call_result_fb - .return_value_as_hlfloat() + let hlfloat = return_value_box + .value_as_hlfloat() .ok_or_else(|| anyhow!("Failed to get hlfloat from return value"))?; Ok(ReturnValue::Float(hlfloat.value())) } FbReturnValue::hldouble => { - let hldouble = function_call_result_fb - .return_value_as_hldouble() + let hldouble = return_value_box + .value_as_hldouble() .ok_or_else(|| anyhow!("Failed to get hldouble from return value"))?; Ok(ReturnValue::Double(hldouble.value())) } FbReturnValue::hlbool => { - let hlbool = function_call_result_fb - .return_value_as_hlbool() + let hlbool = return_value_box + .value_as_hlbool() .ok_or_else(|| anyhow!("Failed to get hlbool from return value"))?; Ok(ReturnValue::Bool(hlbool.value())) } FbReturnValue::hlstring => { - let hlstring = match function_call_result_fb.return_value_as_hlstring() { + let hlstring = match return_value_box.value_as_hlstring() { Some(hlstring) => hlstring.value().map(|v| v.to_string()), None => None, }; @@ -572,13 +723,12 @@ impl TryFrom> for ReturnValue { } FbReturnValue::hlvoid => Ok(ReturnValue::Void(())), FbReturnValue::hlsizeprefixedbuffer => { - let hlvecbytes = - match function_call_result_fb.return_value_as_hlsizeprefixedbuffer() { - Some(hlvecbytes) => hlvecbytes - .value() - .map(|val| val.iter().collect::>()), - None => None, - }; + let hlvecbytes = match return_value_box.value_as_hlsizeprefixedbuffer() { + Some(hlvecbytes) => hlvecbytes + .value() + .map(|val| val.iter().collect::>()), + None => None, + }; Ok(ReturnValue::VecBytes(hlvecbytes.unwrap_or(Vec::new()))) } other => { @@ -588,123 +738,169 @@ impl TryFrom> for ReturnValue { } } -impl TryFrom<&[u8]> for ReturnValue { - type Error = Error; - #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))] - fn try_from(value: &[u8]) -> Result { - let function_call_result_fb = size_prefixed_root::(value) - .map_err(|e| anyhow!("Failed to get ReturnValue from bytes: {:?}", e))?; - function_call_result_fb.try_into() - } -} - impl TryFrom<&ReturnValue> for Vec { type Error = Error; #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))] fn try_from(value: &ReturnValue) -> Result> { let mut builder = flatbuffers::FlatBufferBuilder::new(); - let result = match value { + let result_bytes = match value { ReturnValue::Int(i) => { - let hlint = hlint::create(&mut builder, &hlintArgs { value: *i }); - let function_call_result = FbFunctionCallResult::create( + let hlint_off = hlint::create(&mut builder, &hlintArgs { value: *i }); + let rv_box = ReturnValueBox::create( + &mut builder, + &ReturnValueBoxArgs { + value: Some(hlint_off.as_union_value()), + value_type: FbReturnValue::hlint, + }, + ); + let fcr = FbFunctionCallResult::create( &mut builder, &FbFunctionCallResultArgs { - return_value: Some(hlint.as_union_value()), - return_value_type: FbReturnValue::hlint, + result: Some(rv_box.as_union_value()), + result_type: FunctionCallResultType::ReturnValueBox, }, ); - builder.finish_size_prefixed(function_call_result, None); + builder.finish_size_prefixed(fcr, None); builder.finished_data().to_vec() } ReturnValue::UInt(ui) => { - let hluint = hluint::create(&mut builder, &hluintArgs { value: *ui }); - let function_call_result = FbFunctionCallResult::create( + let off = hluint::create(&mut builder, &hluintArgs { value: *ui }); + let rv_box = ReturnValueBox::create( + &mut builder, + &ReturnValueBoxArgs { + value: Some(off.as_union_value()), + value_type: FbReturnValue::hluint, + }, + ); + let fcr = FbFunctionCallResult::create( &mut builder, &FbFunctionCallResultArgs { - return_value: Some(hluint.as_union_value()), - return_value_type: FbReturnValue::hluint, + result: Some(rv_box.as_union_value()), + result_type: FunctionCallResultType::ReturnValueBox, }, ); - builder.finish_size_prefixed(function_call_result, None); + builder.finish_size_prefixed(fcr, None); builder.finished_data().to_vec() } ReturnValue::Long(l) => { - let hllong = hllong::create(&mut builder, &hllongArgs { value: *l }); - let function_call_result = FbFunctionCallResult::create( + let off = hllong::create(&mut builder, &hllongArgs { value: *l }); + let rv_box = ReturnValueBox::create( + &mut builder, + &ReturnValueBoxArgs { + value: Some(off.as_union_value()), + value_type: FbReturnValue::hllong, + }, + ); + let fcr = FbFunctionCallResult::create( &mut builder, &FbFunctionCallResultArgs { - return_value: Some(hllong.as_union_value()), - return_value_type: FbReturnValue::hllong, + result: Some(rv_box.as_union_value()), + result_type: FunctionCallResultType::ReturnValueBox, }, ); - builder.finish_size_prefixed(function_call_result, None); + builder.finish_size_prefixed(fcr, None); builder.finished_data().to_vec() } ReturnValue::ULong(ul) => { - let hlulong = hlulong::create(&mut builder, &hlulongArgs { value: *ul }); - let function_call_result = FbFunctionCallResult::create( + let off = hlulong::create(&mut builder, &hlulongArgs { value: *ul }); + let rv_box = ReturnValueBox::create( + &mut builder, + &ReturnValueBoxArgs { + value: Some(off.as_union_value()), + value_type: FbReturnValue::hlulong, + }, + ); + let fcr = FbFunctionCallResult::create( &mut builder, &FbFunctionCallResultArgs { - return_value: Some(hlulong.as_union_value()), - return_value_type: FbReturnValue::hlulong, + result: Some(rv_box.as_union_value()), + result_type: FunctionCallResultType::ReturnValueBox, }, ); - builder.finish_size_prefixed(function_call_result, None); + builder.finish_size_prefixed(fcr, None); builder.finished_data().to_vec() } ReturnValue::Float(f) => { - let hlfloat = hlfloat::create(&mut builder, &hlfloatArgs { value: *f }); - let function_call_result = FbFunctionCallResult::create( + let off = hlfloat::create(&mut builder, &hlfloatArgs { value: *f }); + let rv_box = ReturnValueBox::create( + &mut builder, + &ReturnValueBoxArgs { + value: Some(off.as_union_value()), + value_type: FbReturnValue::hlfloat, + }, + ); + let fcr = FbFunctionCallResult::create( &mut builder, &FbFunctionCallResultArgs { - return_value: Some(hlfloat.as_union_value()), - return_value_type: FbReturnValue::hlfloat, + result: Some(rv_box.as_union_value()), + result_type: FunctionCallResultType::ReturnValueBox, }, ); - builder.finish_size_prefixed(function_call_result, None); + builder.finish_size_prefixed(fcr, None); builder.finished_data().to_vec() } ReturnValue::Double(d) => { - let hldouble = hldouble::create(&mut builder, &hldoubleArgs { value: *d }); - let function_call_result = FbFunctionCallResult::create( + let off = hldouble::create(&mut builder, &hldoubleArgs { value: *d }); + let rv_box = ReturnValueBox::create( + &mut builder, + &ReturnValueBoxArgs { + value: Some(off.as_union_value()), + value_type: FbReturnValue::hldouble, + }, + ); + let fcr = FbFunctionCallResult::create( &mut builder, &FbFunctionCallResultArgs { - return_value: Some(hldouble.as_union_value()), - return_value_type: FbReturnValue::hldouble, + result: Some(rv_box.as_union_value()), + result_type: FunctionCallResultType::ReturnValueBox, }, ); - builder.finish_size_prefixed(function_call_result, None); + builder.finish_size_prefixed(fcr, None); builder.finished_data().to_vec() } ReturnValue::Bool(b) => { - let hlbool = hlbool::create(&mut builder, &hlboolArgs { value: *b }); - let function_call_result = FbFunctionCallResult::create( + let off = hlbool::create(&mut builder, &hlboolArgs { value: *b }); + let rv_box = ReturnValueBox::create( + &mut builder, + &ReturnValueBoxArgs { + value: Some(off.as_union_value()), + value_type: FbReturnValue::hlbool, + }, + ); + let fcr = FbFunctionCallResult::create( &mut builder, &FbFunctionCallResultArgs { - return_value: Some(hlbool.as_union_value()), - return_value_type: FbReturnValue::hlbool, + result: Some(rv_box.as_union_value()), + result_type: FunctionCallResultType::ReturnValueBox, }, ); - builder.finish_size_prefixed(function_call_result, None); + builder.finish_size_prefixed(fcr, None); builder.finished_data().to_vec() } ReturnValue::String(s) => { - let hlstring = { + let off = { let val = builder.create_string(s.as_str()); hlstring::create(&mut builder, &hlstringArgs { value: Some(val) }) }; - let function_call_result = FbFunctionCallResult::create( + let rv_box = ReturnValueBox::create( + &mut builder, + &ReturnValueBoxArgs { + value: Some(off.as_union_value()), + value_type: FbReturnValue::hlstring, + }, + ); + let fcr = FbFunctionCallResult::create( &mut builder, &FbFunctionCallResultArgs { - return_value: Some(hlstring.as_union_value()), - return_value_type: FbReturnValue::hlstring, + result: Some(rv_box.as_union_value()), + result_type: FunctionCallResultType::ReturnValueBox, }, ); - builder.finish_size_prefixed(function_call_result, None); + builder.finish_size_prefixed(fcr, None); builder.finished_data().to_vec() } ReturnValue::VecBytes(v) => { - let hlvecbytes = { + let off = { let val = builder.create_vector(v.as_slice()); hlsizeprefixedbuffer::create( &mut builder, @@ -714,30 +910,77 @@ impl TryFrom<&ReturnValue> for Vec { }, ) }; - let function_call_result = FbFunctionCallResult::create( + let rv_box = ReturnValueBox::create( + &mut builder, + &ReturnValueBoxArgs { + value: Some(off.as_union_value()), + value_type: FbReturnValue::hlsizeprefixedbuffer, + }, + ); + let fcr = FbFunctionCallResult::create( &mut builder, &FbFunctionCallResultArgs { - return_value: Some(hlvecbytes.as_union_value()), - return_value_type: FbReturnValue::hlsizeprefixedbuffer, + result: Some(rv_box.as_union_value()), + result_type: FunctionCallResultType::ReturnValueBox, }, ); - builder.finish_size_prefixed(function_call_result, None); + builder.finish_size_prefixed(fcr, None); builder.finished_data().to_vec() } ReturnValue::Void(()) => { - let hlvoid = hlvoid::create(&mut builder, &hlvoidArgs {}); - let function_call_result = FbFunctionCallResult::create( + let off = hlvoid::create(&mut builder, &hlvoidArgs {}); + let rv_box = ReturnValueBox::create( + &mut builder, + &ReturnValueBoxArgs { + value: Some(off.as_union_value()), + value_type: FbReturnValue::hlvoid, + }, + ); + let fcr = FbFunctionCallResult::create( &mut builder, &FbFunctionCallResultArgs { - return_value: Some(hlvoid.as_union_value()), - return_value_type: FbReturnValue::hlvoid, + result: Some(rv_box.as_union_value()), + result_type: FunctionCallResultType::ReturnValueBox, }, ); - builder.finish_size_prefixed(function_call_result, None); + builder.finish_size_prefixed(fcr, None); builder.finished_data().to_vec() } }; - Ok(result) + Ok(result_bytes) + } +} + +#[cfg(test)] +mod tests { + use flatbuffers::FlatBufferBuilder; + + use super::super::guest_error::ErrorCode; + use super::*; + + #[test] + fn encode_success_result() { + let mut builder = FlatBufferBuilder::new(); + let test_data = FunctionCallResult::new(Ok(ReturnValue::Int(42))).encode(&mut builder); + + let function_call_result = FunctionCallResult::try_from(test_data).unwrap(); + let result = function_call_result.into_inner().unwrap(); + assert_eq!(result, ReturnValue::Int(42)); + } + + #[test] + fn encode_error_result() { + let mut builder = FlatBufferBuilder::new(); + let test_error = GuestError::new( + ErrorCode::GuestFunctionNotFound, + "Function not found".to_string(), + ); + let test_data = FunctionCallResult::new(Err(test_error.clone())).encode(&mut builder); + + let function_call_result = FunctionCallResult::try_from(test_data).unwrap(); + let error = function_call_result.into_inner().unwrap_err(); + assert_eq!(error.code, test_error.code); + assert_eq!(error.message, test_error.message); } } diff --git a/src/hyperlight_common/src/flatbuffer_wrappers/guest_error.rs b/src/hyperlight_common/src/flatbuffer_wrappers/guest_error.rs index 289ae48b4..b3d1f457e 100644 --- a/src/hyperlight_common/src/flatbuffer_wrappers/guest_error.rs +++ b/src/hyperlight_common/src/flatbuffer_wrappers/guest_error.rs @@ -17,16 +17,11 @@ limitations under the License. extern crate flatbuffers; use alloc::string::{String, ToString}; -use alloc::vec::Vec; -use anyhow::{Error, Result}; -use flatbuffers::size_prefixed_root; #[cfg(feature = "tracing")] use tracing::{Span, instrument}; -use crate::flatbuffers::hyperlight::generated::{ - ErrorCode as FbErrorCode, GuestError as FbGuestError, GuestErrorArgs, -}; +use crate::flatbuffers::hyperlight::generated::ErrorCode as FbErrorCode; #[derive(Debug, Clone, Copy, Eq, PartialEq)] #[repr(C)] @@ -48,6 +43,7 @@ pub enum ErrorCode { GuestFunctionParameterTypeMismatch = 14, GuestError = 15, ArrayLengthParamIsMissing = 16, + HostFunctionError = 17, } impl From for FbErrorCode { @@ -73,6 +69,7 @@ impl From for FbErrorCode { } ErrorCode::GuestError => Self::GuestError, ErrorCode::ArrayLengthParamIsMissing => Self::ArrayLengthParamIsMissing, + ErrorCode::HostFunctionError => Self::HostError, } } } @@ -99,6 +96,7 @@ impl From for ErrorCode { } FbErrorCode::GuestError => Self::GuestError, FbErrorCode::ArrayLengthParamIsMissing => Self::ArrayLengthParamIsMissing, + FbErrorCode::HostError => Self::HostFunctionError, _ => Self::UnknownError, } } @@ -123,6 +121,7 @@ impl From for ErrorCode { 14 => Self::GuestFunctionParameterTypeMismatch, 15 => Self::GuestError, 16 => Self::ArrayLengthParamIsMissing, + 17 => Self::HostFunctionError, _ => Self::UnknownError, } } @@ -147,6 +146,7 @@ impl From for u64 { ErrorCode::GuestFunctionParameterTypeMismatch => 14, ErrorCode::GuestError => 15, ErrorCode::ArrayLengthParamIsMissing => 16, + ErrorCode::HostFunctionError => 17, } } } @@ -174,6 +174,7 @@ impl From for String { } ErrorCode::GuestError => "GuestError".to_string(), ErrorCode::ArrayLengthParamIsMissing => "ArrayLengthParamIsMissing".to_string(), + ErrorCode::HostFunctionError => "HostFunctionError".to_string(), } } } @@ -194,44 +195,6 @@ impl GuestError { } } -impl TryFrom<&[u8]> for GuestError { - type Error = Error; - fn try_from(value: &[u8]) -> Result { - let guest_error_fb = size_prefixed_root::(value) - .map_err(|e| anyhow::anyhow!("Error while reading GuestError: {:?}", e))?; - let code = guest_error_fb.code(); - let message = match guest_error_fb.message() { - Some(message) => message.to_string(), - None => String::new(), - }; - Ok(Self { - code: code.into(), - message, - }) - } -} - -impl TryFrom<&GuestError> for Vec { - type Error = Error; - #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))] - fn try_from(value: &GuestError) -> Result> { - let mut builder = flatbuffers::FlatBufferBuilder::new(); - let message = builder.create_string(&value.message); - - let guest_error_fb = FbGuestError::create( - &mut builder, - &GuestErrorArgs { - code: value.code.into(), - message: Some(message), - }, - ); - builder.finish_size_prefixed(guest_error_fb, None); - let res = builder.finished_data().to_vec(); - - Ok(res) - } -} - impl Default for GuestError { #[cfg_attr(feature = "tracing", instrument(parent = Span::current(), level= "Trace"))] fn default() -> Self { diff --git a/src/hyperlight_common/src/flatbuffer_wrappers/util.rs b/src/hyperlight_common/src/flatbuffer_wrappers/util.rs index 96ab16f1e..f1ce3de02 100644 --- a/src/hyperlight_common/src/flatbuffer_wrappers/util.rs +++ b/src/hyperlight_common/src/flatbuffer_wrappers/util.rs @@ -21,7 +21,8 @@ use flatbuffers::FlatBufferBuilder; use crate::flatbuffer_wrappers::function_types::ParameterValue; use crate::flatbuffers::hyperlight::generated::{ FunctionCallResult as FbFunctionCallResult, FunctionCallResultArgs as FbFunctionCallResultArgs, - ReturnValue as FbReturnValue, hlbool as Fbhlbool, hlboolArgs as FbhlboolArgs, + FunctionCallResultType as FbFunctionCallResultType, ReturnValue as FbReturnValue, + ReturnValueBox, ReturnValueBoxArgs, hlbool as Fbhlbool, hlboolArgs as FbhlboolArgs, hldouble as Fbhldouble, hldoubleArgs as FbhldoubleArgs, hlfloat as Fbhlfloat, hlfloatArgs as FbhlfloatArgs, hlint as Fbhlint, hlintArgs as FbhlintArgs, hllong as Fbhllong, hllongArgs as FbhllongArgs, hlsizeprefixedbuffer as Fbhlsizeprefixedbuffer, @@ -34,8 +35,8 @@ use crate::flatbuffers::hyperlight::generated::{ /// Flatbuffer-encodes the given value pub fn get_flatbuffer_result(val: T) -> Vec { let mut builder = FlatBufferBuilder::new(); - let res = &T::serialize(&val, &mut builder); - let result_offset = FbFunctionCallResult::create(&mut builder, res); + let res = T::serialize(&val, &mut builder); + let result_offset = FbFunctionCallResult::create(&mut builder, &res); builder.finish_size_prefixed(result_offset, None); @@ -50,9 +51,17 @@ pub trait FlatbufferSerializable { impl FlatbufferSerializable for () { fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs { + let void_off = Fbhlvoid::create(builder, &FbhlvoidArgs {}); + let rv_box = ReturnValueBox::create( + builder, + &ReturnValueBoxArgs { + value_type: FbReturnValue::hlvoid, + value: Some(void_off.as_union_value()), + }, + ); FbFunctionCallResultArgs { - return_value: Some(Fbhlvoid::create(builder, &FbhlvoidArgs {}).as_union_value()), - return_value_type: FbReturnValue::hlvoid, + result_type: FbFunctionCallResultType::ReturnValueBox, + result: Some(rv_box.as_union_value()), } } } @@ -60,113 +69,165 @@ impl FlatbufferSerializable for () { impl FlatbufferSerializable for &str { fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs { let string_offset = builder.create_string(self); + let str_off = Fbhlstring::create( + builder, + &FbhlstringArgs { + value: Some(string_offset), + }, + ); + let rv_box = ReturnValueBox::create( + builder, + &ReturnValueBoxArgs { + value_type: FbReturnValue::hlstring, + value: Some(str_off.as_union_value()), + }, + ); FbFunctionCallResultArgs { - return_value: Some( - Fbhlstring::create( - builder, - &FbhlstringArgs { - value: Some(string_offset), - }, - ) - .as_union_value(), - ), - return_value_type: FbReturnValue::hlstring, + result_type: FbFunctionCallResultType::ReturnValueBox, + result: Some(rv_box.as_union_value()), } } } impl FlatbufferSerializable for &[u8] { fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs { - let vec_offset = builder.create_vector(self); + let vec_off = builder.create_vector(self); + let buf_off = Fbhlsizeprefixedbuffer::create( + builder, + &FbhlsizeprefixedbufferArgs { + size: self.len() as i32, + value: Some(vec_off), + }, + ); + let rv_box = ReturnValueBox::create( + builder, + &ReturnValueBoxArgs { + value_type: FbReturnValue::hlsizeprefixedbuffer, + value: Some(buf_off.as_union_value()), + }, + ); FbFunctionCallResultArgs { - return_value: Some( - Fbhlsizeprefixedbuffer::create( - builder, - &FbhlsizeprefixedbufferArgs { - size: self.len() as i32, - value: Some(vec_offset), - }, - ) - .as_union_value(), - ), - return_value_type: FbReturnValue::hlsizeprefixedbuffer, + result_type: FbFunctionCallResultType::ReturnValueBox, + result: Some(rv_box.as_union_value()), } } } impl FlatbufferSerializable for f32 { fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs { + let off = Fbhlfloat::create(builder, &FbhlfloatArgs { value: *self }); + let rv_box = ReturnValueBox::create( + builder, + &ReturnValueBoxArgs { + value_type: FbReturnValue::hlfloat, + value: Some(off.as_union_value()), + }, + ); FbFunctionCallResultArgs { - return_value: Some( - Fbhlfloat::create(builder, &FbhlfloatArgs { value: *self }).as_union_value(), - ), - return_value_type: FbReturnValue::hlfloat, + result_type: FbFunctionCallResultType::ReturnValueBox, + result: Some(rv_box.as_union_value()), } } } impl FlatbufferSerializable for f64 { fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs { + let off = Fbhldouble::create(builder, &FbhldoubleArgs { value: *self }); + let rv_box = ReturnValueBox::create( + builder, + &ReturnValueBoxArgs { + value_type: FbReturnValue::hldouble, + value: Some(off.as_union_value()), + }, + ); FbFunctionCallResultArgs { - return_value: Some( - Fbhldouble::create(builder, &FbhldoubleArgs { value: *self }).as_union_value(), - ), - return_value_type: FbReturnValue::hldouble, + result_type: FbFunctionCallResultType::ReturnValueBox, + result: Some(rv_box.as_union_value()), } } } impl FlatbufferSerializable for i32 { fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs { + let off = Fbhlint::create(builder, &FbhlintArgs { value: *self }); + let rv_box = ReturnValueBox::create( + builder, + &ReturnValueBoxArgs { + value_type: FbReturnValue::hlint, + value: Some(off.as_union_value()), + }, + ); FbFunctionCallResultArgs { - return_value: Some( - Fbhlint::create(builder, &FbhlintArgs { value: *self }).as_union_value(), - ), - return_value_type: FbReturnValue::hlint, + result_type: FbFunctionCallResultType::ReturnValueBox, + result: Some(rv_box.as_union_value()), } } } impl FlatbufferSerializable for i64 { fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs { + let off = Fbhllong::create(builder, &FbhllongArgs { value: *self }); + let rv_box = ReturnValueBox::create( + builder, + &ReturnValueBoxArgs { + value_type: FbReturnValue::hllong, + value: Some(off.as_union_value()), + }, + ); FbFunctionCallResultArgs { - return_value: Some( - Fbhllong::create(builder, &FbhllongArgs { value: *self }).as_union_value(), - ), - return_value_type: FbReturnValue::hllong, + result_type: FbFunctionCallResultType::ReturnValueBox, + result: Some(rv_box.as_union_value()), } } } impl FlatbufferSerializable for u32 { fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs { + let off = Fbhluint::create(builder, &FbhluintArgs { value: *self }); + let rv_box = ReturnValueBox::create( + builder, + &ReturnValueBoxArgs { + value_type: FbReturnValue::hluint, + value: Some(off.as_union_value()), + }, + ); FbFunctionCallResultArgs { - return_value: Some( - Fbhluint::create(builder, &FbhluintArgs { value: *self }).as_union_value(), - ), - return_value_type: FbReturnValue::hluint, + result_type: FbFunctionCallResultType::ReturnValueBox, + result: Some(rv_box.as_union_value()), } } } impl FlatbufferSerializable for u64 { fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs { + let off = Fbhlulong::create(builder, &FbhlulongArgs { value: *self }); + let rv_box = ReturnValueBox::create( + builder, + &ReturnValueBoxArgs { + value_type: FbReturnValue::hlulong, + value: Some(off.as_union_value()), + }, + ); FbFunctionCallResultArgs { - return_value: Some( - Fbhlulong::create(builder, &FbhlulongArgs { value: *self }).as_union_value(), - ), - return_value_type: FbReturnValue::hlulong, + result_type: FbFunctionCallResultType::ReturnValueBox, + result: Some(rv_box.as_union_value()), } } } impl FlatbufferSerializable for bool { fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs { + let off = Fbhlbool::create(builder, &FbhlboolArgs { value: *self }); + let rv_box = ReturnValueBox::create( + builder, + &ReturnValueBoxArgs { + value_type: FbReturnValue::hlbool, + value: Some(off.as_union_value()), + }, + ); FbFunctionCallResultArgs { - return_value: Some( - Fbhlbool::create(builder, &FbhlboolArgs { value: *self }).as_union_value(), - ), - return_value_type: FbReturnValue::hlbool, + result_type: FbFunctionCallResultType::ReturnValueBox, + result: Some(rv_box.as_union_value()), } } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/error_code_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/error_code_generated.rs index 6b03bb0cb..b299358e3 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/error_code_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/error_code_generated.rs @@ -19,13 +19,13 @@ pub const ENUM_MIN_ERROR_CODE: u64 = 0; since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021." )] -pub const ENUM_MAX_ERROR_CODE: u64 = 16; +pub const ENUM_MAX_ERROR_CODE: u64 = 17; #[deprecated( since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021." )] #[allow(non_camel_case_types)] -pub const ENUM_VALUES_ERROR_CODE: [ErrorCode; 16] = [ +pub const ENUM_VALUES_ERROR_CODE: [ErrorCode; 17] = [ ErrorCode::NoError, ErrorCode::UnsupportedParameterType, ErrorCode::GuestFunctionNameNotProvided, @@ -42,6 +42,7 @@ pub const ENUM_VALUES_ERROR_CODE: [ErrorCode; 16] = [ ErrorCode::GuestFunctionParameterTypeMismatch, ErrorCode::GuestError, ErrorCode::ArrayLengthParamIsMissing, + ErrorCode::HostError, ]; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] @@ -65,9 +66,10 @@ impl ErrorCode { pub const GuestFunctionParameterTypeMismatch: Self = Self(14); pub const GuestError: Self = Self(15); pub const ArrayLengthParamIsMissing: Self = Self(16); + pub const HostError: Self = Self(17); pub const ENUM_MIN: u64 = 0; - pub const ENUM_MAX: u64 = 16; + pub const ENUM_MAX: u64 = 17; pub const ENUM_VALUES: &'static [Self] = &[ Self::NoError, Self::UnsupportedParameterType, @@ -85,6 +87,7 @@ impl ErrorCode { Self::GuestFunctionParameterTypeMismatch, Self::GuestError, Self::ArrayLengthParamIsMissing, + Self::HostError, ]; /// Returns the variant's name or "" if unknown. pub fn variant_name(self) -> Option<&'static str> { @@ -107,6 +110,7 @@ impl ErrorCode { Self::GuestFunctionParameterTypeMismatch => Some("GuestFunctionParameterTypeMismatch"), Self::GuestError => Some("GuestError"), Self::ArrayLengthParamIsMissing => Some("ArrayLengthParamIsMissing"), + Self::HostError => Some("HostError"), _ => None, } } diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_generated.rs index 786d6de98..7ea5b4d63 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_generated.rs @@ -237,80 +237,3 @@ impl core::fmt::Debug for FunctionCall<'_> { ds.finish() } } -#[inline] -/// Verifies that a buffer of bytes contains a `FunctionCall` -/// and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_function_call_unchecked`. -pub fn root_as_function_call(buf: &[u8]) -> Result { - flatbuffers::root::(buf) -} -#[inline] -/// Verifies that a buffer of bytes contains a size prefixed -/// `FunctionCall` and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `size_prefixed_root_as_function_call_unchecked`. -pub fn size_prefixed_root_as_function_call( - buf: &[u8], -) -> Result { - flatbuffers::size_prefixed_root::(buf) -} -#[inline] -/// Verifies, with the given options, that a buffer of bytes -/// contains a `FunctionCall` and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_function_call_unchecked`. -pub fn root_as_function_call_with_opts<'b, 'o>( - opts: &'o flatbuffers::VerifierOptions, - buf: &'b [u8], -) -> Result, flatbuffers::InvalidFlatbuffer> { - flatbuffers::root_with_opts::>(opts, buf) -} -#[inline] -/// Verifies, with the given verifier options, that a buffer of -/// bytes contains a size prefixed `FunctionCall` and returns -/// it. Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_function_call_unchecked`. -pub fn size_prefixed_root_as_function_call_with_opts<'b, 'o>( - opts: &'o flatbuffers::VerifierOptions, - buf: &'b [u8], -) -> Result, flatbuffers::InvalidFlatbuffer> { - flatbuffers::size_prefixed_root_with_opts::>(opts, buf) -} -#[inline] -/// Assumes, without verification, that a buffer of bytes contains a FunctionCall and returns it. -/// # Safety -/// Callers must trust the given bytes do indeed contain a valid `FunctionCall`. -pub unsafe fn root_as_function_call_unchecked(buf: &[u8]) -> FunctionCall { - unsafe { flatbuffers::root_unchecked::(buf) } -} -#[inline] -/// Assumes, without verification, that a buffer of bytes contains a size prefixed FunctionCall and returns it. -/// # Safety -/// Callers must trust the given bytes do indeed contain a valid size prefixed `FunctionCall`. -pub unsafe fn size_prefixed_root_as_function_call_unchecked(buf: &[u8]) -> FunctionCall { - unsafe { flatbuffers::size_prefixed_root_unchecked::(buf) } -} -#[inline] -pub fn finish_function_call_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( - fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - root: flatbuffers::WIPOffset>, -) { - fbb.finish(root, None); -} - -#[inline] -pub fn finish_size_prefixed_function_call_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( - fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - root: flatbuffers::WIPOffset>, -) { - fbb.finish_size_prefixed(root, None); -} diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_result_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_result_generated.rs index 9e7cddd15..7f26e9c00 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_result_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_result_generated.rs @@ -28,8 +28,8 @@ impl<'a> flatbuffers::Follow<'a> for FunctionCallResult<'a> { } impl<'a> FunctionCallResult<'a> { - pub const VT_RETURN_VALUE_TYPE: flatbuffers::VOffsetT = 4; - pub const VT_RETURN_VALUE: flatbuffers::VOffsetT = 6; + pub const VT_RESULT_TYPE: flatbuffers::VOffsetT = 4; + pub const VT_RESULT: flatbuffers::VOffsetT = 6; #[inline] pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { @@ -41,36 +41,36 @@ impl<'a> FunctionCallResult<'a> { args: &'args FunctionCallResultArgs, ) -> flatbuffers::WIPOffset> { let mut builder = FunctionCallResultBuilder::new(_fbb); - if let Some(x) = args.return_value { - builder.add_return_value(x); + if let Some(x) = args.result { + builder.add_result(x); } - builder.add_return_value_type(args.return_value_type); + builder.add_result_type(args.result_type); builder.finish() } #[inline] - pub fn return_value_type(&self) -> ReturnValue { + pub fn result_type(&self) -> FunctionCallResultType { // Safety: // Created from valid Table for this object // which contains a valid value in this slot unsafe { self._tab - .get::( - FunctionCallResult::VT_RETURN_VALUE_TYPE, - Some(ReturnValue::NONE), + .get::( + FunctionCallResult::VT_RESULT_TYPE, + Some(FunctionCallResultType::NONE), ) .unwrap() } } #[inline] - pub fn return_value(&self) -> flatbuffers::Table<'a> { + pub fn result(&self) -> flatbuffers::Table<'a> { // Safety: // Created from valid Table for this object // which contains a valid value in this slot unsafe { self._tab .get::>>( - FunctionCallResult::VT_RETURN_VALUE, + FunctionCallResult::VT_RESULT, None, ) .unwrap() @@ -78,13 +78,13 @@ impl<'a> FunctionCallResult<'a> { } #[inline] #[allow(non_snake_case)] - pub fn return_value_as_hlint(&self) -> Option> { - if self.return_value_type() == ReturnValue::hlint { - let u = self.return_value(); + pub fn result_as_return_value_box(&self) -> Option> { + if self.result_type() == FunctionCallResultType::ReturnValueBox { + let u = self.result(); // Safety: // Created from a valid Table for this object // Which contains a valid union in this slot - Some(unsafe { hlint::init_from_table(u) }) + Some(unsafe { ReturnValueBox::init_from_table(u) }) } else { None } @@ -92,125 +92,13 @@ impl<'a> FunctionCallResult<'a> { #[inline] #[allow(non_snake_case)] - pub fn return_value_as_hluint(&self) -> Option> { - if self.return_value_type() == ReturnValue::hluint { - let u = self.return_value(); + pub fn result_as_guest_error(&self) -> Option> { + if self.result_type() == FunctionCallResultType::GuestError { + let u = self.result(); // Safety: // Created from a valid Table for this object // Which contains a valid union in this slot - Some(unsafe { hluint::init_from_table(u) }) - } else { - None - } - } - - #[inline] - #[allow(non_snake_case)] - pub fn return_value_as_hllong(&self) -> Option> { - if self.return_value_type() == ReturnValue::hllong { - let u = self.return_value(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid union in this slot - Some(unsafe { hllong::init_from_table(u) }) - } else { - None - } - } - - #[inline] - #[allow(non_snake_case)] - pub fn return_value_as_hlulong(&self) -> Option> { - if self.return_value_type() == ReturnValue::hlulong { - let u = self.return_value(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid union in this slot - Some(unsafe { hlulong::init_from_table(u) }) - } else { - None - } - } - - #[inline] - #[allow(non_snake_case)] - pub fn return_value_as_hlfloat(&self) -> Option> { - if self.return_value_type() == ReturnValue::hlfloat { - let u = self.return_value(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid union in this slot - Some(unsafe { hlfloat::init_from_table(u) }) - } else { - None - } - } - - #[inline] - #[allow(non_snake_case)] - pub fn return_value_as_hldouble(&self) -> Option> { - if self.return_value_type() == ReturnValue::hldouble { - let u = self.return_value(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid union in this slot - Some(unsafe { hldouble::init_from_table(u) }) - } else { - None - } - } - - #[inline] - #[allow(non_snake_case)] - pub fn return_value_as_hlstring(&self) -> Option> { - if self.return_value_type() == ReturnValue::hlstring { - let u = self.return_value(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid union in this slot - Some(unsafe { hlstring::init_from_table(u) }) - } else { - None - } - } - - #[inline] - #[allow(non_snake_case)] - pub fn return_value_as_hlbool(&self) -> Option> { - if self.return_value_type() == ReturnValue::hlbool { - let u = self.return_value(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid union in this slot - Some(unsafe { hlbool::init_from_table(u) }) - } else { - None - } - } - - #[inline] - #[allow(non_snake_case)] - pub fn return_value_as_hlvoid(&self) -> Option> { - if self.return_value_type() == ReturnValue::hlvoid { - let u = self.return_value(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid union in this slot - Some(unsafe { hlvoid::init_from_table(u) }) - } else { - None - } - } - - #[inline] - #[allow(non_snake_case)] - pub fn return_value_as_hlsizeprefixedbuffer(&self) -> Option> { - if self.return_value_type() == ReturnValue::hlsizeprefixedbuffer { - let u = self.return_value(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid union in this slot - Some(unsafe { hlsizeprefixedbuffer::init_from_table(u) }) + Some(unsafe { GuestError::init_from_table(u) }) } else { None } @@ -225,61 +113,21 @@ impl flatbuffers::Verifiable for FunctionCallResult<'_> { ) -> Result<(), flatbuffers::InvalidFlatbuffer> { use self::flatbuffers::Verifiable; v.visit_table(pos)? - .visit_union::( - "return_value_type", - Self::VT_RETURN_VALUE_TYPE, - "return_value", - Self::VT_RETURN_VALUE, + .visit_union::( + "result_type", + Self::VT_RESULT_TYPE, + "result", + Self::VT_RESULT, true, |key, v, pos| match key { - ReturnValue::hlint => v - .verify_union_variant::>( - "ReturnValue::hlint", - pos, - ), - ReturnValue::hluint => v - .verify_union_variant::>( - "ReturnValue::hluint", - pos, - ), - ReturnValue::hllong => v - .verify_union_variant::>( - "ReturnValue::hllong", - pos, - ), - ReturnValue::hlulong => v - .verify_union_variant::>( - "ReturnValue::hlulong", - pos, - ), - ReturnValue::hlfloat => v - .verify_union_variant::>( - "ReturnValue::hlfloat", + FunctionCallResultType::ReturnValueBox => v + .verify_union_variant::>( + "FunctionCallResultType::ReturnValueBox", pos, ), - ReturnValue::hldouble => v - .verify_union_variant::>( - "ReturnValue::hldouble", - pos, - ), - ReturnValue::hlstring => v - .verify_union_variant::>( - "ReturnValue::hlstring", - pos, - ), - ReturnValue::hlbool => v - .verify_union_variant::>( - "ReturnValue::hlbool", - pos, - ), - ReturnValue::hlvoid => v - .verify_union_variant::>( - "ReturnValue::hlvoid", - pos, - ), - ReturnValue::hlsizeprefixedbuffer => v - .verify_union_variant::>( - "ReturnValue::hlsizeprefixedbuffer", + FunctionCallResultType::GuestError => v + .verify_union_variant::>( + "FunctionCallResultType::GuestError", pos, ), _ => Ok(()), @@ -290,15 +138,15 @@ impl flatbuffers::Verifiable for FunctionCallResult<'_> { } } pub struct FunctionCallResultArgs { - pub return_value_type: ReturnValue, - pub return_value: Option>, + pub result_type: FunctionCallResultType, + pub result: Option>, } impl<'a> Default for FunctionCallResultArgs { #[inline] fn default() -> Self { FunctionCallResultArgs { - return_value_type: ReturnValue::NONE, - return_value: None, // required field + result_type: FunctionCallResultType::NONE, + result: None, // required field } } } @@ -309,22 +157,17 @@ pub struct FunctionCallResultBuilder<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> } impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> FunctionCallResultBuilder<'a, 'b, A> { #[inline] - pub fn add_return_value_type(&mut self, return_value_type: ReturnValue) { - self.fbb_.push_slot::( - FunctionCallResult::VT_RETURN_VALUE_TYPE, - return_value_type, - ReturnValue::NONE, + pub fn add_result_type(&mut self, result_type: FunctionCallResultType) { + self.fbb_.push_slot::( + FunctionCallResult::VT_RESULT_TYPE, + result_type, + FunctionCallResultType::NONE, ); } #[inline] - pub fn add_return_value( - &mut self, - return_value: flatbuffers::WIPOffset, - ) { - self.fbb_.push_slot_always::>( - FunctionCallResult::VT_RETURN_VALUE, - return_value, - ); + pub fn add_result(&mut self, result: flatbuffers::WIPOffset) { + self.fbb_ + .push_slot_always::>(FunctionCallResult::VT_RESULT, result); } #[inline] pub fn new( @@ -340,7 +183,7 @@ impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> FunctionCallResultBuilder<'a, ' pub fn finish(self) -> flatbuffers::WIPOffset> { let o = self.fbb_.end_table(self.start_); self.fbb_ - .required(o, FunctionCallResult::VT_RETURN_VALUE, "return_value"); + .required(o, FunctionCallResult::VT_RESULT, "result"); flatbuffers::WIPOffset::new(o.value()) } } @@ -348,194 +191,33 @@ impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> FunctionCallResultBuilder<'a, ' impl core::fmt::Debug for FunctionCallResult<'_> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let mut ds = f.debug_struct("FunctionCallResult"); - ds.field("return_value_type", &self.return_value_type()); - match self.return_value_type() { - ReturnValue::hlint => { - if let Some(x) = self.return_value_as_hlint() { - ds.field("return_value", &x) + ds.field("result_type", &self.result_type()); + match self.result_type() { + FunctionCallResultType::ReturnValueBox => { + if let Some(x) = self.result_as_return_value_box() { + ds.field("result", &x) } else { ds.field( - "return_value", + "result", &"InvalidFlatbuffer: Union discriminant does not match value.", ) } } - ReturnValue::hluint => { - if let Some(x) = self.return_value_as_hluint() { - ds.field("return_value", &x) + FunctionCallResultType::GuestError => { + if let Some(x) = self.result_as_guest_error() { + ds.field("result", &x) } else { ds.field( - "return_value", - &"InvalidFlatbuffer: Union discriminant does not match value.", - ) - } - } - ReturnValue::hllong => { - if let Some(x) = self.return_value_as_hllong() { - ds.field("return_value", &x) - } else { - ds.field( - "return_value", - &"InvalidFlatbuffer: Union discriminant does not match value.", - ) - } - } - ReturnValue::hlulong => { - if let Some(x) = self.return_value_as_hlulong() { - ds.field("return_value", &x) - } else { - ds.field( - "return_value", - &"InvalidFlatbuffer: Union discriminant does not match value.", - ) - } - } - ReturnValue::hlfloat => { - if let Some(x) = self.return_value_as_hlfloat() { - ds.field("return_value", &x) - } else { - ds.field( - "return_value", - &"InvalidFlatbuffer: Union discriminant does not match value.", - ) - } - } - ReturnValue::hldouble => { - if let Some(x) = self.return_value_as_hldouble() { - ds.field("return_value", &x) - } else { - ds.field( - "return_value", - &"InvalidFlatbuffer: Union discriminant does not match value.", - ) - } - } - ReturnValue::hlstring => { - if let Some(x) = self.return_value_as_hlstring() { - ds.field("return_value", &x) - } else { - ds.field( - "return_value", - &"InvalidFlatbuffer: Union discriminant does not match value.", - ) - } - } - ReturnValue::hlbool => { - if let Some(x) = self.return_value_as_hlbool() { - ds.field("return_value", &x) - } else { - ds.field( - "return_value", - &"InvalidFlatbuffer: Union discriminant does not match value.", - ) - } - } - ReturnValue::hlvoid => { - if let Some(x) = self.return_value_as_hlvoid() { - ds.field("return_value", &x) - } else { - ds.field( - "return_value", - &"InvalidFlatbuffer: Union discriminant does not match value.", - ) - } - } - ReturnValue::hlsizeprefixedbuffer => { - if let Some(x) = self.return_value_as_hlsizeprefixedbuffer() { - ds.field("return_value", &x) - } else { - ds.field( - "return_value", + "result", &"InvalidFlatbuffer: Union discriminant does not match value.", ) } } _ => { let x: Option<()> = None; - ds.field("return_value", &x) + ds.field("result", &x) } }; ds.finish() } } -#[inline] -/// Verifies that a buffer of bytes contains a `FunctionCallResult` -/// and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_function_call_result_unchecked`. -pub fn root_as_function_call_result( - buf: &[u8], -) -> Result { - flatbuffers::root::(buf) -} -#[inline] -/// Verifies that a buffer of bytes contains a size prefixed -/// `FunctionCallResult` and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `size_prefixed_root_as_function_call_result_unchecked`. -pub fn size_prefixed_root_as_function_call_result( - buf: &[u8], -) -> Result { - flatbuffers::size_prefixed_root::(buf) -} -#[inline] -/// Verifies, with the given options, that a buffer of bytes -/// contains a `FunctionCallResult` and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_function_call_result_unchecked`. -pub fn root_as_function_call_result_with_opts<'b, 'o>( - opts: &'o flatbuffers::VerifierOptions, - buf: &'b [u8], -) -> Result, flatbuffers::InvalidFlatbuffer> { - flatbuffers::root_with_opts::>(opts, buf) -} -#[inline] -/// Verifies, with the given verifier options, that a buffer of -/// bytes contains a size prefixed `FunctionCallResult` and returns -/// it. Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_function_call_result_unchecked`. -pub fn size_prefixed_root_as_function_call_result_with_opts<'b, 'o>( - opts: &'o flatbuffers::VerifierOptions, - buf: &'b [u8], -) -> Result, flatbuffers::InvalidFlatbuffer> { - flatbuffers::size_prefixed_root_with_opts::>(opts, buf) -} -#[inline] -/// Assumes, without verification, that a buffer of bytes contains a FunctionCallResult and returns it. -/// # Safety -/// Callers must trust the given bytes do indeed contain a valid `FunctionCallResult`. -pub unsafe fn root_as_function_call_result_unchecked(buf: &[u8]) -> FunctionCallResult { - unsafe { flatbuffers::root_unchecked::(buf) } -} -#[inline] -/// Assumes, without verification, that a buffer of bytes contains a size prefixed FunctionCallResult and returns it. -/// # Safety -/// Callers must trust the given bytes do indeed contain a valid size prefixed `FunctionCallResult`. -pub unsafe fn size_prefixed_root_as_function_call_result_unchecked( - buf: &[u8], -) -> FunctionCallResult { - unsafe { flatbuffers::size_prefixed_root_unchecked::(buf) } -} -#[inline] -pub fn finish_function_call_result_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( - fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - root: flatbuffers::WIPOffset>, -) { - fbb.finish(root, None); -} - -#[inline] -pub fn finish_size_prefixed_function_call_result_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( - fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - root: flatbuffers::WIPOffset>, -) { - fbb.finish_size_prefixed(root, None); -} diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_result_type_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_result_type_generated.rs new file mode 100644 index 000000000..0c54dfed4 --- /dev/null +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/function_call_result_type_generated.rs @@ -0,0 +1,110 @@ +// automatically generated by the FlatBuffers compiler, do not modify +// @generated +extern crate alloc; +extern crate flatbuffers; +use alloc::boxed::Box; +use alloc::string::{String, ToString}; +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::mem; + +use self::flatbuffers::{EndianScalar, Follow}; +use super::*; +#[deprecated( + since = "2.0.0", + note = "Use associated constants instead. This will no longer be generated in 2021." +)] +pub const ENUM_MIN_FUNCTION_CALL_RESULT_TYPE: u8 = 0; +#[deprecated( + since = "2.0.0", + note = "Use associated constants instead. This will no longer be generated in 2021." +)] +pub const ENUM_MAX_FUNCTION_CALL_RESULT_TYPE: u8 = 2; +#[deprecated( + since = "2.0.0", + note = "Use associated constants instead. This will no longer be generated in 2021." +)] +#[allow(non_camel_case_types)] +pub const ENUM_VALUES_FUNCTION_CALL_RESULT_TYPE: [FunctionCallResultType; 3] = [ + FunctionCallResultType::NONE, + FunctionCallResultType::ReturnValueBox, + FunctionCallResultType::GuestError, +]; + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[repr(transparent)] +pub struct FunctionCallResultType(pub u8); +#[allow(non_upper_case_globals)] +impl FunctionCallResultType { + pub const NONE: Self = Self(0); + pub const ReturnValueBox: Self = Self(1); + pub const GuestError: Self = Self(2); + + pub const ENUM_MIN: u8 = 0; + pub const ENUM_MAX: u8 = 2; + pub const ENUM_VALUES: &'static [Self] = &[Self::NONE, Self::ReturnValueBox, Self::GuestError]; + /// Returns the variant's name or "" if unknown. + pub fn variant_name(self) -> Option<&'static str> { + match self { + Self::NONE => Some("NONE"), + Self::ReturnValueBox => Some("ReturnValueBox"), + Self::GuestError => Some("GuestError"), + _ => None, + } + } +} +impl core::fmt::Debug for FunctionCallResultType { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + if let Some(name) = self.variant_name() { + f.write_str(name) + } else { + f.write_fmt(format_args!("", self.0)) + } + } +} +impl<'a> flatbuffers::Follow<'a> for FunctionCallResultType { + type Inner = Self; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + let b = unsafe { flatbuffers::read_scalar_at::(buf, loc) }; + Self(b) + } +} + +impl flatbuffers::Push for FunctionCallResultType { + type Output = FunctionCallResultType; + #[inline] + unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { + unsafe { + flatbuffers::emplace_scalar::(dst, self.0); + } + } +} + +impl flatbuffers::EndianScalar for FunctionCallResultType { + type Scalar = u8; + #[inline] + fn to_little_endian(self) -> u8 { + self.0.to_le() + } + #[inline] + #[allow(clippy::wrong_self_convention)] + fn from_little_endian(v: u8) -> Self { + let b = u8::from_le(v); + Self(b) + } +} + +impl<'a> flatbuffers::Verifiable for FunctionCallResultType { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, + pos: usize, + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + u8::run_verifier(v, pos) + } +} + +impl flatbuffers::SimpleToVerifyInSlice for FunctionCallResultType {} +pub struct FunctionCallResultTypeUnionTableOffset {} diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_error_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_error_generated.rs index 24b76ea47..21ef559b6 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_error_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_error_generated.rs @@ -139,80 +139,3 @@ impl core::fmt::Debug for GuestError<'_> { ds.finish() } } -#[inline] -/// Verifies that a buffer of bytes contains a `GuestError` -/// and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_guest_error_unchecked`. -pub fn root_as_guest_error(buf: &[u8]) -> Result { - flatbuffers::root::(buf) -} -#[inline] -/// Verifies that a buffer of bytes contains a size prefixed -/// `GuestError` and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `size_prefixed_root_as_guest_error_unchecked`. -pub fn size_prefixed_root_as_guest_error( - buf: &[u8], -) -> Result { - flatbuffers::size_prefixed_root::(buf) -} -#[inline] -/// Verifies, with the given options, that a buffer of bytes -/// contains a `GuestError` and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_guest_error_unchecked`. -pub fn root_as_guest_error_with_opts<'b, 'o>( - opts: &'o flatbuffers::VerifierOptions, - buf: &'b [u8], -) -> Result, flatbuffers::InvalidFlatbuffer> { - flatbuffers::root_with_opts::>(opts, buf) -} -#[inline] -/// Verifies, with the given verifier options, that a buffer of -/// bytes contains a size prefixed `GuestError` and returns -/// it. Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_guest_error_unchecked`. -pub fn size_prefixed_root_as_guest_error_with_opts<'b, 'o>( - opts: &'o flatbuffers::VerifierOptions, - buf: &'b [u8], -) -> Result, flatbuffers::InvalidFlatbuffer> { - flatbuffers::size_prefixed_root_with_opts::>(opts, buf) -} -#[inline] -/// Assumes, without verification, that a buffer of bytes contains a GuestError and returns it. -/// # Safety -/// Callers must trust the given bytes do indeed contain a valid `GuestError`. -pub unsafe fn root_as_guest_error_unchecked(buf: &[u8]) -> GuestError { - unsafe { flatbuffers::root_unchecked::(buf) } -} -#[inline] -/// Assumes, without verification, that a buffer of bytes contains a size prefixed GuestError and returns it. -/// # Safety -/// Callers must trust the given bytes do indeed contain a valid size prefixed `GuestError`. -pub unsafe fn size_prefixed_root_as_guest_error_unchecked(buf: &[u8]) -> GuestError { - unsafe { flatbuffers::size_prefixed_root_unchecked::(buf) } -} -#[inline] -pub fn finish_guest_error_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( - fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - root: flatbuffers::WIPOffset>, -) { - fbb.finish(root, None); -} - -#[inline] -pub fn finish_size_prefixed_guest_error_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( - fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - root: flatbuffers::WIPOffset>, -) { - fbb.finish_size_prefixed(root, None); -} diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_log_data_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_log_data_generated.rs index d57f8ed7e..d3de70427 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_log_data_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/guest_log_data_generated.rs @@ -235,80 +235,3 @@ impl core::fmt::Debug for GuestLogData<'_> { ds.finish() } } -#[inline] -/// Verifies that a buffer of bytes contains a `GuestLogData` -/// and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_guest_log_data_unchecked`. -pub fn root_as_guest_log_data(buf: &[u8]) -> Result { - flatbuffers::root::(buf) -} -#[inline] -/// Verifies that a buffer of bytes contains a size prefixed -/// `GuestLogData` and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `size_prefixed_root_as_guest_log_data_unchecked`. -pub fn size_prefixed_root_as_guest_log_data( - buf: &[u8], -) -> Result { - flatbuffers::size_prefixed_root::(buf) -} -#[inline] -/// Verifies, with the given options, that a buffer of bytes -/// contains a `GuestLogData` and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_guest_log_data_unchecked`. -pub fn root_as_guest_log_data_with_opts<'b, 'o>( - opts: &'o flatbuffers::VerifierOptions, - buf: &'b [u8], -) -> Result, flatbuffers::InvalidFlatbuffer> { - flatbuffers::root_with_opts::>(opts, buf) -} -#[inline] -/// Verifies, with the given verifier options, that a buffer of -/// bytes contains a size prefixed `GuestLogData` and returns -/// it. Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_guest_log_data_unchecked`. -pub fn size_prefixed_root_as_guest_log_data_with_opts<'b, 'o>( - opts: &'o flatbuffers::VerifierOptions, - buf: &'b [u8], -) -> Result, flatbuffers::InvalidFlatbuffer> { - flatbuffers::size_prefixed_root_with_opts::>(opts, buf) -} -#[inline] -/// Assumes, without verification, that a buffer of bytes contains a GuestLogData and returns it. -/// # Safety -/// Callers must trust the given bytes do indeed contain a valid `GuestLogData`. -pub unsafe fn root_as_guest_log_data_unchecked(buf: &[u8]) -> GuestLogData { - unsafe { flatbuffers::root_unchecked::(buf) } -} -#[inline] -/// Assumes, without verification, that a buffer of bytes contains a size prefixed GuestLogData and returns it. -/// # Safety -/// Callers must trust the given bytes do indeed contain a valid size prefixed `GuestLogData`. -pub unsafe fn size_prefixed_root_as_guest_log_data_unchecked(buf: &[u8]) -> GuestLogData { - unsafe { flatbuffers::size_prefixed_root_unchecked::(buf) } -} -#[inline] -pub fn finish_guest_log_data_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( - fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - root: flatbuffers::WIPOffset>, -) { - fbb.finish(root, None); -} - -#[inline] -pub fn finish_size_prefixed_guest_log_data_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( - fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - root: flatbuffers::WIPOffset>, -) { - fbb.finish_size_prefixed(root, None); -} diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_definition_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_definition_generated.rs index 010d111bf..8ffb6f35e 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_definition_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_definition_generated.rs @@ -202,88 +202,3 @@ impl core::fmt::Debug for HostFunctionDefinition<'_> { ds.finish() } } -#[inline] -/// Verifies that a buffer of bytes contains a `HostFunctionDefinition` -/// and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_host_function_definition_unchecked`. -pub fn root_as_host_function_definition( - buf: &[u8], -) -> Result { - flatbuffers::root::(buf) -} -#[inline] -/// Verifies that a buffer of bytes contains a size prefixed -/// `HostFunctionDefinition` and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `size_prefixed_root_as_host_function_definition_unchecked`. -pub fn size_prefixed_root_as_host_function_definition( - buf: &[u8], -) -> Result { - flatbuffers::size_prefixed_root::(buf) -} -#[inline] -/// Verifies, with the given options, that a buffer of bytes -/// contains a `HostFunctionDefinition` and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_host_function_definition_unchecked`. -pub fn root_as_host_function_definition_with_opts<'b, 'o>( - opts: &'o flatbuffers::VerifierOptions, - buf: &'b [u8], -) -> Result, flatbuffers::InvalidFlatbuffer> { - flatbuffers::root_with_opts::>(opts, buf) -} -#[inline] -/// Verifies, with the given verifier options, that a buffer of -/// bytes contains a size prefixed `HostFunctionDefinition` and returns -/// it. Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_host_function_definition_unchecked`. -pub fn size_prefixed_root_as_host_function_definition_with_opts<'b, 'o>( - opts: &'o flatbuffers::VerifierOptions, - buf: &'b [u8], -) -> Result, flatbuffers::InvalidFlatbuffer> { - flatbuffers::size_prefixed_root_with_opts::>(opts, buf) -} -#[inline] -/// Assumes, without verification, that a buffer of bytes contains a HostFunctionDefinition and returns it. -/// # Safety -/// Callers must trust the given bytes do indeed contain a valid `HostFunctionDefinition`. -pub unsafe fn root_as_host_function_definition_unchecked(buf: &[u8]) -> HostFunctionDefinition { - unsafe { flatbuffers::root_unchecked::(buf) } -} -#[inline] -/// Assumes, without verification, that a buffer of bytes contains a size prefixed HostFunctionDefinition and returns it. -/// # Safety -/// Callers must trust the given bytes do indeed contain a valid size prefixed `HostFunctionDefinition`. -pub unsafe fn size_prefixed_root_as_host_function_definition_unchecked( - buf: &[u8], -) -> HostFunctionDefinition { - unsafe { flatbuffers::size_prefixed_root_unchecked::(buf) } -} -#[inline] -pub fn finish_host_function_definition_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( - fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - root: flatbuffers::WIPOffset>, -) { - fbb.finish(root, None); -} - -#[inline] -pub fn finish_size_prefixed_host_function_definition_buffer< - 'a, - 'b, - A: flatbuffers::Allocator + 'a, ->( - fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - root: flatbuffers::WIPOffset>, -) { - fbb.finish_size_prefixed(root, None); -} diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_details_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_details_generated.rs index a502dd491..54cf45c73 100644 --- a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_details_generated.rs +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/host_function_details_generated.rs @@ -132,84 +132,3 @@ impl core::fmt::Debug for HostFunctionDetails<'_> { ds.finish() } } -#[inline] -/// Verifies that a buffer of bytes contains a `HostFunctionDetails` -/// and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_host_function_details_unchecked`. -pub fn root_as_host_function_details( - buf: &[u8], -) -> Result { - flatbuffers::root::(buf) -} -#[inline] -/// Verifies that a buffer of bytes contains a size prefixed -/// `HostFunctionDetails` and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `size_prefixed_root_as_host_function_details_unchecked`. -pub fn size_prefixed_root_as_host_function_details( - buf: &[u8], -) -> Result { - flatbuffers::size_prefixed_root::(buf) -} -#[inline] -/// Verifies, with the given options, that a buffer of bytes -/// contains a `HostFunctionDetails` and returns it. -/// Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_host_function_details_unchecked`. -pub fn root_as_host_function_details_with_opts<'b, 'o>( - opts: &'o flatbuffers::VerifierOptions, - buf: &'b [u8], -) -> Result, flatbuffers::InvalidFlatbuffer> { - flatbuffers::root_with_opts::>(opts, buf) -} -#[inline] -/// Verifies, with the given verifier options, that a buffer of -/// bytes contains a size prefixed `HostFunctionDetails` and returns -/// it. Note that verification is still experimental and may not -/// catch every error, or be maximally performant. For the -/// previous, unchecked, behavior use -/// `root_as_host_function_details_unchecked`. -pub fn size_prefixed_root_as_host_function_details_with_opts<'b, 'o>( - opts: &'o flatbuffers::VerifierOptions, - buf: &'b [u8], -) -> Result, flatbuffers::InvalidFlatbuffer> { - flatbuffers::size_prefixed_root_with_opts::>(opts, buf) -} -#[inline] -/// Assumes, without verification, that a buffer of bytes contains a HostFunctionDetails and returns it. -/// # Safety -/// Callers must trust the given bytes do indeed contain a valid `HostFunctionDetails`. -pub unsafe fn root_as_host_function_details_unchecked(buf: &[u8]) -> HostFunctionDetails { - unsafe { flatbuffers::root_unchecked::(buf) } -} -#[inline] -/// Assumes, without verification, that a buffer of bytes contains a size prefixed HostFunctionDetails and returns it. -/// # Safety -/// Callers must trust the given bytes do indeed contain a valid size prefixed `HostFunctionDetails`. -pub unsafe fn size_prefixed_root_as_host_function_details_unchecked( - buf: &[u8], -) -> HostFunctionDetails { - unsafe { flatbuffers::size_prefixed_root_unchecked::(buf) } -} -#[inline] -pub fn finish_host_function_details_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( - fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - root: flatbuffers::WIPOffset>, -) { - fbb.finish(root, None); -} - -#[inline] -pub fn finish_size_prefixed_host_function_details_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( - fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - root: flatbuffers::WIPOffset>, -) { - fbb.finish_size_prefixed(root, None); -} diff --git a/src/hyperlight_common/src/flatbuffers/hyperlight/generated/return_value_box_generated.rs b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/return_value_box_generated.rs new file mode 100644 index 000000000..cecd8b6c1 --- /dev/null +++ b/src/hyperlight_common/src/flatbuffers/hyperlight/generated/return_value_box_generated.rs @@ -0,0 +1,451 @@ +// automatically generated by the FlatBuffers compiler, do not modify +// @generated +extern crate alloc; +extern crate flatbuffers; +use alloc::boxed::Box; +use alloc::string::{String, ToString}; +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::mem; + +use self::flatbuffers::{EndianScalar, Follow}; +use super::*; +pub enum ReturnValueBoxOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct ReturnValueBox<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for ReturnValueBox<'a> { + type Inner = ReturnValueBox<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: unsafe { flatbuffers::Table::new(buf, loc) }, + } + } +} + +impl<'a> ReturnValueBox<'a> { + pub const VT_VALUE_TYPE: flatbuffers::VOffsetT = 4; + pub const VT_VALUE: flatbuffers::VOffsetT = 6; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + ReturnValueBox { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: flatbuffers::Allocator + 'bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr, A>, + args: &'args ReturnValueBoxArgs, + ) -> flatbuffers::WIPOffset> { + let mut builder = ReturnValueBoxBuilder::new(_fbb); + if let Some(x) = args.value { + builder.add_value(x); + } + builder.add_value_type(args.value_type); + builder.finish() + } + + #[inline] + pub fn value_type(&self) -> ReturnValue { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(ReturnValueBox::VT_VALUE_TYPE, Some(ReturnValue::NONE)) + .unwrap() + } + } + #[inline] + pub fn value(&self) -> flatbuffers::Table<'a> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::>>( + ReturnValueBox::VT_VALUE, + None, + ) + .unwrap() + } + } + #[inline] + #[allow(non_snake_case)] + pub fn value_as_hlint(&self) -> Option> { + if self.value_type() == ReturnValue::hlint { + let u = self.value(); + // Safety: + // Created from a valid Table for this object + // Which contains a valid union in this slot + Some(unsafe { hlint::init_from_table(u) }) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn value_as_hluint(&self) -> Option> { + if self.value_type() == ReturnValue::hluint { + let u = self.value(); + // Safety: + // Created from a valid Table for this object + // Which contains a valid union in this slot + Some(unsafe { hluint::init_from_table(u) }) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn value_as_hllong(&self) -> Option> { + if self.value_type() == ReturnValue::hllong { + let u = self.value(); + // Safety: + // Created from a valid Table for this object + // Which contains a valid union in this slot + Some(unsafe { hllong::init_from_table(u) }) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn value_as_hlulong(&self) -> Option> { + if self.value_type() == ReturnValue::hlulong { + let u = self.value(); + // Safety: + // Created from a valid Table for this object + // Which contains a valid union in this slot + Some(unsafe { hlulong::init_from_table(u) }) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn value_as_hlfloat(&self) -> Option> { + if self.value_type() == ReturnValue::hlfloat { + let u = self.value(); + // Safety: + // Created from a valid Table for this object + // Which contains a valid union in this slot + Some(unsafe { hlfloat::init_from_table(u) }) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn value_as_hldouble(&self) -> Option> { + if self.value_type() == ReturnValue::hldouble { + let u = self.value(); + // Safety: + // Created from a valid Table for this object + // Which contains a valid union in this slot + Some(unsafe { hldouble::init_from_table(u) }) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn value_as_hlstring(&self) -> Option> { + if self.value_type() == ReturnValue::hlstring { + let u = self.value(); + // Safety: + // Created from a valid Table for this object + // Which contains a valid union in this slot + Some(unsafe { hlstring::init_from_table(u) }) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn value_as_hlbool(&self) -> Option> { + if self.value_type() == ReturnValue::hlbool { + let u = self.value(); + // Safety: + // Created from a valid Table for this object + // Which contains a valid union in this slot + Some(unsafe { hlbool::init_from_table(u) }) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn value_as_hlvoid(&self) -> Option> { + if self.value_type() == ReturnValue::hlvoid { + let u = self.value(); + // Safety: + // Created from a valid Table for this object + // Which contains a valid union in this slot + Some(unsafe { hlvoid::init_from_table(u) }) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn value_as_hlsizeprefixedbuffer(&self) -> Option> { + if self.value_type() == ReturnValue::hlsizeprefixedbuffer { + let u = self.value(); + // Safety: + // Created from a valid Table for this object + // Which contains a valid union in this slot + Some(unsafe { hlsizeprefixedbuffer::init_from_table(u) }) + } else { + None + } + } +} + +impl flatbuffers::Verifiable for ReturnValueBox<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, + pos: usize, + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_union::( + "value_type", + Self::VT_VALUE_TYPE, + "value", + Self::VT_VALUE, + true, + |key, v, pos| match key { + ReturnValue::hlint => v + .verify_union_variant::>( + "ReturnValue::hlint", + pos, + ), + ReturnValue::hluint => v + .verify_union_variant::>( + "ReturnValue::hluint", + pos, + ), + ReturnValue::hllong => v + .verify_union_variant::>( + "ReturnValue::hllong", + pos, + ), + ReturnValue::hlulong => v + .verify_union_variant::>( + "ReturnValue::hlulong", + pos, + ), + ReturnValue::hlfloat => v + .verify_union_variant::>( + "ReturnValue::hlfloat", + pos, + ), + ReturnValue::hldouble => v + .verify_union_variant::>( + "ReturnValue::hldouble", + pos, + ), + ReturnValue::hlstring => v + .verify_union_variant::>( + "ReturnValue::hlstring", + pos, + ), + ReturnValue::hlbool => v + .verify_union_variant::>( + "ReturnValue::hlbool", + pos, + ), + ReturnValue::hlvoid => v + .verify_union_variant::>( + "ReturnValue::hlvoid", + pos, + ), + ReturnValue::hlsizeprefixedbuffer => v + .verify_union_variant::>( + "ReturnValue::hlsizeprefixedbuffer", + pos, + ), + _ => Ok(()), + }, + )? + .finish(); + Ok(()) + } +} +pub struct ReturnValueBoxArgs { + pub value_type: ReturnValue, + pub value: Option>, +} +impl<'a> Default for ReturnValueBoxArgs { + #[inline] + fn default() -> Self { + ReturnValueBoxArgs { + value_type: ReturnValue::NONE, + value: None, // required field + } + } +} + +pub struct ReturnValueBoxBuilder<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> ReturnValueBoxBuilder<'a, 'b, A> { + #[inline] + pub fn add_value_type(&mut self, value_type: ReturnValue) { + self.fbb_.push_slot::( + ReturnValueBox::VT_VALUE_TYPE, + value_type, + ReturnValue::NONE, + ); + } + #[inline] + pub fn add_value(&mut self, value: flatbuffers::WIPOffset) { + self.fbb_ + .push_slot_always::>(ReturnValueBox::VT_VALUE, value); + } + #[inline] + pub fn new( + _fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, + ) -> ReturnValueBoxBuilder<'a, 'b, A> { + let start = _fbb.start_table(); + ReturnValueBoxBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + self.fbb_.required(o, ReturnValueBox::VT_VALUE, "value"); + flatbuffers::WIPOffset::new(o.value()) + } +} + +impl core::fmt::Debug for ReturnValueBox<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("ReturnValueBox"); + ds.field("value_type", &self.value_type()); + match self.value_type() { + ReturnValue::hlint => { + if let Some(x) = self.value_as_hlint() { + ds.field("value", &x) + } else { + ds.field( + "value", + &"InvalidFlatbuffer: Union discriminant does not match value.", + ) + } + } + ReturnValue::hluint => { + if let Some(x) = self.value_as_hluint() { + ds.field("value", &x) + } else { + ds.field( + "value", + &"InvalidFlatbuffer: Union discriminant does not match value.", + ) + } + } + ReturnValue::hllong => { + if let Some(x) = self.value_as_hllong() { + ds.field("value", &x) + } else { + ds.field( + "value", + &"InvalidFlatbuffer: Union discriminant does not match value.", + ) + } + } + ReturnValue::hlulong => { + if let Some(x) = self.value_as_hlulong() { + ds.field("value", &x) + } else { + ds.field( + "value", + &"InvalidFlatbuffer: Union discriminant does not match value.", + ) + } + } + ReturnValue::hlfloat => { + if let Some(x) = self.value_as_hlfloat() { + ds.field("value", &x) + } else { + ds.field( + "value", + &"InvalidFlatbuffer: Union discriminant does not match value.", + ) + } + } + ReturnValue::hldouble => { + if let Some(x) = self.value_as_hldouble() { + ds.field("value", &x) + } else { + ds.field( + "value", + &"InvalidFlatbuffer: Union discriminant does not match value.", + ) + } + } + ReturnValue::hlstring => { + if let Some(x) = self.value_as_hlstring() { + ds.field("value", &x) + } else { + ds.field( + "value", + &"InvalidFlatbuffer: Union discriminant does not match value.", + ) + } + } + ReturnValue::hlbool => { + if let Some(x) = self.value_as_hlbool() { + ds.field("value", &x) + } else { + ds.field( + "value", + &"InvalidFlatbuffer: Union discriminant does not match value.", + ) + } + } + ReturnValue::hlvoid => { + if let Some(x) = self.value_as_hlvoid() { + ds.field("value", &x) + } else { + ds.field( + "value", + &"InvalidFlatbuffer: Union discriminant does not match value.", + ) + } + } + ReturnValue::hlsizeprefixedbuffer => { + if let Some(x) = self.value_as_hlsizeprefixedbuffer() { + ds.field("value", &x) + } else { + ds.field( + "value", + &"InvalidFlatbuffer: Union discriminant does not match value.", + ) + } + } + _ => { + let x: Option<()> = None; + ds.field("value", &x) + } + }; + ds.finish() + } +} diff --git a/src/hyperlight_common/src/flatbuffers/mod.rs b/src/hyperlight_common/src/flatbuffers/mod.rs index d0a859cd8..bf8582877 100644 --- a/src/hyperlight_common/src/flatbuffers/mod.rs +++ b/src/hyperlight_common/src/flatbuffers/mod.rs @@ -2,7 +2,6 @@ // @generated pub mod hyperlight { use super::*; - #[allow(mismatched_lifetime_syntaxes)] pub mod generated { use super::*; mod parameter_value_generated; @@ -13,6 +12,14 @@ pub mod hyperlight { pub use self::return_type_generated::*; mod return_value_generated; pub use self::return_value_generated::*; + mod error_code_generated; + pub use self::error_code_generated::*; + mod function_call_result_type_generated; + pub use self::function_call_result_type_generated::*; + mod function_call_type_generated; + pub use self::function_call_type_generated::*; + mod log_level_generated; + pub use self::log_level_generated::*; mod hlint_generated; pub use self::hlint_generated::*; mod hluint_generated; @@ -31,29 +38,25 @@ pub mod hyperlight { pub use self::hlbool_generated::*; mod hlvecbytes_generated; pub use self::hlvecbytes_generated::*; + mod hlsizeprefixedbuffer_generated; + pub use self::hlsizeprefixedbuffer_generated::*; mod hlvoid_generated; pub use self::hlvoid_generated::*; + mod guest_error_generated; + pub use self::guest_error_generated::*; + mod return_value_box_generated; + pub use self::return_value_box_generated::*; mod function_call_result_generated; pub use self::function_call_result_generated::*; mod parameter_generated; pub use self::parameter_generated::*; mod function_call_generated; pub use self::function_call_generated::*; - mod function_call_type_generated; - pub use self::function_call_type_generated::*; - mod error_code_generated; - pub use self::error_code_generated::*; - mod guest_error_generated; - pub use self::guest_error_generated::*; + mod guest_log_data_generated; + pub use self::guest_log_data_generated::*; mod host_function_definition_generated; pub use self::host_function_definition_generated::*; mod host_function_details_generated; pub use self::host_function_details_generated::*; - mod hlsizeprefixedbuffer_generated; - pub use self::hlsizeprefixedbuffer_generated::*; - mod log_level_generated; - pub use self::log_level_generated::*; - mod guest_log_data_generated; - pub use self::guest_log_data_generated::*; - } -} + } // generated +} // hyperlight diff --git a/src/hyperlight_guest/src/guest_handle/host_comm.rs b/src/hyperlight_guest/src/guest_handle/host_comm.rs index 17b5300e5..5802d08f7 100644 --- a/src/hyperlight_guest/src/guest_handle/host_comm.rs +++ b/src/hyperlight_guest/src/guest_handle/host_comm.rs @@ -22,9 +22,9 @@ use core::slice::from_raw_parts; use flatbuffers::FlatBufferBuilder; use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType}; use hyperlight_common::flatbuffer_wrappers::function_types::{ - ParameterValue, ReturnType, ReturnValue, + FunctionCallResult, ParameterValue, ReturnType, ReturnValue, }; -use hyperlight_common::flatbuffer_wrappers::guest_error::{ErrorCode, GuestError}; +use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_common::flatbuffer_wrappers::guest_log_data::GuestLogData; use hyperlight_common::flatbuffer_wrappers::guest_log_level::LogLevel; use hyperlight_common::flatbuffer_wrappers::host_function_details::HostFunctionDetails; @@ -68,18 +68,24 @@ impl GuestHandle { /// internally to get the return value. #[hyperlight_guest_tracing::trace_function] pub fn get_host_return_value>(&self) -> Result { - let return_value = self - .try_pop_shared_input_data_into::() - .expect("Unable to deserialize a return value from host"); - T::try_from(return_value).map_err(|_| { - HyperlightGuestError::new( - ErrorCode::GuestError, - format!( - "Host return value was not a {} as expected", - core::any::type_name::() - ), - ) - }) + let inner = self + .try_pop_shared_input_data_into::() + .expect("Unable to deserialize a return value from host") + .into_inner(); + + match inner { + Ok(ret) => T::try_from(ret).map_err(|_| { + let expected = core::any::type_name::(); + HyperlightGuestError::new( + ErrorCode::UnsupportedParameterType, + format!("Host return value could not be converted to expected {expected}",), + ) + }), + Err(e) => Err(HyperlightGuestError { + kind: e.code, + message: e.message, + }), + } } /// Call a host function without reading its return value from shared mem. @@ -148,22 +154,6 @@ impl GuestHandle { .expect("Failed to convert buffer to HostFunctionDetails") } - /// Write an error to the shared output data buffer. - #[hyperlight_guest_tracing::trace_function] - pub fn write_error(&self, error_code: ErrorCode, message: Option<&str>) { - let guest_error: GuestError = GuestError::new( - error_code, - message.map_or("".to_string(), |m| m.to_string()), - ); - let guest_error_buffer: Vec = (&guest_error) - .try_into() - .expect("Invalid guest_error_buffer, could not be converted to a Vec"); - - if let Err(e) = self.push_shared_output_data(&guest_error_buffer) { - panic!("Unable to push guest error to shared output data: {:#?}", e); - } - } - /// Log a message with the specified log level, source, caller, source file, and line number. #[hyperlight_guest_tracing::trace_function] pub fn log_message( diff --git a/src/hyperlight_guest_bin/Cargo.toml b/src/hyperlight_guest_bin/Cargo.toml index c21d00c91..31dfe4030 100644 --- a/src/hyperlight_guest_bin/Cargo.toml +++ b/src/hyperlight_guest_bin/Cargo.toml @@ -27,6 +27,8 @@ hyperlight-guest-tracing = { workspace = true, default-features = false } buddy_system_allocator = "0.11.0" log = { version = "0.4", default-features = false } spin = "0.10.0" +flatbuffers = { version = "25.2.10", default-features = false } + [lints] workspace = true diff --git a/src/hyperlight_guest_bin/src/guest_err.rs b/src/hyperlight_guest_bin/src/guest_err.rs deleted file mode 100644 index 0b384a391..000000000 --- a/src/hyperlight_guest_bin/src/guest_err.rs +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -use core::ffi::{CStr, c_char}; - -use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; -use hyperlight_guest::exit::halt; - -use crate::GUEST_HANDLE; - -/// Exposes a C API to allow the guest to set an error -/// -/// # Safety -/// TODO -/// cbindgen:ignore -#[unsafe(no_mangle)] -#[allow(non_camel_case_types)] -pub unsafe extern "C" fn setError(code: u64, message: *const c_char) { - let handle = unsafe { GUEST_HANDLE }; - - let error_code = ErrorCode::from(code); - match message.is_null() { - true => handle.write_error(error_code, None), - false => { - let message = unsafe { CStr::from_ptr(message).to_str().ok() } - .expect("Invalid error message, could not be converted to a string"); - handle.write_error(error_code, Some(message)); - } - } - - halt(); -} diff --git a/src/hyperlight_guest_bin/src/guest_function/call.rs b/src/hyperlight_guest_bin/src/guest_function/call.rs index 7eabdeb29..7bc3ca087 100644 --- a/src/hyperlight_guest_bin/src/guest_function/call.rs +++ b/src/hyperlight_guest_bin/src/guest_function/call.rs @@ -17,9 +17,10 @@ limitations under the License. use alloc::format; use alloc::vec::Vec; +use flatbuffers::FlatBufferBuilder; use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType}; -use hyperlight_common::flatbuffer_wrappers::function_types::ParameterType; -use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; +use hyperlight_common::flatbuffer_wrappers::function_types::{FunctionCallResult, ParameterType}; +use hyperlight_common::flatbuffer_wrappers::guest_error::{ErrorCode, GuestError}; use hyperlight_guest::error::{HyperlightGuestError, Result}; use hyperlight_guest::exit::halt; @@ -81,10 +82,12 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result // This function is marked as no_mangle/inline to prevent the compiler from inlining it , if its inlined the epilogue will not be called // and we will leak memory as the epilogue will not be called as halt() is not going to return. +// +// This function may panic, as we have no other ways of dealing with errors at this level #[unsafe(no_mangle)] #[inline(never)] #[hyperlight_guest_tracing::trace_function] -fn internal_dispatch_function() -> Result<()> { +fn internal_dispatch_function() { let handle = unsafe { GUEST_HANDLE }; #[cfg(debug_assertions)] @@ -94,11 +97,24 @@ fn internal_dispatch_function() -> Result<()> { .try_pop_shared_input_data_into::() .expect("Function call deserialization failed"); - let result_vec = call_guest_function(function_call).inspect_err(|e| { - handle.write_error(e.kind, Some(e.message.as_str())); - })?; + let res = call_guest_function(function_call); - handle.push_shared_output_data(&result_vec) + match res { + Ok(bytes) => { + handle + .push_shared_output_data(bytes.as_slice()) + .expect("Failed to serialize function call result"); + } + Err(err) => { + let guest_error = Err(GuestError::new(err.kind, err.message)); + let fcr = FunctionCallResult::new(guest_error); + let mut builder = FlatBufferBuilder::new(); + let data = fcr.encode(&mut builder); + handle + .push_shared_output_data(data) + .expect("Failed to serialize function call result"); + } + } } // This is implemented as a separate function to make sure that epilogue in the internal_dispatch_function is called before the halt() @@ -117,6 +133,6 @@ pub(crate) extern "C" fn dispatch_function() { // part of the big identity-mapped region at the base of the // guest. crate::paging::flush_tlb(); - let _ = internal_dispatch_function(); + internal_dispatch_function(); halt(); } diff --git a/src/hyperlight_guest_bin/src/lib.rs b/src/hyperlight_guest_bin/src/lib.rs index 8686aab5e..1c6089a0e 100644 --- a/src/hyperlight_guest_bin/src/lib.rs +++ b/src/hyperlight_guest_bin/src/lib.rs @@ -45,7 +45,6 @@ pub mod exceptions { pub(super) mod idtr; mod interrupt_entry; } -pub mod guest_err; pub mod guest_function { pub(super) mod call; pub mod definition; @@ -121,7 +120,7 @@ pub(crate) static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::empty(); pub(crate) static HEAP_ALLOCATOR: ProfiledLockedHeap<32> = ProfiledLockedHeap(LockedHeap::<32>::empty()); -pub(crate) static mut GUEST_HANDLE: GuestHandle = GuestHandle::new(); +pub static mut GUEST_HANDLE: GuestHandle = GuestHandle::new(); pub(crate) static mut REGISTERED_GUEST_FUNCTIONS: GuestFunctionRegister = GuestFunctionRegister::new(); diff --git a/src/hyperlight_guest_capi/Cargo.toml b/src/hyperlight_guest_capi/Cargo.toml index 66bc454ab..1a9c277c2 100644 --- a/src/hyperlight_guest_capi/Cargo.toml +++ b/src/hyperlight_guest_capi/Cargo.toml @@ -15,6 +15,8 @@ workspace = true hyperlight-guest = { workspace = true, default-features = false } hyperlight-guest-bin = { workspace = true, default-features = true } hyperlight-common = { workspace = true, default-features = false } + +flatbuffers = { version = "25.2.10", default-features = false } log = { version = "0.4", default-features = false } [build-dependencies] diff --git a/src/hyperlight_guest_capi/src/error.rs b/src/hyperlight_guest_capi/src/error.rs index a6be2bf59..03217600e 100644 --- a/src/hyperlight_guest_capi/src/error.rs +++ b/src/hyperlight_guest_capi/src/error.rs @@ -14,15 +14,32 @@ See the License for the specific language governing permissions and limitations under the License. */ -use core::ffi::c_char; +use core::ffi::{CStr, c_char}; -use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; -use hyperlight_guest_bin::guest_err::setError; +use flatbuffers::FlatBufferBuilder; +use hyperlight_common::flatbuffer_wrappers::function_types::FunctionCallResult; +use hyperlight_common::flatbuffer_wrappers::guest_error::{ErrorCode, GuestError}; +use hyperlight_guest_bin::GUEST_HANDLE; + +use crate::alloc::borrow::ToOwned; #[unsafe(no_mangle)] pub extern "C" fn hl_set_error(err: ErrorCode, message: *const c_char) { + let cstr = unsafe { CStr::from_ptr(message) }; + let guest_error = Err(GuestError::new( + err.into(), + cstr.to_str() + .expect("Failed to convert CStr to &str") + .to_owned(), + )); + let fcr = FunctionCallResult::new(guest_error); + let mut builder = FlatBufferBuilder::new(); + let data = fcr.encode(&mut builder); unsafe { - setError(err.into(), message); + #[allow(static_mut_refs)] // we are single threaded + GUEST_HANDLE + .push_shared_output_data(data) + .expect("Failed to set error") } } diff --git a/src/hyperlight_host/src/func/guest_err.rs b/src/hyperlight_host/src/func/guest_err.rs deleted file mode 100644 index 27db6d231..000000000 --- a/src/hyperlight_host/src/func/guest_err.rs +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; - -use crate::error::HyperlightError::{GuestError, StackOverflow}; -use crate::mem::mgr::SandboxMemoryManager; -use crate::mem::shared_mem::HostSharedMemory; -use crate::metrics::{METRIC_GUEST_ERROR, METRIC_GUEST_ERROR_LABEL_CODE}; -use crate::{Result, log_then_return}; - -/// Check for a guest error and return an `Err` if one was found, -/// and `Ok` if one was not found. -pub(crate) fn check_for_guest_error( - mgr: &mut SandboxMemoryManager, -) -> Result<()> { - let guest_err = mgr.get_guest_error().ok(); - let Some(guest_err) = guest_err else { - return Ok(()); - }; - - metrics::counter!( - METRIC_GUEST_ERROR, - METRIC_GUEST_ERROR_LABEL_CODE => (guest_err.code as u64).to_string() - ) - .increment(1); - - match guest_err.code { - ErrorCode::NoError => Ok(()), - ErrorCode::StackOverflow => { - log_then_return!(StackOverflow()); - } - _ => { - log_then_return!(GuestError(guest_err.code, guest_err.message.clone())); - } - } -} diff --git a/src/hyperlight_host/src/func/mod.rs b/src/hyperlight_host/src/func/mod.rs index 57b69dbc4..4290d503d 100644 --- a/src/hyperlight_host/src/func/mod.rs +++ b/src/hyperlight_host/src/func/mod.rs @@ -14,8 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/// Functionality to check for errors after a guest call -pub(crate) mod guest_err; /// Definitions and functionality to enable guest-to-host function calling, /// also called "host functions" /// diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 7d9d0d288..0a5e0916e 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -16,11 +16,11 @@ limitations under the License. use std::cmp::Ordering; +use flatbuffers::FlatBufferBuilder; use hyperlight_common::flatbuffer_wrappers::function_call::{ FunctionCall, validate_guest_function_call_buffer, }; -use hyperlight_common::flatbuffer_wrappers::function_types::ReturnValue; -use hyperlight_common::flatbuffer_wrappers::guest_error::GuestError; +use hyperlight_common::flatbuffer_wrappers::function_types::FunctionCallResult; use hyperlight_common::flatbuffer_wrappers::guest_log_data::GuestLogData; use hyperlight_common::flatbuffer_wrappers::host_function_details::HostFunctionDetails; use tracing::{Span, instrument}; @@ -501,18 +501,19 @@ impl SandboxMemoryManager { ) } - /// Writes a function call result to memory + /// Writes a host function call result to memory #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - pub(crate) fn write_response_from_host_method_call(&mut self, res: &ReturnValue) -> Result<()> { - let function_call_ret_val_buffer = Vec::::try_from(res).map_err(|_| { - new_error!( - "write_response_from_host_method_call: failed to convert ReturnValue to Vec" - ) - })?; + pub(crate) fn write_response_from_host_function_call( + &mut self, + res: &FunctionCallResult, + ) -> Result<()> { + let mut builder = FlatBufferBuilder::new(); + let data = res.encode(&mut builder); + self.shared_mem.push_buffer( self.layout.input_data_buffer_offset, self.layout.sandbox_memory_config.get_input_data_size(), - function_call_ret_val_buffer.as_slice(), + data, ) } @@ -533,10 +534,11 @@ impl SandboxMemoryManager { ) } - /// Reads a function call result from memory + /// Reads a function call result from memory. + /// A function call result can be either an error or a successful return value. #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - pub(crate) fn get_guest_function_call_result(&mut self) -> Result { - self.shared_mem.try_pop_buffer_into::( + pub(crate) fn get_guest_function_call_result(&mut self) -> Result { + self.shared_mem.try_pop_buffer_into::( self.layout.output_data_buffer_offset, self.layout.sandbox_memory_config.get_output_data_size(), ) @@ -551,14 +553,6 @@ impl SandboxMemoryManager { ) } - /// Get the guest error data - pub(crate) fn get_guest_error(&mut self) -> Result { - self.shared_mem.try_pop_buffer_into::( - self.layout.output_data_buffer_offset, - self.layout.sandbox_memory_config.get_output_data_size(), - ) - } - pub(crate) fn clear_io_buffers(&mut self) { // Clear the output data buffer loop { diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index b80a7c960..817c48251 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -28,14 +28,14 @@ use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, Functi use hyperlight_common::flatbuffer_wrappers::function_types::{ ParameterValue, ReturnType, ReturnValue, }; +use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_common::flatbuffer_wrappers::util::estimate_flatbuffer_capacity; use tracing::{Span, instrument}; use super::Callable; use super::host_funcs::FunctionRegistry; use super::snapshot::Snapshot; -use crate::HyperlightError::SnapshotSandboxMismatch; -use crate::func::guest_err::check_for_guest_error; +use crate::HyperlightError::{self, SnapshotSandboxMismatch}; use crate::func::{ParameterTuple, SupportedReturnType}; use crate::hypervisor::{Hypervisor, InterruptHandle}; #[cfg(unix)] @@ -44,7 +44,9 @@ use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::ptr::RawPtr; use crate::mem::shared_mem::HostSharedMemory; -use crate::metrics::maybe_time_and_emit_guest_call; +use crate::metrics::{ + METRIC_GUEST_ERROR, METRIC_GUEST_ERROR_LABEL_CODE, maybe_time_and_emit_guest_call, +}; use crate::{Result, log_then_return}; /// Global counter for assigning unique IDs to sandboxes @@ -410,9 +412,24 @@ impl MultiUseSandbox { )?; self.mem_mgr.check_stack_guard()?; - check_for_guest_error(&mut self.mem_mgr)?; - self.mem_mgr.get_guest_function_call_result() + let guest_result = self.mem_mgr.get_guest_function_call_result()?.into_inner(); + + match guest_result { + Ok(val) => Ok(val), + Err(guest_error) => { + metrics::counter!( + METRIC_GUEST_ERROR, + METRIC_GUEST_ERROR_LABEL_CODE => (guest_error.code as u64).to_string() + ) + .increment(1); + + Err(match guest_error.code { + ErrorCode::StackOverflow => HyperlightError::StackOverflow(), + _ => HyperlightError::GuestError(guest_error.code, guest_error.message), + }) + } + } })(); // In the happy path we do not need to clear io-buffers from the host because: @@ -493,6 +510,43 @@ mod tests { use crate::sandbox::SandboxConfiguration; use crate::{GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox}; + /// Make sure input/output buffers are properly reset after guest call (with host call) + #[test] + fn host_func_error() { + let path = simple_guest_as_string().unwrap(); + let mut sandbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap(); + sandbox + .register("HostError", || -> Result<()> { + Err(HyperlightError::Error("hi".to_string())) + }) + .unwrap(); + let mut sandbox = sandbox.evolve().unwrap(); + + // will exhaust io if leaky + for _ in 0..1000 { + let result = sandbox + .call::( + "CallGivenParamlessHostFuncThatReturnsI64", + "HostError".to_string(), + ) + .unwrap_err(); + + assert!( + matches!(result, HyperlightError::GuestError(code, msg) if code == ErrorCode::HostFunctionError && msg == "hi"), + ); + } + } + + #[test] + fn call_host_func_expect_error() { + let path = simple_guest_as_string().unwrap(); + let sandbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap(); + let mut sandbox = sandbox.evolve().unwrap(); + sandbox + .call::<()>("CallHostExpectError", "SomeUnknownHostFunc".to_string()) + .unwrap(); + } + /// Make sure input/output buffers are properly reset after guest call (with host call) #[test] fn io_buffer_reset() { @@ -606,6 +660,9 @@ mod tests { #[ignore] #[cfg(target_os = "linux")] fn test_violate_seccomp_filters() -> Result<()> { + #[cfg(feature = "seccomp")] + use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; + fn make_get_pid_syscall() -> Result { let pid = unsafe { libc::syscall(libc::SYS_getpid) }; Ok(pid as u64) @@ -629,7 +686,9 @@ mod tests { match res { Ok(_) => panic!("Expected to fail due to seccomp violation"), Err(e) => match e { - HyperlightError::DisallowedSyscall => {} + HyperlightError::GuestError(t, msg) + if t == ErrorCode::HostFunctionError + && msg.contains("Seccomp filter trapped on disallowed syscall") => {} _ => panic!("Expected DisallowedSyscall error: {}", e), }, } diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index 8f9c1166f..6e59c5367 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -22,8 +22,8 @@ use std::sync::{Arc, Mutex}; use fallible_iterator::FallibleIterator; #[cfg(feature = "unwind_guest")] use framehop::Unwinder; -use hyperlight_common::flatbuffer_wrappers::function_types::ParameterValue; -use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; +use hyperlight_common::flatbuffer_wrappers::function_types::{FunctionCallResult, ParameterValue}; +use hyperlight_common::flatbuffer_wrappers::guest_error::{ErrorCode, GuestError}; use hyperlight_common::flatbuffer_wrappers::guest_log_data::GuestLogData; use hyperlight_common::outb::{Exception, OutBAction}; #[cfg(feature = "trace_guest")] @@ -283,8 +283,12 @@ pub(crate) fn handle_outb( let res = host_funcs .try_lock() .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .call_host_function(&name, args)?; - mem_mgr.write_response_from_host_method_call(&res)?; // push input buffers + .call_host_function(&name, args) + .map_err(|e| GuestError::new(ErrorCode::HostFunctionError, e.to_string())); + + let func_result = FunctionCallResult::new(res); + + mem_mgr.write_response_from_host_function_call(&func_result)?; Ok(()) } diff --git a/src/hyperlight_host/tests/sandbox_host_tests.rs b/src/hyperlight_host/tests/sandbox_host_tests.rs index 5255cd811..cfcc0e6c6 100644 --- a/src/hyperlight_host/tests/sandbox_host_tests.rs +++ b/src/hyperlight_host/tests/sandbox_host_tests.rs @@ -351,10 +351,17 @@ fn host_function_error() -> Result<()> { // call guest function that calls host function let mut init_sandbox: MultiUseSandbox = sandbox.evolve()?; let msg = "Hello world"; - let res = init_sandbox - .call::("GuestMethod1", msg.to_string()) - .unwrap_err(); - assert!(matches!(res, HyperlightError::Error(msg) if msg == "Host function error!")); + + for _ in 0..1000 { + let res = init_sandbox + .call::("GuestMethod1", msg.to_string()) + .unwrap_err(); + assert!( + matches!(&res, HyperlightError::GuestError(_, msg) if msg == "Host function error!") // rust guest + || matches!(&res, HyperlightError::GuestAborted(_, msg) if msg.contains("Host function error!")) // c guest + || matches!(&res, HyperlightError::StackOverflow()) // c guest. TODO fix this. C guest leaks when host func returns error guest panics. + ); + } } Ok(()) } diff --git a/src/schema/all.fbs b/src/schema/all.fbs new file mode 100644 index 000000000..9e70a50b8 --- /dev/null +++ b/src/schema/all.fbs @@ -0,0 +1,7 @@ +include "function_types.fbs"; +include "function_call_result.fbs"; +include "function_call.fbs"; +include "guest_error.fbs"; +include "guest_log_data.fbs"; +include "host_function_definition.fbs"; +include "host_function_details.fbs"; \ No newline at end of file diff --git a/src/schema/function_call_result.fbs b/src/schema/function_call_result.fbs index 28a5b6fe3..53ea52b25 100644 --- a/src/schema/function_call_result.fbs +++ b/src/schema/function_call_result.fbs @@ -1,9 +1,21 @@ include "function_types.fbs"; +include "guest_error.fbs"; namespace Hyperlight.Generated; +// Wrapper so ReturnValue (a union) can be a single union variant +table ReturnValueBox { + value: ReturnValue (required); +} + +// Result-like union +union FunctionCallResultType { + ReturnValueBox, + GuestError +} + table FunctionCallResult { - return_value:ReturnValue(required); + result: FunctionCallResultType (required); } root_type FunctionCallResult; \ No newline at end of file diff --git a/src/schema/guest_error.fbs b/src/schema/guest_error.fbs index fca2cc0b0..14dfa85e4 100644 --- a/src/schema/guest_error.fbs +++ b/src/schema/guest_error.fbs @@ -16,7 +16,8 @@ enum ErrorCode: ulong { MallocFailed = 13, // this error is set when malloc returns 0 bytes. GuestFunctionParameterTypeMismatch = 14, // The function call parameter type was not the expected type. GuestError = 15, // An error occurred in the guest Guest implementation should use this along with a message when calling setError. - ArrayLengthParamIsMissing = 16 // Expected a int parameter to follow a byte array + ArrayLengthParamIsMissing = 16, // Expected a int parameter to follow a byte array + HostError = 17 // Guest called Host Function, which errored. } table GuestError { diff --git a/src/tests/rust_guests/dummyguest/Cargo.lock b/src/tests/rust_guests/dummyguest/Cargo.lock index 12437e491..4baf80060 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.lock +++ b/src/tests/rust_guests/dummyguest/Cargo.lock @@ -96,6 +96,7 @@ dependencies = [ "buddy_system_allocator", "cc", "cfg-if", + "flatbuffers", "glob", "hyperlight-common", "hyperlight-guest", diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index 5f9e34407..076ef55f3 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -88,6 +88,7 @@ dependencies = [ "buddy_system_allocator", "cc", "cfg-if", + "flatbuffers", "glob", "hyperlight-common", "hyperlight-guest", diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index 681165a60..bdf8d5f62 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -939,9 +939,45 @@ fn exec_mapped_buffer(function_call: &FunctionCall) -> Result> { } } +fn call_host_expect_error(function_call: &FunctionCall) -> Result> { + if let ParameterValue::String(hostfuncname) = + function_call.parameters.clone().unwrap()[0].clone() + { + let res = call_host_function::(&hostfuncname, None, ReturnType::Int); + + match res { + Ok(_) => Err(HyperlightGuestError::new( + ErrorCode::GuestError, + "Expected host function to fail, but it succeeded".to_string(), + )), + Err(e) => { + assert_eq!(e.kind, ErrorCode::HostFunctionError); + assert_eq!( + e.message, + format!("HostFunction {} was not found", hostfuncname) + ); + Ok(get_flatbuffer_result(())) + } + } + } else { + Err(HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + "Invalid parameters passed to call_host_expect_error".to_string(), + )) + } +} + #[no_mangle] #[hyperlight_guest_tracing::trace_function] pub extern "C" fn hyperlight_main() { + let expect_error_def = GuestFunctionDefinition::new( + "CallHostExpectError".to_string(), + Vec::from(&[ParameterType::String]), + ReturnType::Void, + call_host_expect_error as usize, + ); + register_function(expect_error_def); + let twenty_four_k_in_def = GuestFunctionDefinition::new( "24K_in_8K_out".to_string(), Vec::from(&[ParameterType::VecBytes]), diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index 8ab31004c..c1e385e2c 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -231,6 +231,7 @@ dependencies = [ "buddy_system_allocator", "cc", "cfg-if", + "flatbuffers", "glob", "hyperlight-common", "hyperlight-guest", From ad6fcd8bbbddbd38d6a38026ecb94b61986b73ff Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Wed, 8 Oct 2025 16:25:37 -0700 Subject: [PATCH 231/271] Fix join github actions job (#944) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- .github/workflows/ValidatePullRequest.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ValidatePullRequest.yml b/.github/workflows/ValidatePullRequest.yml index 0a00bbb8e..f5e8b1157 100644 --- a/.github/workflows/ValidatePullRequest.yml +++ b/.github/workflows/ValidatePullRequest.yml @@ -98,9 +98,8 @@ jobs: if: always() runs-on: ubuntu-latest steps: - - name: Previous jobs succeeded - if: ${{ !(contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) }} - run: exit 0 - - name: Previous jobs failed - if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }} - run: exit 1 + # Calculate the exit status of the whole CI workflow. + # If all dependent jobs were successful, this exits with 0 (and the outcome job continues successfully). + # If a some dependent job has failed, this exits with 1. + - name: calculate the correct exit status + run: jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}' From 4a7a3fc1f9f1cb3a43049389c29f906fcb736a7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 04:05:07 +0000 Subject: [PATCH 232/271] Bump wasmparser from 0.239.0 to 0.240.0 (#949) Bumps [wasmparser](https://github.com/bytecodealliance/wasm-tools) from 0.239.0 to 0.240.0. - [Release notes](https://github.com/bytecodealliance/wasm-tools/releases) - [Commits](https://github.com/bytecodealliance/wasm-tools/commits) --- updated-dependencies: - dependency-name: wasmparser dependency-version: 0.240.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9491f3183..d989ce173 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4026,9 +4026,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.239.0" +version = "0.240.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" +checksum = "b722dcf61e0ea47440b53ff83ccb5df8efec57a69d150e4f24882e4eba7e24a4" dependencies = [ "bitflags 2.9.4", "hashbrown", diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index f82b9bb56..af05ad5e5 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -16,7 +16,7 @@ name = "hyperlight_component_macro" proc-macro = true [dependencies] -wasmparser = { version = "0.239.0" } +wasmparser = { version = "0.240.0" } quote = { version = "1.0.41" } proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index 1a03e25d0..301ce0f3f 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -15,7 +15,7 @@ Shared implementation for the procedural macros that generate Hyperlight host an name = "hyperlight_component_util" [dependencies] -wasmparser = { version = "0.239.0" } +wasmparser = { version = "0.240.0" } quote = { version = "1.0.41" } proc-macro2 = { version = "1.0.101" } syn = { version = "2.0.106" } From 99c217c70b3b1818dd20acc1e20337a7887f410a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 04:05:22 +0000 Subject: [PATCH 233/271] Bump windows from 0.62.1 to 0.62.2 (#941) Bumps [windows](https://github.com/microsoft/windows-rs) from 0.62.1 to 0.62.2. - [Release notes](https://github.com/microsoft/windows-rs/releases) - [Commits](https://github.com/microsoft/windows-rs/commits) --- updated-dependencies: - dependency-name: windows dependency-version: 0.62.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 56 +++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d989ce173..6928f7833 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1505,7 +1505,7 @@ dependencies = [ "tracing-tracy", "uuid", "vmm-sys-util", - "windows 0.62.1", + "windows 0.62.2", "windows-result 0.4.1", "windows-sys 0.61.2", "windows-version", @@ -4103,14 +4103,14 @@ dependencies = [ [[package]] name = "windows" -version = "0.62.1" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49e6c4a1f363c8210c6f77ba24f645c61c6fb941eccf013da691f7e09515b8ac" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ - "windows-collections 0.3.1", - "windows-core 0.62.1", - "windows-future 0.3.1", - "windows-numerics 0.3.0", + "windows-collections 0.3.2", + "windows-core 0.62.2", + "windows-future 0.3.2", + "windows-numerics 0.3.1", ] [[package]] @@ -4124,11 +4124,11 @@ dependencies = [ [[package]] name = "windows-collections" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "123e712f464a8a60ce1a13f4c446d2d43ab06464cb5842ff68f5c71b6fb7852e" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-core 0.62.1", + "windows-core 0.62.2", ] [[package]] @@ -4146,15 +4146,15 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.62.1" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", "windows-link 0.2.1", "windows-result 0.4.1", - "windows-strings 0.5.0", + "windows-strings 0.5.1", ] [[package]] @@ -4170,20 +4170,20 @@ dependencies = [ [[package]] name = "windows-future" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f3db6b24b120200d649cd4811b4947188ed3a8d2626f7075146c5d178a9a4a" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "windows-core 0.62.1", + "windows-core 0.62.2", "windows-link 0.2.1", - "windows-threading 0.2.0", + "windows-threading 0.2.1", ] [[package]] name = "windows-implement" -version = "0.60.1" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -4192,9 +4192,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.2" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -4225,11 +4225,11 @@ dependencies = [ [[package]] name = "windows-numerics" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce3498fe0aba81e62e477408383196b4b0363db5e0c27646f932676283b43d8" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-core 0.62.1", + "windows-core 0.62.2", "windows-link 0.2.1", ] @@ -4262,9 +4262,9 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link 0.2.1", ] @@ -4349,9 +4349,9 @@ dependencies = [ [[package]] name = "windows-threading" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab47f085ad6932defa48855254c758cdd0e2f2d48e62a34118a268d8f345e118" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" dependencies = [ "windows-link 0.2.1", ] From 036d3ae1ea907dfd87af52f5c17b46b5c1797958 Mon Sep 17 00:00:00 2001 From: Shailesh Date: Fri, 10 Oct 2025 03:22:01 +0530 Subject: [PATCH 234/271] Closes #274: Adding FFI functions for bool, float, double, string, vecbytes (#950) - Add Tests for CAPI Flatbuffers - Separate function for creating Uninitialized Sandbox for C guests - Ignore Test cases for float and double until Github issue #179 is fixed. Signed-off-by: Shailesh Vashishth --- src/hyperlight_guest_capi/src/flatbuffer.rs | 42 ++++++++- src/hyperlight_host/tests/common/mod.rs | 8 ++ src/hyperlight_host/tests/integration_test.rs | 94 ++++++++++++++++++- src/tests/c_guests/c_simpleguest/main.c | 80 +++++++++++++++- 4 files changed, 221 insertions(+), 3 deletions(-) diff --git a/src/hyperlight_guest_capi/src/flatbuffer.rs b/src/hyperlight_guest_capi/src/flatbuffer.rs index b710d4245..ff12400d6 100644 --- a/src/hyperlight_guest_capi/src/flatbuffer.rs +++ b/src/hyperlight_guest_capi/src/flatbuffer.rs @@ -15,6 +15,9 @@ limitations under the License. */ use alloc::boxed::Box; +use alloc::ffi::CString; +use alloc::string::String; +use alloc::vec::Vec; use core::ffi::{CStr, c_char}; use hyperlight_common::flatbuffer_wrappers::util::get_flatbuffer_result; @@ -92,6 +95,13 @@ pub extern "C" fn hl_flatbuffer_result_from_Bytes(data: *const u8, len: usize) - Box::new(unsafe { FfiVec::from_vec(vec) }) } +#[unsafe(no_mangle)] +pub extern "C" fn hl_flatbuffer_result_from_Bool(value: bool) -> Box { + let vec = get_flatbuffer_result(value); + + Box::new(unsafe { FfiVec::from_vec(vec) }) +} + //--- Functions for getting values returned by host functions calls #[unsafe(no_mangle)] @@ -115,4 +125,34 @@ pub extern "C" fn hl_get_host_return_value_as_ULong() -> u64 { get_host_return_value().expect("Unable to get host return value as ulong") } -// TODO add bool, float, double, string, vecbytes +#[unsafe(no_mangle)] +pub extern "C" fn hl_get_host_return_value_as_Bool() -> bool { + get_host_return_value().expect("Unable to get host return value as bool") +} + +#[unsafe(no_mangle)] +pub extern "C" fn hl_get_host_return_value_as_Float() -> f32 { + get_host_return_value().expect("Unable to get host return value as f32") +} + +#[unsafe(no_mangle)] +pub extern "C" fn hl_get_host_return_value_as_Double() -> f64 { + get_host_return_value().expect("Unable to get host return value as f64") +} + +#[unsafe(no_mangle)] +pub extern "C" fn hl_get_host_return_value_as_String() -> *const c_char { + let string_value: String = + get_host_return_value().expect("Unable to get host return value as string"); + + let c_string = CString::new(string_value).expect("Failed to create CString"); + c_string.into_raw() +} + +#[unsafe(no_mangle)] +pub extern "C" fn hl_get_host_return_value_as_VecBytes() -> Box { + let vec_value: Vec = + get_host_return_value().expect("Unable to get host return value as vec bytes"); + + Box::new(unsafe { FfiVec::from_vec(vec_value) }) +} diff --git a/src/hyperlight_host/tests/common/mod.rs b/src/hyperlight_host/tests/common/mod.rs index ab1a97b71..41016d1be 100644 --- a/src/hyperlight_host/tests/common/mod.rs +++ b/src/hyperlight_host/tests/common/mod.rs @@ -35,6 +35,14 @@ pub fn new_uninit_rust() -> Result { ) } +/// Returns a c-language simpleguest. +pub fn new_uninit_c() -> Result { + UninitializedSandbox::new( + GuestBinary::FilePath(c_simple_guest_as_string().unwrap()), + None, + ) +} + pub fn get_simpleguest_sandboxes( writer: Option>, // An optional writer to make sure correct info is passed to the host printer ) -> Vec { diff --git a/src/hyperlight_host/tests/integration_test.rs b/src/hyperlight_host/tests/integration_test.rs index be3ead190..0869a9d5a 100644 --- a/src/hyperlight_host/tests/integration_test.rs +++ b/src/hyperlight_host/tests/integration_test.rs @@ -28,7 +28,7 @@ use hyperlight_testing::{c_simple_guest_as_string, simple_guest_as_string}; use log::LevelFilter; pub mod common; // pub to disable dead_code warning -use crate::common::{new_uninit, new_uninit_rust}; +use crate::common::{new_uninit, new_uninit_c, new_uninit_rust}; // A host function cannot be interrupted, but we can at least make sure after requesting to interrupt a host call, // we don't re-enter the guest again once the host call is done @@ -765,3 +765,95 @@ fn log_test_messages(levelfilter: Option) { .unwrap(); } } + +/// Tests whether host is able to return Bool as return type +/// or not +#[test] +fn test_if_guest_is_able_to_get_bool_return_values_from_host() { + let mut sbox1 = new_uninit_c().unwrap(); + + sbox1 + .register("HostBool", |a: i32, b: i32| a + b > 10) + .unwrap(); + let mut sbox3 = sbox1.evolve().unwrap(); + + for i in 1..10 { + if i < 6 { + let res = sbox3 + .call::("GuestRetrievesBoolValue", (i, i)) + .unwrap(); + println!("{:?}", res); + assert!(!res); + } else { + let res = sbox3 + .call::("GuestRetrievesBoolValue", (i, i)) + .unwrap(); + println!("{:?}", res); + assert!(res); + } + } +} + +/// Tests whether host is able to return Float/f32 as return type +/// or not +/// Adding Ignore attribute, due known issues with float and double +/// calculations - see Github issue #179. Once it is fixed we can +/// remove ignore attribute +#[ignore] +#[test] +fn test_if_guest_is_able_to_get_float_return_values_from_host() { + let mut sbox1 = new_uninit_c().unwrap(); + + sbox1 + .register("HostAddFloat", |a: f32, b: f32| a + b) + .unwrap(); + let mut sbox3 = sbox1.evolve().unwrap(); + let res = sbox3 + .call::("GuestRetrievesFloatValue", (1.34_f32, 1.34_f32)) + .unwrap(); + println!("{:?}", res); + assert_eq!(res, 2.68_f32); +} + +/// Tests whether host is able to return Double/f64 as return type +/// or not +/// Adding Ignore attribute, due known issues with float and double +/// calculations - see Github issue #179. Once it is fixed we can +/// remove ignore attribute +#[ignore] +#[test] +fn test_if_guest_is_able_to_get_double_return_values_from_host() { + let mut sbox1 = new_uninit_c().unwrap(); + + sbox1 + .register("HostAddDouble", |a: f64, b: f64| a + b) + .unwrap(); + let mut sbox3 = sbox1.evolve().unwrap(); + let res = sbox3 + .call::("GuestRetrievesDoubleValue", (1.34_f64, 1.34_f64)) + .unwrap(); + println!("{:?}", res); + assert_eq!(res, 2.68_f64); +} + +/// Tests whether host is able to return String as return type +/// or not +#[test] +fn test_if_guest_is_able_to_get_string_return_values_from_host() { + let mut sbox1 = new_uninit_c().unwrap(); + + sbox1 + .register("HostAddStrings", |a: String| { + a + ", string added by Host Function" + }) + .unwrap(); + let mut sbox3 = sbox1.evolve().unwrap(); + let res = sbox3 + .call::("GuestRetrievesStringValue", ()) + .unwrap(); + println!("{:?}", res); + assert_eq!( + res, + "Guest Function, string added by Host Function".to_string() + ); +} diff --git a/src/tests/c_guests/c_simpleguest/main.c b/src/tests/c_guests/c_simpleguest/main.c index 2822b108d..30caff590 100644 --- a/src/tests/c_guests/c_simpleguest/main.c +++ b/src/tests/c_guests/c_simpleguest/main.c @@ -256,6 +256,80 @@ int guest_function(const char *from_host) { return 0; } +bool guest_fn_checks_if_host_returns_bool_value(int32_t a, int32_t b) { + hl_Parameter params[2]; + + params[0].tag = hl_ParameterType_Int; + params[0].value.Int = a; + + params[1].tag = hl_ParameterType_Int; + params[1].value.Int = b; + + const hl_FunctionCall host_call = {.function_name = "HostBool", + .parameters = params, + .parameters_len = 2, + .return_type = hl_ReturnType_Bool + }; + hl_call_host_function(&host_call); + return hl_get_host_return_value_as_Bool(); +} + +float guest_fn_checks_if_host_returns_float_value(float a, float b) { + hl_Parameter params[2]; + + params[0].tag = hl_ParameterType_Float; + params[0].value.Float = a; + + params[1].tag = hl_ParameterType_Float; + params[1].value.Float = b; + + const hl_FunctionCall host_call = {.function_name = "HostAddFloat", + .parameters = params, + .parameters_len = 2, + .return_type = hl_ReturnType_Float + }; + hl_call_host_function(&host_call); + return hl_get_host_return_value_as_Float(); +} + +double guest_fn_checks_if_host_returns_double_value(double a, double b) { + hl_Parameter params[2]; + + params[0].tag = hl_ParameterType_Double; + params[0].value.Double = a; + + params[1].tag = hl_ParameterType_Double; + params[1].value.Double = b; + + const hl_FunctionCall host_call = {.function_name = "HostAddDouble", + .parameters = params, + .parameters_len = 2, + .return_type = hl_ReturnType_Double + }; + hl_call_host_function(&host_call); + return hl_get_host_return_value_as_Double(); +} + +const char* guest_fn_checks_if_host_returns_string_value() { + char guest_message[256] = "Guest Function"; + hl_Parameter params; + + params.tag = hl_ParameterType_String; + params.value.String = guest_message; + + const hl_FunctionCall host_call = {.function_name = "HostAddStrings", + .parameters = ¶ms, + .parameters_len = 1, + .return_type = hl_ReturnType_String + }; + hl_call_host_function(&host_call); + return hl_get_host_return_value_as_String(); +} + +HYPERLIGHT_WRAP_FUNCTION(guest_fn_checks_if_host_returns_float_value, Float, 2, Float, Float) +HYPERLIGHT_WRAP_FUNCTION(guest_fn_checks_if_host_returns_double_value, Double, 2, Double, Double) +HYPERLIGHT_WRAP_FUNCTION(guest_fn_checks_if_host_returns_string_value, String, 0) +HYPERLIGHT_WRAP_FUNCTION(guest_fn_checks_if_host_returns_bool_value, Bool, 2, Int, Int) HYPERLIGHT_WRAP_FUNCTION(echo, String, 1, String) // HYPERLIGHT_WRAP_FUNCTION(set_byte_array_to_zero, 1, VecBytes) is not valid for functions that return VecBytes HYPERLIGHT_WRAP_FUNCTION(guest_function, Int, 1, String) @@ -289,6 +363,10 @@ HYPERLIGHT_WRAP_FUNCTION(log_message, Int, 2, String, Long) void hyperlight_main(void) { + HYPERLIGHT_REGISTER_FUNCTION("GuestRetrievesFloatValue", guest_fn_checks_if_host_returns_float_value); + HYPERLIGHT_REGISTER_FUNCTION("GuestRetrievesDoubleValue", guest_fn_checks_if_host_returns_double_value); + HYPERLIGHT_REGISTER_FUNCTION("GuestRetrievesStringValue", guest_fn_checks_if_host_returns_string_value); + HYPERLIGHT_REGISTER_FUNCTION("GuestRetrievesBoolValue", guest_fn_checks_if_host_returns_bool_value); HYPERLIGHT_REGISTER_FUNCTION("Echo", echo); // HYPERLIGHT_REGISTER_FUNCTION macro does not work for functions that return VecBytes, // so we use hl_register_function_definition directly @@ -338,4 +416,4 @@ hl_Vec *c_guest_dispatch_function(const hl_FunctionCall *function_call) { } return NULL; -} +} \ No newline at end of file From 741f7f40dc9a9ad9ede1fb2a861621e221abe749 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 04:05:24 +0000 Subject: [PATCH 235/271] Bump libc from 0.2.176 to 0.2.177 (#952) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.176 to 0.2.177. - [Release notes](https://github.com/rust-lang/libc/releases) - [Changelog](https://github.com/rust-lang/libc/blob/0.2.177/CHANGELOG.md) - [Commits](https://github.com/rust-lang/libc/compare/0.2.176...0.2.177) --- updated-dependencies: - dependency-name: libc dependency-version: 0.2.177 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6928f7833..a8c68a567 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1821,9 +1821,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.176" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libfuzzer-sys" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index bce81f2e1..593c43c1d 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -26,7 +26,7 @@ gdbstub_arch = { version = "0.3.2", optional = true } goblin = { version = "0.10", default-features = false, features = ["std", "elf32", "elf64", "endian_fd"] } rand = { version = "0.9" } cfg-if = { version = "1.0.3" } -libc = { version = "0.2.176" } +libc = { version = "0.2.177" } flatbuffers = "25.9.23" framehop = { version = "0.15.0", optional = true } fallible-iterator = { version = "0.3.0", optional = true } From 9e4b9cbf3c1deeb53ec50dbf175afec033634114 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 04:05:41 +0000 Subject: [PATCH 236/271] Bump gdbstub from 0.7.7 to 0.7.8 (#954) Bumps [gdbstub](https://github.com/daniel5151/gdbstub) from 0.7.7 to 0.7.8. - [Release notes](https://github.com/daniel5151/gdbstub/releases) - [Changelog](https://github.com/daniel5151/gdbstub/blob/master/CHANGELOG.md) - [Commits](https://github.com/daniel5151/gdbstub/compare/0.7.7...0.7.8) --- updated-dependencies: - dependency-name: gdbstub dependency-version: 0.7.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a8c68a567..566c40f6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1012,9 +1012,9 @@ dependencies = [ [[package]] name = "gdbstub" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b686b198dfaa4109ebd0443d2841bc521e4b4b2915f1d84b3bb50332a8cdc1ae" +checksum = "72742d2b395902caf8a5d520d0dd3334ba6d1138938429200e58d5174e275f3f" dependencies = [ "bitflags 2.9.4", "cfg-if", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 593c43c1d..e15028dd6 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -21,7 +21,7 @@ bench = false # see https://bheisler.github.io/criterion.rs/book/faq.html#cargo- workspace = true [dependencies] -gdbstub = { version = "0.7.7", optional = true } +gdbstub = { version = "0.7.8", optional = true } gdbstub_arch = { version = "0.3.2", optional = true } goblin = { version = "0.10", default-features = false, features = ["std", "elf32", "elf64", "endian_fd"] } rand = { version = "0.9" } From 11fdcdd0301a1e2d3bbd28ed4c45d786ce2224e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 04:05:46 +0000 Subject: [PATCH 237/271] Bump cc from 1.2.40 to 1.2.41 (#953) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.40 to 1.2.41. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.40...cc-v1.2.41) --- updated-dependencies: - dependency-name: cc dependency-version: 1.2.41 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 566c40f6f..42f19ad23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,9 +362,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.40" +version = "1.2.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" dependencies = [ "find-msvc-tools", "jobserver", @@ -835,9 +835,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "flatbuffers" From e3ae8310836459404573cd4bbf385854480abba4 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Oct 2025 14:45:45 -0700 Subject: [PATCH 238/271] Remove redundant local import of ErrorCode in test function (#948) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- src/hyperlight_host/src/sandbox/initialized_multi_use.rs | 3 --- src/tests/rust_guests/witguest/Cargo.lock | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 817c48251..6dc02d71f 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -660,9 +660,6 @@ mod tests { #[ignore] #[cfg(target_os = "linux")] fn test_violate_seccomp_filters() -> Result<()> { - #[cfg(feature = "seccomp")] - use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; - fn make_get_pid_syscall() -> Result { let pid = unsafe { libc::syscall(libc::SYS_getpid) }; Ok(pid as u64) diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index c1e385e2c..281181180 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -522,9 +522,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "wasmparser" -version = "0.239.0" +version = "0.240.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" +checksum = "b722dcf61e0ea47440b53ff83ccb5df8efec57a69d150e4f24882e4eba7e24a4" dependencies = [ "bitflags", "hashbrown", From cdd68b926a0c8cbfdff8d7d10559de48870d20f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Oct 2025 04:05:18 +0000 Subject: [PATCH 239/271] Bump tokio from 1.47.1 to 1.48.0 (#955) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.47.1 to 1.48.0. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.47.1...tokio-1.48.0) --- updated-dependencies: - dependency-name: tokio dependency-version: 1.48.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 71 +++++----------------------------- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 42f19ad23..1e4c38f90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli 0.31.1", -] - [[package]] name = "addr2line" version = "0.25.1" @@ -19,9 +10,9 @@ checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "cpp_demangle", "fallible-iterator", - "gimli 0.32.2", + "gimli", "memmap2", - "object 0.37.3", + "object", "rustc-demangle", "smallvec", "typed-arena", @@ -175,21 +166,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line 0.24.2", - "cfg-if", - "libc", - "miniz_oxide", - "object 0.36.7", - "rustc-demangle", - "windows-targets 0.52.6", -] - [[package]] name = "base64" version = "0.22.1" @@ -916,7 +892,7 @@ dependencies = [ "arrayvec", "cfg-if", "fallible-iterator", - "gimli 0.32.2", + "gimli", "macho-unwind-info", "pe-unwind-info", ] @@ -1081,12 +1057,6 @@ dependencies = [ "wasi 0.14.3+wasi-0.2.4", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "gimli" version = "0.32.2" @@ -1680,17 +1650,6 @@ dependencies = [ "serde", ] -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "libc", -] - [[package]] name = "ipnet" version = "2.11.0" @@ -2175,15 +2134,6 @@ dependencies = [ "syn", ] -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - [[package]] name = "object" version = "0.37.3" @@ -3437,29 +3387,26 @@ dependencies = [ [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", "socket2", "tokio-macros", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", @@ -3588,7 +3535,7 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" name = "trace_dump" version = "0.10.0" dependencies = [ - "addr2line 0.25.1", + "addr2line", "blake3", "piet-common", ] diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index e15028dd6..5cca461f6 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -101,7 +101,7 @@ opentelemetry = "0.30.0" opentelemetry-otlp = { version = "0.30.0", default-features = false, features = ["http-proto", "reqwest-blocking-client"] } opentelemetry-semantic-conventions = "0.31" opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio"] } -tokio = { version = "1.47.1", features = ["full"] } +tokio = { version = "1.48.0", features = ["full"] } criterion = "0.7.0" tracing-chrome = "0.7.2" metrics-util = "0.20.0" From 1ed8cd2ec260a7f55d990af5b0ca328e9e6fbc3a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Oct 2025 04:05:20 +0000 Subject: [PATCH 240/271] Bump cfg-if from 1.0.3 to 1.0.4 (#958) Bumps [cfg-if](https://github.com/rust-lang/cfg-if) from 1.0.3 to 1.0.4. - [Release notes](https://github.com/rust-lang/cfg-if/releases) - [Changelog](https://github.com/rust-lang/cfg-if/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cfg-if/compare/v1.0.3...v1.0.4) --- updated-dependencies: - dependency-name: cfg-if dependency-version: 1.0.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e4c38f90..e312fab4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -369,9 +369,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 5cca461f6..0b003b20d 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -25,7 +25,7 @@ gdbstub = { version = "0.7.8", optional = true } gdbstub_arch = { version = "0.3.2", optional = true } goblin = { version = "0.10", default-features = false, features = ["std", "elf32", "elf64", "endian_fd"] } rand = { version = "0.9" } -cfg-if = { version = "1.0.3" } +cfg-if = { version = "1.0.4" } libc = { version = "0.2.177" } flatbuffers = "25.9.23" framehop = { version = "0.15.0", optional = true } From b62445ebe56de270c1a4d6449a5a854f451dcd84 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Thu, 16 Oct 2025 17:19:00 -0700 Subject: [PATCH 241/271] Unify register representation (#907) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- .../src/hypervisor/gdb/hyperv_debug.rs | 119 +--- .../src/hypervisor/gdb/kvm_debug.rs | 100 +-- src/hyperlight_host/src/hypervisor/gdb/mod.rs | 44 +- .../src/hypervisor/gdb/mshv_debug.rs | 93 +-- .../src/hypervisor/gdb/x86_64_target.rs | 29 +- .../src/hypervisor/hyperv_linux.rs | 184 ++--- .../src/hypervisor/hyperv_windows.rs | 331 +++------ src/hyperlight_host/src/hypervisor/kvm.rs | 149 ++-- src/hyperlight_host/src/hypervisor/mod.rs | 110 ++- .../src/hypervisor/{fpu.rs => regs.rs} | 23 +- .../src/hypervisor/regs/fpu.rs | 438 ++++++++++++ .../src/hypervisor/regs/special_regs.rs | 667 ++++++++++++++++++ .../src/hypervisor/regs/standard_regs.rs | 423 +++++++++++ .../hypervisor/windows_hypervisor_platform.rs | 491 +++---------- .../src/hypervisor/wrappers.rs | 79 --- src/hyperlight_host/src/sandbox/outb.rs | 35 +- typos.toml | 1 + 17 files changed, 2087 insertions(+), 1229 deletions(-) rename src/hyperlight_host/src/hypervisor/{fpu.rs => regs.rs} (56%) create mode 100644 src/hyperlight_host/src/hypervisor/regs/fpu.rs create mode 100644 src/hyperlight_host/src/hypervisor/regs/special_regs.rs create mode 100644 src/hyperlight_host/src/hypervisor/regs/standard_regs.rs diff --git a/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs b/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs index c6528f8ab..f5b332d02 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs @@ -19,9 +19,10 @@ use std::collections::HashMap; use windows::Win32::System::Hypervisor::WHV_VP_EXCEPTION_CONTEXT; use super::arch::{MAX_NO_OF_HW_BP, vcpu_stop_reason}; -use super::{GuestDebug, SW_BP_SIZE, VcpuStopReason, X86_64Regs}; +use super::{GuestDebug, SW_BP_SIZE, VcpuStopReason}; +use crate::hypervisor::regs::{CommonFpu, CommonRegisters}; use crate::hypervisor::windows_hypervisor_platform::VMProcessor; -use crate::hypervisor::wrappers::{WHvDebugRegisters, WHvGeneralRegisters}; +use crate::hypervisor::wrappers::WHvDebugRegisters; use crate::{HyperlightError, Result, new_error}; /// KVM Debug struct @@ -54,7 +55,7 @@ impl HypervDebug { /// Returns the instruction pointer from the stopped vCPU fn get_instruction_pointer(&self, vcpu_fd: &VMProcessor) -> Result { let regs = vcpu_fd - .get_regs() + .regs() .map_err(|e| new_error!("Could not retrieve registers from vCPU: {:?}", e))?; Ok(regs.rip) @@ -103,7 +104,7 @@ impl HypervDebug { self.single_step = step; let mut regs = vcpu_fd - .get_regs() + .regs() .map_err(|e| new_error!("Could not get registers: {:?}", e))?; // Set TF Flag to enable Traps @@ -114,7 +115,7 @@ impl HypervDebug { } vcpu_fd - .set_general_purpose_registers(®s) + .set_regs(®s) .map_err(|e| new_error!("Could not set guest registers: {:?}", e))?; Ok(()) @@ -185,45 +186,17 @@ impl GuestDebug for HypervDebug { self.sw_breakpoints.remove(addr) } - fn read_regs(&self, vcpu_fd: &Self::Vcpu, regs: &mut X86_64Regs) -> Result<()> { + fn read_regs(&self, vcpu_fd: &Self::Vcpu) -> Result<(CommonRegisters, CommonFpu)> { log::debug!("Read registers"); - let vcpu_regs = vcpu_fd - .get_regs() + let regs = vcpu_fd + .regs() .map_err(|e| new_error!("Could not read guest registers: {:?}", e))?; - regs.rax = vcpu_regs.rax; - regs.rbx = vcpu_regs.rbx; - regs.rcx = vcpu_regs.rcx; - regs.rdx = vcpu_regs.rdx; - regs.rsi = vcpu_regs.rsi; - regs.rdi = vcpu_regs.rdi; - regs.rbp = vcpu_regs.rbp; - regs.rsp = vcpu_regs.rsp; - regs.r8 = vcpu_regs.r8; - regs.r9 = vcpu_regs.r9; - regs.r10 = vcpu_regs.r10; - regs.r11 = vcpu_regs.r11; - regs.r12 = vcpu_regs.r12; - regs.r13 = vcpu_regs.r13; - regs.r14 = vcpu_regs.r14; - regs.r15 = vcpu_regs.r15; - - regs.rip = vcpu_regs.rip; - regs.rflags = vcpu_regs.rflags; - - // Fetch XMM from WHVP - if let Ok(fpu) = vcpu_fd.get_fpu() { - regs.xmm = [ - fpu.xmm0, fpu.xmm1, fpu.xmm2, fpu.xmm3, fpu.xmm4, fpu.xmm5, fpu.xmm6, fpu.xmm7, - fpu.xmm8, fpu.xmm9, fpu.xmm10, fpu.xmm11, fpu.xmm12, fpu.xmm13, fpu.xmm14, - fpu.xmm15, - ]; - regs.mxcsr = fpu.mxcsr; - } else { - log::warn!("Failed to read FPU/XMM via WHVP for debug registers"); - } + let fpu = vcpu_fd + .fpu() + .map_err(|e| new_error!("Could not read guest FPU registers: {:?}", e))?; - Ok(()) + Ok((regs, fpu)) } fn set_single_step(&mut self, vcpu_fd: &Self::Vcpu, enable: bool) -> Result<()> { @@ -236,62 +209,28 @@ impl GuestDebug for HypervDebug { .map_err(|_| HyperlightError::TranslateGuestAddress(gva)) } - fn write_regs(&self, vcpu_fd: &Self::Vcpu, regs: &X86_64Regs) -> Result<()> { + fn write_regs( + &self, + vcpu_fd: &Self::Vcpu, + regs: &CommonRegisters, + fpu: &CommonFpu, + ) -> Result<()> { log::debug!("Write registers"); - let gprs = WHvGeneralRegisters { - rax: regs.rax, - rbx: regs.rbx, - rcx: regs.rcx, - rdx: regs.rdx, - rsi: regs.rsi, - rdi: regs.rdi, - rbp: regs.rbp, - rsp: regs.rsp, - r8: regs.r8, - r9: regs.r9, - r10: regs.r10, - r11: regs.r11, - r12: regs.r12, - r13: regs.r13, - r14: regs.r14, - r15: regs.r15, - - rip: regs.rip, - rflags: regs.rflags, - }; vcpu_fd - .set_general_purpose_registers(&gprs) + .set_regs(regs) .map_err(|e| new_error!("Could not write guest registers: {:?}", e))?; - // Load existing FPU state, replace XMM and MXCSR, and write it back. - let mut fpu = match vcpu_fd.get_fpu() { - Ok(f) => f, - Err(e) => { - return Err(new_error!("Could not write guest registers: {:?}", e)); - } - }; - - fpu.xmm0 = regs.xmm[0]; - fpu.xmm1 = regs.xmm[1]; - fpu.xmm2 = regs.xmm[2]; - fpu.xmm3 = regs.xmm[3]; - fpu.xmm4 = regs.xmm[4]; - fpu.xmm5 = regs.xmm[5]; - fpu.xmm6 = regs.xmm[6]; - fpu.xmm7 = regs.xmm[7]; - fpu.xmm8 = regs.xmm[8]; - fpu.xmm9 = regs.xmm[9]; - fpu.xmm10 = regs.xmm[10]; - fpu.xmm11 = regs.xmm[11]; - fpu.xmm12 = regs.xmm[12]; - fpu.xmm13 = regs.xmm[13]; - fpu.xmm14 = regs.xmm[14]; - fpu.xmm15 = regs.xmm[15]; - fpu.mxcsr = regs.mxcsr; + // Only xmm and mxcsr is piped though in the given fpu, so only set those + let mut current_fpu: CommonFpu = vcpu_fd + .fpu() + .map_err(|e| new_error!("Could not read guest FPU registers: {:?}", e))?; + current_fpu.mxcsr = fpu.mxcsr; + current_fpu.xmm = fpu.xmm; vcpu_fd - .set_fpu(&fpu) - .map_err(|e| new_error!("Could not write guest registers: {:?}", e)) + .set_fpu(¤t_fpu) + .map_err(|e| new_error!("Could not write guest FPU registers: {:?}", e))?; + Ok(()) } } diff --git a/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs b/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs index fdd6943fa..ae5996d49 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs @@ -18,12 +18,13 @@ use std::collections::HashMap; use kvm_bindings::{ KVM_GUESTDBG_ENABLE, KVM_GUESTDBG_SINGLESTEP, KVM_GUESTDBG_USE_HW_BP, KVM_GUESTDBG_USE_SW_BP, - kvm_debug_exit_arch, kvm_guest_debug, kvm_regs, + kvm_debug_exit_arch, kvm_guest_debug, }; use kvm_ioctls::VcpuFd; use super::arch::{MAX_NO_OF_HW_BP, SW_BP_SIZE, vcpu_stop_reason}; -use super::{GuestDebug, VcpuStopReason, X86_64Regs}; +use super::{GuestDebug, VcpuStopReason}; +use crate::hypervisor::regs::{CommonFpu, CommonRegisters}; use crate::{HyperlightError, Result, new_error}; /// KVM Debug struct @@ -167,57 +168,29 @@ impl GuestDebug for KvmDebug { self.sw_breakpoints.remove(addr) } - fn read_regs(&self, vcpu_fd: &Self::Vcpu, regs: &mut X86_64Regs) -> Result<()> { + fn read_regs(&self, vcpu_fd: &Self::Vcpu) -> Result<(CommonRegisters, CommonFpu)> { log::debug!("Read registers"); - let vcpu_regs = vcpu_fd + let regs = vcpu_fd .get_regs() .map_err(|e| new_error!("Could not read guest registers: {:?}", e))?; - regs.rax = vcpu_regs.rax; - regs.rbx = vcpu_regs.rbx; - regs.rcx = vcpu_regs.rcx; - regs.rdx = vcpu_regs.rdx; - regs.rsi = vcpu_regs.rsi; - regs.rdi = vcpu_regs.rdi; - regs.rbp = vcpu_regs.rbp; - regs.rsp = vcpu_regs.rsp; - regs.r8 = vcpu_regs.r8; - regs.r9 = vcpu_regs.r9; - regs.r10 = vcpu_regs.r10; - regs.r11 = vcpu_regs.r11; - regs.r12 = vcpu_regs.r12; - regs.r13 = vcpu_regs.r13; - regs.r14 = vcpu_regs.r14; - regs.r15 = vcpu_regs.r15; - - regs.rip = vcpu_regs.rip; - regs.rflags = vcpu_regs.rflags; - - // Read XMM registers from FPU state - // note kvm get_fpu doesn't actually set or read the mxcsr value - // https://elixir.bootlin.com/linux/v6.16/source/arch/x86/kvm/x86.c#L12229 - match vcpu_fd.get_fpu() { - Ok(fpu) => { - // Convert KVM XMM registers ([u8; 16] x 16) to [u128; 16] - regs.xmm = fpu.xmm.map(u128::from_le_bytes); - } - Err(e) => { - log::warn!("Failed to read FPU state for XMM registers: {:?}", e); - } - } + let fpu_data = vcpu_fd + .get_fpu() + .map_err(|e| new_error!("Could not read guest FPU registers: {:?}", e))?; + let mut fpu: CommonFpu = CommonFpu::from(&fpu_data); // Read MXCSR from XSAVE (MXCSR is at byte offset 24 -> u32 index 6) // 11.5.10 Mode-Specific XSAVE/XRSTOR State Management match vcpu_fd.get_xsave() { Ok(xsave) => { - regs.mxcsr = xsave.region[6]; + fpu.mxcsr = xsave.region[6]; } Err(e) => { log::warn!("Failed to read XSAVE for MXCSR: {:?}", e); } } - Ok(()) + Ok((CommonRegisters::from(®s), fpu)) } fn set_single_step(&mut self, vcpu_fd: &Self::Vcpu, enable: bool) -> Result<()> { @@ -236,49 +209,30 @@ impl GuestDebug for KvmDebug { } } - fn write_regs(&self, vcpu_fd: &Self::Vcpu, regs: &X86_64Regs) -> Result<()> { + fn write_regs( + &self, + vcpu_fd: &Self::Vcpu, + regs: &CommonRegisters, + fpu: &CommonFpu, + ) -> Result<()> { log::debug!("Write registers"); - let new_regs = kvm_regs { - rax: regs.rax, - rbx: regs.rbx, - rcx: regs.rcx, - rdx: regs.rdx, - rsi: regs.rsi, - rdi: regs.rdi, - rbp: regs.rbp, - rsp: regs.rsp, - r8: regs.r8, - r9: regs.r9, - r10: regs.r10, - r11: regs.r11, - r12: regs.r12, - r13: regs.r13, - r14: regs.r14, - r15: regs.r15, - - rip: regs.rip, - rflags: regs.rflags, - }; + let new_regs = regs.into(); vcpu_fd .set_regs(&new_regs) .map_err(|e| new_error!("Could not write guest registers: {:?}", e))?; - // load existing values and replace the xmm registers - let mut fpu = match vcpu_fd.get_fpu() { - Ok(fpu) => fpu, - Err(e) => { - return Err(new_error!("Could not write guest registers: {:?}", e)); - } - }; - - // Convert XMM registers from [u128; 16] (our internal representation) - // to [[u8; 16]; 16] (KVM FPU representation) using little-endian byte order. - fpu.xmm = regs.xmm.map(u128::to_le_bytes); + // Only xmm and mxcsr is piped though in the given fpu, so only set those + let mut current_fpu: CommonFpu = (&vcpu_fd.get_fpu()?).into(); + current_fpu.mxcsr = fpu.mxcsr; + current_fpu.xmm = fpu.xmm; vcpu_fd - .set_fpu(&fpu) + .set_fpu(&(¤t_fpu).into()) .map_err(|e| new_error!("Could not write guest registers: {:?}", e))?; + // Read XMM registers from FPU state + // note kvm get_fpu doesn't actually set or read the mxcsr value + // https://elixir.bootlin.com/linux/v6.16/source/arch/x86/kvm/x86.c#L12229 // Update MXCSR using XSAVE region entry 6 (MXCSR) if available. let mut xsave = match vcpu_fd.get_xsave() { Ok(xsave) => xsave, @@ -287,7 +241,7 @@ impl GuestDebug for KvmDebug { } }; - xsave.region[6] = regs.mxcsr; + xsave.region[6] = fpu.mxcsr; unsafe { vcpu_fd .set_xsave(&xsave) diff --git a/src/hyperlight_host/src/hypervisor/gdb/mod.rs b/src/hyperlight_host/src/hypervisor/gdb/mod.rs index e8daf5aa9..d6333e456 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/mod.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/mod.rs @@ -46,6 +46,7 @@ use thiserror::Error; use x86_64_target::HyperlightSandboxTarget; use super::InterruptHandle; +use crate::hypervisor::regs::{CommonFpu, CommonRegisters}; use crate::mem::layout::SandboxMemoryLayout; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; @@ -88,31 +89,6 @@ impl From for TargetError { } } -/// Struct that contains the x86_64 core registers -#[derive(Debug, Default)] -pub(crate) struct X86_64Regs { - pub(crate) rax: u64, - pub(crate) rbx: u64, - pub(crate) rcx: u64, - pub(crate) rdx: u64, - pub(crate) rsi: u64, - pub(crate) rdi: u64, - pub(crate) rbp: u64, - pub(crate) rsp: u64, - pub(crate) r8: u64, - pub(crate) r9: u64, - pub(crate) r10: u64, - pub(crate) r11: u64, - pub(crate) r12: u64, - pub(crate) r13: u64, - pub(crate) r14: u64, - pub(crate) r15: u64, - pub(crate) rip: u64, - pub(crate) rflags: u64, - pub(crate) xmm: [u128; 16], - pub(crate) mxcsr: u32, -} - /// Defines the possible reasons for which a vCPU can be stopped when debugging #[derive(Debug)] pub enum VcpuStopReason { @@ -142,7 +118,7 @@ pub(crate) enum DebugMsg { RemoveSwBreakpoint(u64), Step, WriteAddr(u64, Vec), - WriteRegisters(Box), + WriteRegisters(Box<(CommonRegisters, CommonFpu)>), } /// Enumerates the possible responses that a hypervisor can provide to a debugger @@ -157,7 +133,7 @@ pub(crate) enum DebugResponse { NotAllowed, InterruptHandle(Arc), ReadAddr(Vec), - ReadRegisters(Box), + ReadRegisters(Box<(CommonRegisters, CommonFpu)>), RemoveHwBreakpoint(bool), RemoveSwBreakpoint(bool), Step, @@ -185,13 +161,18 @@ pub(super) trait GuestDebug { fn delete_sw_breakpoint_data(&mut self, addr: &u64) -> Option<[u8; 1]>; /// Read registers - fn read_regs(&self, vcpu_fd: &Self::Vcpu, regs: &mut X86_64Regs) -> crate::Result<()>; + fn read_regs(&self, vcpu_fd: &Self::Vcpu) -> crate::Result<(CommonRegisters, CommonFpu)>; /// Enables or disables stepping and sets the vCPU debug configuration fn set_single_step(&mut self, vcpu_fd: &Self::Vcpu, enable: bool) -> crate::Result<()>; /// Translates the guest address to physical address fn translate_gva(&self, vcpu_fd: &Self::Vcpu, gva: u64) -> crate::Result; /// Write registers - fn write_regs(&self, vcpu_fd: &Self::Vcpu, regs: &X86_64Regs) -> crate::Result<()>; + fn write_regs( + &self, + vcpu_fd: &Self::Vcpu, + regs: &CommonRegisters, + fpu: &CommonFpu, + ) -> crate::Result<()>; /// Adds hardware breakpoint fn add_hw_breakpoint(&mut self, vcpu_fd: &Self::Vcpu, addr: u64) -> crate::Result<()> { @@ -451,7 +432,10 @@ mod tests { let res = gdb_conn.try_recv(); assert!(res.is_err()); - let res = hyp_conn.send(DebugResponse::ReadRegisters(Box::default())); + let res = hyp_conn.send(DebugResponse::ReadRegisters(Box::new(( + Default::default(), + Default::default(), + )))); assert!(res.is_ok()); let res = gdb_conn.recv(); diff --git a/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs b/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs index 540581426..92569a2fd 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/mshv_debug.rs @@ -28,12 +28,12 @@ use std::collections::HashMap; use mshv_bindings::{ DebugRegisters, HV_TRANSLATE_GVA_VALIDATE_READ, HV_TRANSLATE_GVA_VALIDATE_WRITE, - StandardRegisters, }; use mshv_ioctls::VcpuFd; use super::arch::{MAX_NO_OF_HW_BP, SW_BP_SIZE, vcpu_stop_reason}; -use super::{GuestDebug, VcpuStopReason, X86_64Regs}; +use super::{GuestDebug, VcpuStopReason}; +use crate::hypervisor::regs::{CommonFpu, CommonRegisters}; use crate::{HyperlightError, Result, new_error}; #[derive(Debug, Default)] @@ -194,45 +194,20 @@ impl GuestDebug for MshvDebug { self.sw_breakpoints.remove(addr) } - fn read_regs(&self, vcpu_fd: &Self::Vcpu, regs: &mut X86_64Regs) -> Result<()> { + fn read_regs(&self, vcpu_fd: &Self::Vcpu) -> Result<(CommonRegisters, CommonFpu)> { log::debug!("Read registers"); - let vcpu_regs = vcpu_fd + + let regs = vcpu_fd .get_regs() .map_err(|e| new_error!("Could not read guest registers: {:?}", e))?; + let regs = CommonRegisters::from(®s); - regs.rax = vcpu_regs.rax; - regs.rbx = vcpu_regs.rbx; - regs.rcx = vcpu_regs.rcx; - regs.rdx = vcpu_regs.rdx; - regs.rsi = vcpu_regs.rsi; - regs.rdi = vcpu_regs.rdi; - regs.rbp = vcpu_regs.rbp; - regs.rsp = vcpu_regs.rsp; - regs.r8 = vcpu_regs.r8; - regs.r9 = vcpu_regs.r9; - regs.r10 = vcpu_regs.r10; - regs.r11 = vcpu_regs.r11; - regs.r12 = vcpu_regs.r12; - regs.r13 = vcpu_regs.r13; - regs.r14 = vcpu_regs.r14; - regs.r15 = vcpu_regs.r15; - - regs.rip = vcpu_regs.rip; - regs.rflags = vcpu_regs.rflags; - - // Try to read XMM from the FPU state - match vcpu_fd.get_fpu() { - Ok(fpu) => { - // MSHV exposes XMM as [[u8; 16]; 16]. Convert to [u128; 16] - regs.xmm = fpu.xmm.map(u128::from_le_bytes); - regs.mxcsr = fpu.mxcsr; - } - Err(e) => { - log::warn!("Failed to read FPU state for XMM registers (MSHV): {:?}", e); - } - } + let fpu_data = vcpu_fd + .get_fpu() + .map_err(|e| new_error!("Could not read guest FPU registers: {:?}", e))?; + let fpu = CommonFpu::from(&fpu_data); - Ok(()) + Ok((regs, fpu)) } fn set_single_step(&mut self, vcpu_fd: &Self::Vcpu, enable: bool) -> Result<()> { @@ -248,47 +223,25 @@ impl GuestDebug for MshvDebug { Ok(addr) } - fn write_regs(&self, vcpu_fd: &Self::Vcpu, regs: &X86_64Regs) -> Result<()> { + fn write_regs( + &self, + vcpu_fd: &Self::Vcpu, + regs: &CommonRegisters, + fpu: &CommonFpu, + ) -> Result<()> { log::debug!("Write registers"); - let new_regs = StandardRegisters { - rax: regs.rax, - rbx: regs.rbx, - rcx: regs.rcx, - rdx: regs.rdx, - rsi: regs.rsi, - rdi: regs.rdi, - rbp: regs.rbp, - rsp: regs.rsp, - r8: regs.r8, - r9: regs.r9, - r10: regs.r10, - r11: regs.r11, - r12: regs.r12, - r13: regs.r13, - r14: regs.r14, - r15: regs.r15, - - rip: regs.rip, - rflags: regs.rflags, - }; vcpu_fd - .set_regs(&new_regs) + .set_regs(®s.into()) .map_err(|e| new_error!("Could not write guest registers: {:?}", e))?; - // Load existing FPU state, replace XMM and MXCSR, and write it back. - let mut fpu = match vcpu_fd.get_fpu() { - Ok(f) => f, - Err(e) => { - return Err(new_error!("Could not write guest registers: {:?}", e)); - } - }; - - fpu.xmm = regs.xmm.map(u128::to_le_bytes); - fpu.mxcsr = regs.mxcsr; + // Only xmm and mxcsr is piped though in the given fpu, so only set those + let mut current_fpu: CommonFpu = (&vcpu_fd.get_fpu()?).into(); + current_fpu.mxcsr = fpu.mxcsr; + current_fpu.xmm = fpu.xmm; vcpu_fd - .set_fpu(&fpu) + .set_fpu(&(¤t_fpu).into()) .map_err(|e| new_error!("Could not write guest registers: {:?}", e)) } } diff --git a/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs b/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs index 3a67d3017..7ba38fc48 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs @@ -31,8 +31,9 @@ use gdbstub::target::ext::section_offsets::{Offsets, SectionOffsets}; use gdbstub::target::{Target, TargetError, TargetResult}; use gdbstub_arch::x86::X86_64_SSE as GdbTargetArch; -use super::{DebugCommChannel, DebugMsg, DebugResponse, GdbTargetError, X86_64Regs}; +use super::{DebugCommChannel, DebugMsg, DebugResponse, GdbTargetError}; use crate::hypervisor::InterruptHandle; +use crate::hypervisor::regs::{CommonFpu, CommonRegisters}; /// Gdbstub target used by the gdbstub crate to provide GDB protocol implementation pub(crate) struct HyperlightSandboxTarget { @@ -208,7 +209,8 @@ impl SingleThreadBase for HyperlightSandboxTarget { log::debug!("Read regs"); match self.send_command(DebugMsg::ReadRegisters)? { - DebugResponse::ReadRegisters(read_regs) => { + DebugResponse::ReadRegisters(boxed_regs) => { + let (read_regs, read_fpu) = boxed_regs.as_ref(); regs.regs[0] = read_regs.rax; regs.regs[1] = read_regs.rbp; regs.regs[2] = read_regs.rcx; @@ -227,8 +229,9 @@ impl SingleThreadBase for HyperlightSandboxTarget { regs.regs[15] = read_regs.r15; regs.rip = read_regs.rip; regs.eflags = read_regs.rflags as u32; - regs.xmm = read_regs.xmm; - regs.mxcsr = read_regs.mxcsr; + + regs.xmm = read_fpu.xmm.map(u128::from_le_bytes); + regs.mxcsr = read_fpu.mxcsr; Ok(()) } @@ -250,7 +253,7 @@ impl SingleThreadBase for HyperlightSandboxTarget { ) -> TargetResult<(), Self> { log::debug!("Write regs"); - let regs = X86_64Regs { + let common_regs = CommonRegisters { rax: regs.regs[0], rbx: regs.regs[1], rcx: regs.regs[2], @@ -269,11 +272,23 @@ impl SingleThreadBase for HyperlightSandboxTarget { r15: regs.regs[15], rip: regs.rip, rflags: u64::from(regs.eflags), - xmm: regs.xmm, + }; + + let mut xmm = [[0u8; 16]; 16]; + for (i, ®) in regs.xmm.iter().enumerate() { + xmm[i] = reg.to_le_bytes(); + } + + let common_fpu = CommonFpu { + xmm, mxcsr: regs.mxcsr, + ..Default::default() }; - match self.send_command(DebugMsg::WriteRegisters(Box::new(regs)))? { + match self.send_command(DebugMsg::WriteRegisters(Box::new(( + common_regs, + common_fpu, + ))))? { DebugResponse::WriteRegisters => Ok(()), DebugResponse::NotAllowed => { log::error!("Action not allowed at this time, crash might have occurred"); diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 5a009823e..80ee0b16b 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -32,7 +32,7 @@ use log::{LevelFilter, error}; #[cfg(mshv2)] use mshv_bindings::hv_message; use mshv_bindings::{ - FloatingPointUnit, SegmentRegister, SpecialRegisters, StandardRegisters, hv_message_type, + FloatingPointUnit, SpecialRegisters, StandardRegisters, hv_message_type, hv_message_type_HVMSG_GPA_INTERCEPT, hv_message_type_HVMSG_UNMAPPED_GPA, hv_message_type_HVMSG_X64_HALT, hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT, hv_register_assoc, hv_register_name_HV_X64_REGISTER_RIP, hv_register_value, mshv_user_mem_region, @@ -48,32 +48,20 @@ use mshv_bindings::{ hv_partition_property_code_HV_PARTITION_PROPERTY_SYNTHETIC_PROC_FEATURES, hv_partition_synthetic_processor_features, }; -#[cfg(feature = "trace_guest")] -use mshv_bindings::{ - hv_register_name, hv_register_name_HV_X64_REGISTER_RAX, hv_register_name_HV_X64_REGISTER_RBP, - hv_register_name_HV_X64_REGISTER_RCX, hv_register_name_HV_X64_REGISTER_RSP, -}; use mshv_ioctls::{Mshv, VcpuFd, VmFd}; use tracing::{Span, instrument}; #[cfg(crashdump)] use {super::crashdump, std::path::Path}; -#[cfg(feature = "trace_guest")] -use super::TraceRegister; -use super::fpu::{FP_CONTROL_WORD_DEFAULT, FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT}; #[cfg(gdb)] use super::gdb::{ DebugCommChannel, DebugMsg, DebugResponse, GuestDebug, MshvDebug, VcpuStopReason, }; -#[cfg(feature = "init-paging")] -use super::{ - CR0_AM, CR0_ET, CR0_MP, CR0_NE, CR0_PE, CR0_PG, CR0_WP, CR4_OSFXSR, CR4_OSXMMEXCPT, CR4_PAE, - EFER_LMA, EFER_LME, EFER_NX, EFER_SCE, -}; use super::{HyperlightExit, Hypervisor, InterruptHandle, LinuxInterruptHandle, VirtualCPU}; #[cfg(gdb)] use crate::HyperlightError; use crate::hypervisor::get_memory_access_violation; +use crate::hypervisor::regs::CommonFpu; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::ptr::{GuestPtr, RawPtr}; @@ -93,7 +81,7 @@ mod debug { use super::mshv_bindings::hv_x64_exception_intercept_message; use super::{HypervLinuxDriver, *}; - use crate::hypervisor::gdb::{DebugMsg, DebugResponse, VcpuStopReason, X86_64Regs}; + use crate::hypervisor::gdb::{DebugMsg, DebugResponse, VcpuStopReason}; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; use crate::{Result, new_error}; @@ -192,18 +180,14 @@ mod debug { Ok(DebugResponse::ReadAddr(data)) } - DebugMsg::ReadRegisters => { - let mut regs = X86_64Regs::default(); - - debug - .read_regs(&self.vcpu_fd, &mut regs) - .map_err(|e| { - log::error!("Failed to read registers: {:?}", e); + DebugMsg::ReadRegisters => debug + .read_regs(&self.vcpu_fd) + .map_err(|e| { + log::error!("Failed to read registers: {:?}", e); - e - }) - .map(|_| DebugResponse::ReadRegisters(Box::new(regs))) - } + e + }) + .map(|(regs, fpu)| DebugResponse::ReadRegisters(Box::new((regs, fpu)))), DebugMsg::RemoveHwBreakpoint(addr) => Ok(DebugResponse::RemoveHwBreakpoint( debug .remove_hw_breakpoint(&self.vcpu_fd, addr) @@ -244,14 +228,17 @@ mod debug { Ok(DebugResponse::WriteAddr) } - DebugMsg::WriteRegisters(regs) => debug - .write_regs(&self.vcpu_fd, ®s) - .map_err(|e| { - log::error!("Failed to write registers: {:?}", e); + DebugMsg::WriteRegisters(boxed_regs) => { + let (regs, fpu) = boxed_regs.as_ref(); + debug + .write_regs(&self.vcpu_fd, regs, fpu) + .map_err(|e| { + log::error!("Failed to write registers: {:?}", e); - e - }) - .map(|_| DebugResponse::WriteRegisters), + e + }) + .map(|_| DebugResponse::WriteRegisters) + } } } else { Err(new_error!("Debugging is not enabled")) @@ -370,7 +357,7 @@ impl HypervLinuxDriver { vm_fd }; - let mut vcpu_fd = vm_fd.create_vcpu(0)?; + let vcpu_fd = vm_fd.create_vcpu(0)?; #[cfg(gdb)] let (debug, gdb_conn) = if let Some(gdb_conn) = gdb_conn { @@ -414,8 +401,6 @@ impl HypervLinuxDriver { vm_fd.map_user_memory(mshv_region) })?; - Self::setup_initial_sregs(&mut vcpu_fd, pml4_ptr.absolute()?)?; - let interrupt_handle = Arc::new(LinuxInterruptHandle { running: AtomicU64::new(0), cancel_requested: AtomicBool::new(false), @@ -440,7 +425,6 @@ impl HypervLinuxDriver { dropped: AtomicBool::new(false), }); - #[allow(unused_mut)] let mut hv = Self { _mshv: mshv, page_size: 0, @@ -463,6 +447,8 @@ impl HypervLinuxDriver { trace_info, }; + hv.setup_initial_sregs(pml4_ptr.absolute()?)?; + // Send the interrupt handle to the GDB thread if debugging is enabled // This is used to allow the GDB thread to stop the vCPU #[cfg(gdb)] @@ -472,65 +458,6 @@ impl HypervLinuxDriver { Ok(hv) } - - #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - fn setup_initial_sregs(vcpu: &mut VcpuFd, _pml4_addr: u64) -> Result<()> { - #[cfg(feature = "init-paging")] - let sregs = SpecialRegisters { - cr0: CR0_PE | CR0_MP | CR0_ET | CR0_NE | CR0_AM | CR0_PG | CR0_WP, - cr4: CR4_PAE | CR4_OSFXSR | CR4_OSXMMEXCPT, - cr3: _pml4_addr, - efer: EFER_LME | EFER_LMA | EFER_SCE | EFER_NX, - cs: SegmentRegister { - type_: 11, - present: 1, - s: 1, - l: 1, - ..Default::default() - }, - tr: SegmentRegister { - limit: 65535, - type_: 11, - present: 1, - ..Default::default() - }, - ..Default::default() - }; - - #[cfg(not(feature = "init-paging"))] - let sregs = SpecialRegisters { - cs: SegmentRegister { - base: 0, - selector: 0, - limit: 0xFFFF, - type_: 11, - present: 1, - s: 1, - ..Default::default() - }, - ds: SegmentRegister { - base: 0, - selector: 0, - limit: 0xFFFF, - type_: 3, - present: 1, - s: 1, - ..Default::default() - }, - tr: SegmentRegister { - base: 0, - selector: 0, - limit: 0xFFFF, - type_: 11, - present: 1, - s: 0, - ..Default::default() - }, - ..Default::default() - }; - vcpu.set_sregs(&sregs)?; - Ok(()) - } } impl Debug for HypervLinuxDriver { @@ -563,19 +490,6 @@ impl Debug for HypervLinuxDriver { } } -#[cfg(feature = "trace_guest")] -impl From for hv_register_name { - fn from(r: TraceRegister) -> Self { - match r { - TraceRegister::RAX => hv_register_name_HV_X64_REGISTER_RAX, - TraceRegister::RCX => hv_register_name_HV_X64_REGISTER_RCX, - TraceRegister::RIP => hv_register_name_HV_X64_REGISTER_RIP, - TraceRegister::RSP => hv_register_name_HV_X64_REGISTER_RSP, - TraceRegister::RBP => hv_register_name_HV_X64_REGISTER_RBP, - } - } -} - impl Hypervisor for HypervLinuxDriver { #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] fn initialise( @@ -670,13 +584,7 @@ impl Hypervisor for HypervLinuxDriver { self.vcpu_fd.set_regs(®s)?; // reset fpu state - let fpu = FloatingPointUnit { - fcw: FP_CONTROL_WORD_DEFAULT, - ftwx: FP_TAG_WORD_DEFAULT, - mxcsr: MXCSR_DEFAULT, - ..Default::default() // zero out the rest - }; - self.vcpu_fd.set_fpu(&fpu)?; + self.set_fpu(&CommonFpu::default())?; // run VirtualCPU::run( @@ -950,6 +858,39 @@ impl Hypervisor for HypervLinuxDriver { Ok(result) } + fn regs(&self) -> Result { + let mshv_regs = self.vcpu_fd.get_regs()?; + Ok((&mshv_regs).into()) + } + + fn set_regs(&mut self, regs: &super::regs::CommonRegisters) -> Result<()> { + let mshv_regs: StandardRegisters = regs.into(); + self.vcpu_fd.set_regs(&mshv_regs)?; + Ok(()) + } + + fn fpu(&self) -> Result { + let mshv_fpu = self.vcpu_fd.get_fpu()?; + Ok((&mshv_fpu).into()) + } + + fn set_fpu(&mut self, fpu: &super::regs::CommonFpu) -> Result<()> { + let mshv_fpu: FloatingPointUnit = fpu.into(); + self.vcpu_fd.set_fpu(&mshv_fpu)?; + Ok(()) + } + + fn sregs(&self) -> Result { + let mshv_sregs = self.vcpu_fd.get_sregs()?; + Ok((&mshv_sregs).into()) + } + + fn set_sregs(&mut self, sregs: &super::regs::CommonSpecialRegisters) -> Result<()> { + let mshv_sregs: SpecialRegisters = sregs.into(); + self.vcpu_fd.set_sregs(&mshv_sregs)?; + Ok(()) + } + #[instrument(skip_all, parent = Span::current(), level = "Trace")] fn as_mut_hypervisor(&mut self) -> &mut dyn Hypervisor { self as &mut dyn Hypervisor @@ -1159,17 +1100,6 @@ impl Hypervisor for HypervLinuxDriver { } } - #[cfg(feature = "trace_guest")] - fn read_trace_reg(&self, reg: TraceRegister) -> Result { - let mut assoc = [hv_register_assoc { - name: reg.into(), - ..Default::default() - }]; - self.vcpu_fd.get_reg(&mut assoc)?; - // safety: all registers that we currently support are 64-bit - unsafe { Ok(assoc[0].value.reg64) } - } - #[cfg(feature = "trace_guest")] fn trace_info_as_ref(&self) -> &TraceInfo { &self.trace_info diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index e9aa45703..490e1f72e 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -23,13 +23,8 @@ use std::sync::{Arc, Mutex}; use log::LevelFilter; use tracing::{Span, instrument}; use windows::Win32::System::Hypervisor::{ - WHV_MEMORY_ACCESS_TYPE, WHV_PARTITION_HANDLE, WHV_REGISTER_VALUE, WHV_RUN_VP_EXIT_CONTEXT, - WHV_RUN_VP_EXIT_REASON, WHV_X64_SEGMENT_REGISTER, WHV_X64_SEGMENT_REGISTER_0, - WHvCancelRunVirtualProcessor, WHvX64RegisterCs, -}; -#[cfg(feature = "init-paging")] -use windows::Win32::System::Hypervisor::{ - WHvX64RegisterCr0, WHvX64RegisterCr3, WHvX64RegisterCr4, WHvX64RegisterEfer, + WHV_MEMORY_ACCESS_TYPE, WHV_PARTITION_HANDLE, WHV_RUN_VP_EXIT_CONTEXT, WHV_RUN_VP_EXIT_REASON, + WHvCancelRunVirtualProcessor, }; #[cfg(crashdump)] use {super::crashdump, std::path::Path}; @@ -41,22 +36,14 @@ use { crate::HyperlightError, }; -#[cfg(feature = "trace_guest")] -use super::TraceRegister; -use super::fpu::{FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT}; +use super::regs::CommonSpecialRegisters; use super::surrogate_process::SurrogateProcess; use super::surrogate_process_manager::*; use super::windows_hypervisor_platform::{VMPartition, VMProcessor}; -use super::wrappers::{HandleWrapper, WHvFPURegisters}; -#[cfg(feature = "init-paging")] -use super::{ - CR0_AM, CR0_ET, CR0_MP, CR0_NE, CR0_PE, CR0_PG, CR0_WP, CR4_OSFXSR, CR4_OSXMMEXCPT, CR4_PAE, - EFER_LMA, EFER_LME, EFER_NX, EFER_SCE, -}; +use super::wrappers::HandleWrapper; use super::{HyperlightExit, Hypervisor, InterruptHandle, VirtualCPU}; -use crate::hypervisor::fpu::FP_CONTROL_WORD_DEFAULT; use crate::hypervisor::get_memory_access_violation; -use crate::hypervisor::wrappers::WHvGeneralRegisters; +use crate::hypervisor::regs::{CommonFpu, CommonRegisters}; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::ptr::{GuestPtr, RawPtr}; @@ -77,7 +64,7 @@ mod debug { use super::{HypervWindowsDriver, *}; use crate::Result; - use crate::hypervisor::gdb::{DebugMsg, DebugResponse, VcpuStopReason, X86_64Regs}; + use crate::hypervisor::gdb::{DebugMsg, DebugResponse, VcpuStopReason}; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; @@ -175,18 +162,14 @@ mod debug { Ok(DebugResponse::ReadAddr(data)) } - DebugMsg::ReadRegisters => { - let mut regs = X86_64Regs::default(); - - debug - .read_regs(&self.processor, &mut regs) - .map_err(|e| { - log::error!("Failed to read registers: {:?}", e); + DebugMsg::ReadRegisters => debug + .read_regs(&self.processor) + .map_err(|e| { + log::error!("Failed to read registers: {:?}", e); - e - }) - .map(|_| DebugResponse::ReadRegisters(Box::new(regs))) - } + e + }) + .map(|(regs, fpu)| DebugResponse::ReadRegisters(Box::new((regs, fpu)))), DebugMsg::RemoveHwBreakpoint(addr) => Ok(DebugResponse::RemoveHwBreakpoint( debug .remove_hw_breakpoint(&self.processor, addr) @@ -227,14 +210,17 @@ mod debug { Ok(DebugResponse::WriteAddr) } - DebugMsg::WriteRegisters(regs) => debug - .write_regs(&self.processor, ®s) - .map_err(|e| { - log::error!("Failed to write registers: {:?}", e); + DebugMsg::WriteRegisters(boxed_regs) => { + let (regs, fpu) = boxed_regs.as_ref(); + debug + .write_regs(&self.processor, regs, fpu) + .map_err(|e| { + log::error!("Failed to write registers: {:?}", e); - e - }) - .map(|_| DebugResponse::WriteRegisters), + e + }) + .map(|_| DebugResponse::WriteRegisters) + } } } else { Err(new_error!("Debugging is not enabled")) @@ -328,8 +314,7 @@ impl HypervWindowsDriver { partition.map_gpa_range(&mem_regions, &surrogate_process)?; - let mut proc = VMProcessor::new(partition)?; - Self::setup_initial_sregs(&mut proc, pml4_address)?; + let proc = VMProcessor::new(partition)?; let partition_handle = proc.get_partition_hdl(); #[cfg(gdb)] @@ -351,17 +336,16 @@ impl HypervWindowsDriver { dropped: AtomicBool::new(false), }); - #[allow(unused_mut)] let mut hv = Self { processor: proc, _surrogate_process: surrogate_process, entrypoint, orig_rsp: GuestPtr::try_from(RawPtr::from(rsp))?, - sandbox_regions: mem_regions, - mmap_regions: Vec::new(), interrupt_handle: interrupt_handle.clone(), mem_mgr: None, host_funcs: None, + sandbox_regions: mem_regions, + mmap_regions: Vec::new(), #[cfg(gdb)] debug, #[cfg(gdb)] @@ -372,6 +356,8 @@ impl HypervWindowsDriver { trace_info, }; + hv.setup_initial_sregs(pml4_address)?; + // Send the interrupt handle to the GDB thread if debugging is enabled // This is used to allow the GDB thread to stop the vCPU #[cfg(gdb)] @@ -382,62 +368,6 @@ impl HypervWindowsDriver { Ok(hv) } - fn setup_initial_sregs(proc: &mut VMProcessor, _pml4_addr: u64) -> Result<()> { - #[cfg(feature = "init-paging")] - proc.set_registers(&[ - (WHvX64RegisterCr3, WHV_REGISTER_VALUE { Reg64: _pml4_addr }), - ( - WHvX64RegisterCr4, - WHV_REGISTER_VALUE { - Reg64: CR4_PAE | CR4_OSFXSR | CR4_OSXMMEXCPT, - }, - ), - ( - WHvX64RegisterCr0, - WHV_REGISTER_VALUE { - Reg64: CR0_PE | CR0_MP | CR0_ET | CR0_NE | CR0_AM | CR0_PG | CR0_WP, - }, - ), - ( - WHvX64RegisterEfer, - WHV_REGISTER_VALUE { - Reg64: EFER_LME | EFER_LMA | EFER_SCE | EFER_NX, - }, - ), - ( - WHvX64RegisterCs, - WHV_REGISTER_VALUE { - Segment: WHV_X64_SEGMENT_REGISTER { - Anonymous: WHV_X64_SEGMENT_REGISTER_0 { - Attributes: 0b1011 | (1 << 4) | (1 << 7) | (1 << 13), // Type (11: Execute/Read, accessed) | L (64-bit mode) | P (present) | S (code segment) - }, - ..Default::default() // zero out the rest - }, - }, - ), - ])?; - - #[cfg(not(feature = "init-paging"))] - { - proc.set_registers(&[( - WHvX64RegisterCs, - WHV_REGISTER_VALUE { - Segment: WHV_X64_SEGMENT_REGISTER { - Base: 0, - Selector: 0, - Limit: 0xFFFF, - Anonymous: WHV_X64_SEGMENT_REGISTER_0 { - Attributes: 0b1011 | (1 << 4) | (1 << 7), // Type (11: Execute/Read, accessed) | S (code segment) | P (present) - }, - ..Default::default() - }, - }, - )])?; - } - - Ok(()) - } - #[inline] #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] fn get_exit_details(&self, exit_reason: WHV_RUN_VP_EXIT_REASON) -> Result { @@ -445,7 +375,7 @@ impl HypervWindowsDriver { error.push_str(&format!( "Did not receive a halt from Hypervisor as expected - Received {exit_reason:?}!\n" )); - error.push_str(&format!("Registers: \n{:#?}", self.processor.get_regs()?)); + error.push_str(&format!("Registers: \n{:#?}", self.processor.regs()?)); Ok(error) } } @@ -465,127 +395,14 @@ impl Debug for HypervWindowsDriver { } // Get the registers - - let regs = self.processor.get_regs(); - - if let Ok(regs) = regs { - { - fs.field("Registers", ®s); - } + if let Ok(regs) = self.processor.regs() { + fs.field("Registers", ®s); } // Get the special registers - - let special_regs = self.processor.get_sregs(); - if let Ok(special_regs) = special_regs { - fs.field("CR0", unsafe { &special_regs.cr0.Reg64 }); - fs.field("CR2", unsafe { &special_regs.cr2.Reg64 }); - fs.field("CR3", unsafe { &special_regs.cr3.Reg64 }); - fs.field("CR4", unsafe { &special_regs.cr4.Reg64 }); - fs.field("CR8", unsafe { &special_regs.cr8.Reg64 }); - fs.field("EFER", unsafe { &special_regs.efer.Reg64 }); - fs.field("APIC_BASE", unsafe { &special_regs.apic_base.Reg64 }); - - // Segment registers - fs.field( - "CS", - &format_args!( - "{{ Base: {:?}, Limit: {:?}, Selector: {:?}, Attributes: {:?} }}", - unsafe { &special_regs.cs.Segment.Base }, - unsafe { &special_regs.cs.Segment.Limit }, - unsafe { &special_regs.cs.Segment.Selector }, - unsafe { &special_regs.cs.Segment.Anonymous.Attributes } - ), - ); - fs.field( - "DS", - &format_args!( - "{{ Base: {:?}, Limit: {:?}, Selector: {:?}, Attributes: {:?} }}", - unsafe { &special_regs.ds.Segment.Base }, - unsafe { &special_regs.ds.Segment.Limit }, - unsafe { &special_regs.ds.Segment.Selector }, - unsafe { &special_regs.ds.Segment.Anonymous.Attributes } - ), - ); - fs.field( - "ES", - &format_args!( - "{{ Base: {:?}, Limit: {:?}, Selector: {:?}, Attributes: {:?} }}", - unsafe { &special_regs.es.Segment.Base }, - unsafe { &special_regs.es.Segment.Limit }, - unsafe { &special_regs.es.Segment.Selector }, - unsafe { &special_regs.es.Segment.Anonymous.Attributes } - ), - ); - fs.field( - "FS", - &format_args!( - "{{ Base: {:?}, Limit: {:?}, Selector: {:?}, Attributes: {:?} }}", - unsafe { &special_regs.fs.Segment.Base }, - unsafe { &special_regs.fs.Segment.Limit }, - unsafe { &special_regs.fs.Segment.Selector }, - unsafe { &special_regs.fs.Segment.Anonymous.Attributes } - ), - ); - fs.field( - "GS", - &format_args!( - "{{ Base: {:?}, Limit: {:?}, Selector: {:?}, Attributes: {:?} }}", - unsafe { &special_regs.gs.Segment.Base }, - unsafe { &special_regs.gs.Segment.Limit }, - unsafe { &special_regs.gs.Segment.Selector }, - unsafe { &special_regs.gs.Segment.Anonymous.Attributes } - ), - ); - fs.field( - "SS", - &format_args!( - "{{ Base: {:?}, Limit: {:?}, Selector: {:?}, Attributes: {:?} }}", - unsafe { &special_regs.ss.Segment.Base }, - unsafe { &special_regs.ss.Segment.Limit }, - unsafe { &special_regs.ss.Segment.Selector }, - unsafe { &special_regs.ss.Segment.Anonymous.Attributes } - ), - ); - fs.field( - "TR", - &format_args!( - "{{ Base: {:?}, Limit: {:?}, Selector: {:?}, Attributes: {:?} }}", - unsafe { &special_regs.tr.Segment.Base }, - unsafe { &special_regs.tr.Segment.Limit }, - unsafe { &special_regs.tr.Segment.Selector }, - unsafe { &special_regs.tr.Segment.Anonymous.Attributes } - ), - ); - fs.field( - "LDTR", - &format_args!( - "{{ Base: {:?}, Limit: {:?}, Selector: {:?}, Attributes: {:?} }}", - unsafe { &special_regs.ldtr.Segment.Base }, - unsafe { &special_regs.ldtr.Segment.Limit }, - unsafe { &special_regs.ldtr.Segment.Selector }, - unsafe { &special_regs.ldtr.Segment.Anonymous.Attributes } - ), - ); - fs.field( - "GDTR", - &format_args!( - "{{ Base: {:?}, Limit: {:?}, Pad: {:?} }}", - unsafe { &special_regs.gdtr.Table.Base }, - unsafe { &special_regs.gdtr.Table.Limit }, - unsafe { &special_regs.gdtr.Table.Pad } - ), - ); - fs.field( - "IDTR", - &format_args!( - "{{ Base: {:?}, Limit: {:?}, Pad: {:?} }}", - unsafe { &special_regs.idtr.Table.Base }, - unsafe { &special_regs.idtr.Table.Limit }, - unsafe { &special_regs.idtr.Table.Pad } - ), - ); - }; + if let Ok(special_regs) = self.processor.sregs() { + fs.field("SpecialRegisters", &special_regs); + } fs.finish() } @@ -611,7 +428,7 @@ impl Hypervisor for HypervWindowsDriver { None => self.get_max_log_level().into(), }; - let regs = WHvGeneralRegisters { + let regs = CommonRegisters { rip: self.entrypoint, rsp: self.orig_rsp.absolute()?, @@ -624,7 +441,7 @@ impl Hypervisor for HypervWindowsDriver { ..Default::default() }; - self.processor.set_general_purpose_registers(®s)?; + self.set_regs(®s)?; VirtualCPU::run( self.as_mut_hypervisor(), @@ -654,21 +471,16 @@ impl Hypervisor for HypervWindowsDriver { #[cfg(gdb)] dbg_mem_access_hdl: Arc>>, ) -> Result<()> { // Reset general purpose registers, then set RIP and RSP - let regs = WHvGeneralRegisters { + let regs = CommonRegisters { rip: dispatch_func_addr.into(), rsp: self.orig_rsp.absolute()?, rflags: 1 << 1, // eflags bit index 1 is reserved and always needs to be 1 ..Default::default() }; - self.processor.set_general_purpose_registers(®s)?; + self.processor.set_regs(®s)?; // reset fpu state - self.processor.set_fpu(&WHvFPURegisters { - fp_control_word: FP_CONTROL_WORD_DEFAULT, - fp_tag_word: FP_TAG_WORD_DEFAULT, - mxcsr: MXCSR_DEFAULT, - ..Default::default() // zero out the rest - })?; + self.processor.set_fpu(&CommonFpu::default())?; VirtualCPU::run( self.as_mut_hypervisor(), @@ -728,9 +540,9 @@ impl Hypervisor for HypervWindowsDriver { handle_outb(mem_mgr, host_funcs, port, val)?; } - let mut regs = self.processor.get_regs()?; + let mut regs = self.regs()?; regs.rip = rip + instruction_length; - self.processor.set_general_purpose_registers(®s) + self.set_regs(®s) } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] @@ -884,6 +696,35 @@ impl Hypervisor for HypervWindowsDriver { Ok(result) } + /// Get regs + #[allow(dead_code)] + fn regs(&self) -> Result { + self.processor.regs() + } + /// Set regs + fn set_regs(&mut self, regs: &CommonRegisters) -> Result<()> { + self.processor.set_regs(regs) + } + /// Get fpu regs + #[allow(dead_code)] + fn fpu(&self) -> Result { + self.processor.fpu() + } + /// Set fpu regs + fn set_fpu(&mut self, fpu: &CommonFpu) -> Result<()> { + self.processor.set_fpu(fpu) + } + /// Get special regs + #[allow(dead_code)] + fn sregs(&self) -> Result { + self.processor.sregs() + } + /// Set special regs + #[allow(dead_code)] + fn set_sregs(&mut self, sregs: &CommonSpecialRegisters) -> Result<()> { + self.processor.set_sregs(sregs) + } + fn interrupt_handle(&self) -> Arc { self.interrupt_handle.clone() } @@ -898,8 +739,8 @@ impl Hypervisor for HypervWindowsDriver { if self.rt_cfg.guest_core_dump { let mut regs = [0; 27]; - let vcpu_regs = self.processor.get_regs()?; - let sregs = self.processor.get_sregs()?; + let vcpu_regs = self.processor.regs()?; + let sregs = self.processor.sregs()?; let xsave = self.processor.get_xsave()?; // Set the registers in the order expected by the crashdump context @@ -920,16 +761,16 @@ impl Hypervisor for HypervWindowsDriver { regs[14] = vcpu_regs.rdi; // rdi regs[15] = 0; // orig rax regs[16] = vcpu_regs.rip; // rip - regs[17] = unsafe { sregs.cs.Segment.Selector } as u64; // cs + regs[17] = sregs.cs.selector as u64; // cs regs[18] = vcpu_regs.rflags; // eflags regs[19] = vcpu_regs.rsp; // rsp - regs[20] = unsafe { sregs.ss.Segment.Selector } as u64; // ss - regs[21] = unsafe { sregs.fs.Segment.Base }; // fs_base - regs[22] = unsafe { sregs.gs.Segment.Base }; // gs_base - regs[23] = unsafe { sregs.ds.Segment.Selector } as u64; // ds - regs[24] = unsafe { sregs.es.Segment.Selector } as u64; // es - regs[25] = unsafe { sregs.fs.Segment.Selector } as u64; // fs - regs[26] = unsafe { sregs.gs.Segment.Selector } as u64; // gs + regs[20] = sregs.ss.selector as u64; // ss + regs[21] = sregs.fs.base; // fs_base + regs[22] = sregs.gs.base; // gs_base + regs[23] = sregs.ds.selector as u64; // ds + regs[24] = sregs.es.selector as u64; // es + regs[25] = sregs.fs.selector as u64; // fs + regs[26] = sregs.gs.selector as u64; // gs // Get the filename from the config let filename = self.rt_cfg.binary_path.clone().and_then(|path| { @@ -1092,18 +933,6 @@ impl Hypervisor for HypervWindowsDriver { } } - #[cfg(feature = "trace_guest")] - fn read_trace_reg(&self, reg: TraceRegister) -> Result { - let regs = self.processor.get_regs()?; - match reg { - TraceRegister::RAX => Ok(regs.rax), - TraceRegister::RCX => Ok(regs.rcx), - TraceRegister::RIP => Ok(regs.rip), - TraceRegister::RSP => Ok(regs.rsp), - TraceRegister::RBP => Ok(regs.rbp), - } - } - #[cfg(feature = "trace_guest")] fn trace_info_as_ref(&self) -> &TraceInfo { &self.trace_info diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index 36a7066b6..a42538b33 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -14,12 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -use std::convert::TryFrom; use std::fmt::Debug; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::{Arc, Mutex}; -use kvm_bindings::{kvm_fpu, kvm_regs, kvm_userspace_memory_region}; +use kvm_bindings::{kvm_fpu, kvm_regs, kvm_sregs, kvm_userspace_memory_region}; use kvm_ioctls::Cap::UserMemory; use kvm_ioctls::{Kvm, VcpuExit, VcpuFd, VmFd}; use log::LevelFilter; @@ -27,20 +26,13 @@ use tracing::{Span, instrument}; #[cfg(crashdump)] use {super::crashdump, std::path::Path}; -#[cfg(feature = "trace_guest")] -use super::TraceRegister; -use super::fpu::{FP_CONTROL_WORD_DEFAULT, FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT}; #[cfg(gdb)] use super::gdb::{DebugCommChannel, DebugMsg, DebugResponse, GuestDebug, KvmDebug, VcpuStopReason}; -#[cfg(feature = "init-paging")] -use super::{ - CR0_AM, CR0_ET, CR0_MP, CR0_NE, CR0_PE, CR0_PG, CR0_WP, CR4_OSFXSR, CR4_OSXMMEXCPT, CR4_PAE, - EFER_LMA, EFER_LME, EFER_NX, EFER_SCE, -}; use super::{HyperlightExit, Hypervisor, InterruptHandle, LinuxInterruptHandle, VirtualCPU}; #[cfg(gdb)] use crate::HyperlightError; use crate::hypervisor::get_memory_access_violation; +use crate::hypervisor::regs::{CommonFpu, CommonRegisters}; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::ptr::{GuestPtr, RawPtr}; @@ -83,9 +75,7 @@ mod debug { use kvm_bindings::kvm_debug_exit_arch; use super::KVMDriver; - use crate::hypervisor::gdb::{ - DebugMsg, DebugResponse, GuestDebug, KvmDebug, VcpuStopReason, X86_64Regs, - }; + use crate::hypervisor::gdb::{DebugMsg, DebugResponse, GuestDebug, KvmDebug, VcpuStopReason}; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; use crate::{Result, new_error}; @@ -184,18 +174,14 @@ mod debug { Ok(DebugResponse::ReadAddr(data)) } - DebugMsg::ReadRegisters => { - let mut regs = X86_64Regs::default(); - - debug - .read_regs(&self.vcpu_fd, &mut regs) - .map_err(|e| { - log::error!("Failed to read registers: {:?}", e); + DebugMsg::ReadRegisters => debug + .read_regs(&self.vcpu_fd) + .map_err(|e| { + log::error!("Failed to read registers: {:?}", e); - e - }) - .map(|_| DebugResponse::ReadRegisters(Box::new(regs))) - } + e + }) + .map(|(regs, fpu)| DebugResponse::ReadRegisters(Box::new((regs, fpu)))), DebugMsg::RemoveHwBreakpoint(addr) => Ok(DebugResponse::RemoveHwBreakpoint( debug .remove_hw_breakpoint(&self.vcpu_fd, addr) @@ -236,14 +222,17 @@ mod debug { Ok(DebugResponse::WriteAddr) } - DebugMsg::WriteRegisters(regs) => debug - .write_regs(&self.vcpu_fd, ®s) - .map_err(|e| { - log::error!("Failed to write registers: {:?}", e); + DebugMsg::WriteRegisters(boxed_regs) => { + let (regs, fpu) = boxed_regs.as_ref(); + debug + .write_regs(&self.vcpu_fd, regs, fpu) + .map_err(|e| { + log::error!("Failed to write registers: {:?}", e); - e - }) - .map(|_| DebugResponse::WriteRegisters), + e + }) + .map(|_| DebugResponse::WriteRegisters) + } } } else { Err(new_error!("Debugging is not enabled")) @@ -337,8 +326,7 @@ impl KVMDriver { unsafe { vm_fd.set_user_memory_region(kvm_region) } })?; - let mut vcpu_fd = vm_fd.create_vcpu(0)?; - Self::setup_initial_sregs(&mut vcpu_fd, pml4_addr)?; + let vcpu_fd = vm_fd.create_vcpu(0)?; #[cfg(gdb)] let (debug, gdb_conn) = if let Some(gdb_conn) = gdb_conn { @@ -377,8 +365,7 @@ impl KVMDriver { sig_rt_min_offset: config.get_interrupt_vcpu_sigrtmin_offset(), }); - #[allow(unused_mut)] - let mut hv = Self { + let mut kvm = Self { _kvm: kvm, vm_fd, page_size: 0, @@ -402,34 +389,16 @@ impl KVMDriver { trace_info, }; + kvm.setup_initial_sregs(pml4_addr)?; + // Send the interrupt handle to the GDB thread if debugging is enabled // This is used to allow the GDB thread to stop the vCPU #[cfg(gdb)] - if hv.debug.is_some() { - hv.send_dbg_msg(DebugResponse::InterruptHandle(interrupt_handle))?; + if kvm.debug.is_some() { + kvm.send_dbg_msg(DebugResponse::InterruptHandle(interrupt_handle))?; } - Ok(hv) - } - - #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - fn setup_initial_sregs(vcpu_fd: &mut VcpuFd, _pml4_addr: u64) -> Result<()> { - // setup paging and IA-32e (64-bit) mode - let mut sregs = vcpu_fd.get_sregs()?; - cfg_if::cfg_if! { - if #[cfg(feature = "init-paging")] { - sregs.cr3 = _pml4_addr; - sregs.cr4 = CR4_PAE | CR4_OSFXSR | CR4_OSXMMEXCPT; - sregs.cr0 = CR0_PE | CR0_MP | CR0_ET | CR0_NE | CR0_AM | CR0_PG | CR0_WP; - sregs.efer = EFER_LME | EFER_LMA | EFER_SCE | EFER_NX; - sregs.cs.l = 1; // required for 64-bit mode - } else { - sregs.cs.base = 0; - sregs.cs.selector = 0; - } - } - vcpu_fd.set_sregs(&sregs)?; - Ok(()) + Ok(kvm) } } @@ -485,7 +454,7 @@ impl Hypervisor for KVMDriver { None => self.get_max_log_level().into(), }; - let regs = kvm_regs { + let regs = CommonRegisters { rip: self.entrypoint, rsp: self.orig_rsp.absolute()?, @@ -497,7 +466,7 @@ impl Hypervisor for KVMDriver { ..Default::default() }; - self.vcpu_fd.set_regs(®s)?; + self.set_regs(®s)?; VirtualCPU::run( self.as_mut_hypervisor(), @@ -572,24 +541,15 @@ impl Hypervisor for KVMDriver { #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()> { // Reset general purpose registers, then set RIP and RSP - let regs = kvm_regs { + let regs = CommonRegisters { rip: dispatch_func_addr.into(), rsp: self.orig_rsp.absolute()?, ..Default::default() }; - self.vcpu_fd.set_regs(®s)?; + self.set_regs(®s)?; // reset fpu state - let fpu = kvm_fpu { - fcw: FP_CONTROL_WORD_DEFAULT, - ftwx: FP_TAG_WORD_DEFAULT, - mxcsr: MXCSR_DEFAULT, - ..Default::default() // zero out the rest - }; - - // note kvm set_fpu doesn't actually set or read the mxcsr value - // https://elixir.bootlin.com/linux/v6.16/source/arch/x86/kvm/x86.c#L12229 - self.vcpu_fd.set_fpu(&fpu)?; + self.set_fpu(&CommonFpu::default())?; // run VirtualCPU::run( @@ -824,6 +784,39 @@ impl Hypervisor for KVMDriver { Ok(result) } + fn regs(&self) -> Result { + let kvm_regs = self.vcpu_fd.get_regs()?; + Ok((&kvm_regs).into()) + } + + fn set_regs(&mut self, regs: &super::regs::CommonRegisters) -> Result<()> { + let kvm_regs: kvm_regs = regs.into(); + self.vcpu_fd.set_regs(&kvm_regs)?; + Ok(()) + } + + fn fpu(&self) -> Result { + let kvm_fpu = self.vcpu_fd.get_fpu()?; + Ok((&kvm_fpu).into()) + } + + fn set_fpu(&mut self, fpu: &super::regs::CommonFpu) -> Result<()> { + let kvm_fpu: kvm_fpu = fpu.into(); + self.vcpu_fd.set_fpu(&kvm_fpu)?; + Ok(()) + } + + fn sregs(&self) -> Result { + let kvm_sregs = self.vcpu_fd.get_sregs()?; + Ok((&kvm_sregs).into()) + } + + fn set_sregs(&mut self, sregs: &super::regs::CommonSpecialRegisters) -> Result<()> { + let kvm_sregs: kvm_sregs = sregs.into(); + self.vcpu_fd.set_sregs(&kvm_sregs)?; + Ok(()) + } + #[instrument(skip_all, parent = Span::current(), level = "Trace")] fn as_mut_hypervisor(&mut self) -> &mut dyn Hypervisor { self as &mut dyn Hypervisor @@ -1039,18 +1032,6 @@ impl Hypervisor for KVMDriver { } } - #[cfg(feature = "trace_guest")] - fn read_trace_reg(&self, reg: TraceRegister) -> Result { - let regs = self.vcpu_fd.get_regs()?; - Ok(match reg { - TraceRegister::RAX => regs.rax, - TraceRegister::RCX => regs.rcx, - TraceRegister::RIP => regs.rip, - TraceRegister::RSP => regs.rsp, - TraceRegister::RBP => regs.rbp, - }) - } - #[cfg(feature = "trace_guest")] fn trace_info_as_ref(&self) -> &TraceInfo { &self.trace_info diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index 9c04ad3a0..781099134 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -19,16 +19,15 @@ use tracing::{Span, instrument}; use crate::HyperlightError::StackOverflow; use crate::error::HyperlightError::ExecutionCanceledByHost; +use crate::hypervisor::regs::{ + CommonFpu, CommonRegisters, CommonSegmentRegister, CommonSpecialRegisters, +}; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::metrics::METRIC_GUEST_CANCELLATION; #[cfg(feature = "trace_guest")] use crate::sandbox::TraceInfo; use crate::{HyperlightError, Result, log_then_return}; -/// Util for handling x87 fpu state -#[cfg(any(kvm, mshv, target_os = "windows"))] -pub mod fpu; - /// HyperV-on-linux functionality #[cfg(mshv)] pub mod hyperv_linux; @@ -40,6 +39,9 @@ pub(crate) mod hyperv_windows; #[cfg(gdb)] pub(crate) mod gdb; +/// Abstracts over different hypervisor register representations +pub(crate) mod regs; + #[cfg(kvm)] /// Functionality to manipulate KVM-based virtual machines pub mod kvm; @@ -116,21 +118,6 @@ pub enum HyperlightExit { Retry(), } -/// Registers which may be useful for tracing/stack unwinding -#[cfg(feature = "trace_guest")] -pub enum TraceRegister { - /// RAX - RAX, - /// RCX - RCX, - /// RIP - RIP, - /// RSP - RSP, - /// RBP - RBP, -} - /// A common set of hypervisor functionality pub(crate) trait Hypervisor: Debug + Send { /// Initialise the internally stored vCPU with the given PEB address and @@ -189,6 +176,87 @@ pub(crate) trait Hypervisor: Debug + Send { /// Get InterruptHandle to underlying VM fn interrupt_handle(&self) -> Arc; + /// Get regs + #[allow(dead_code)] + fn regs(&self) -> Result; + /// Set regs + #[allow(dead_code)] + fn set_regs(&mut self, regs: &CommonRegisters) -> Result<()>; + /// Get fpu regs + #[allow(dead_code)] + fn fpu(&self) -> Result; + /// Set fpu regs + #[allow(dead_code)] + fn set_fpu(&mut self, fpu: &CommonFpu) -> Result<()>; + /// Get special regs + #[allow(dead_code)] + fn sregs(&self) -> Result; + /// Set special regs + #[allow(dead_code)] + fn set_sregs(&mut self, sregs: &CommonSpecialRegisters) -> Result<()>; + + /// Setup initial special registers for the hypervisor + /// This is a default implementation that works for all hypervisors + fn setup_initial_sregs(&mut self, _pml4_addr: u64) -> Result<()> { + #[cfg(feature = "init-paging")] + let sregs = CommonSpecialRegisters { + cr0: CR0_PE | CR0_MP | CR0_ET | CR0_NE | CR0_AM | CR0_PG | CR0_WP, + cr4: CR4_PAE | CR4_OSFXSR | CR4_OSXMMEXCPT, + cr3: _pml4_addr, + efer: EFER_LME | EFER_LMA | EFER_SCE | EFER_NX, + cs: CommonSegmentRegister { + type_: 11, + present: 1, + s: 1, + l: 1, + ..Default::default() + }, + tr: CommonSegmentRegister { + limit: 65535, + type_: 11, + present: 1, + s: 0, + ..Default::default() + }, + ..Default::default() + }; + + #[cfg(not(feature = "init-paging"))] + let sregs = CommonSpecialRegisters { + cs: CommonSegmentRegister { + base: 0, + selector: 0, + limit: 0xFFFF, + type_: 11, + present: 1, + s: 1, + ..Default::default() + }, + ds: CommonSegmentRegister { + base: 0, + selector: 0, + limit: 0xFFFF, + type_: 3, + present: 1, + s: 1, + ..Default::default() + }, + tr: CommonSegmentRegister { + base: 0, + selector: 0, + limit: 0xFFFF, + type_: 11, + present: 1, + s: 0, + ..Default::default() + }, + ..Default::default() + }; + + self.set_sregs(&sregs)?; + Ok(()) + } + /// Get the logging level to pass to the guest entrypoint fn get_max_log_level(&self) -> u32 { // Check to see if the RUST_LOG environment variable is set @@ -245,10 +313,6 @@ pub(crate) trait Hypervisor: Debug + Send { /// Check stack guard to see if the stack is still valid fn check_stack_guard(&self) -> Result; - /// Read a register for trace/unwind purposes - #[cfg(feature = "trace_guest")] - fn read_trace_reg(&self, reg: TraceRegister) -> Result; - /// Get a reference of the trace info for the guest #[cfg(feature = "trace_guest")] fn trace_info_as_ref(&self) -> &TraceInfo; diff --git a/src/hyperlight_host/src/hypervisor/fpu.rs b/src/hyperlight_host/src/hypervisor/regs.rs similarity index 56% rename from src/hyperlight_host/src/hypervisor/fpu.rs rename to src/hyperlight_host/src/hypervisor/regs.rs index f0b6cb6a2..d29edf4bf 100644 --- a/src/hyperlight_host/src/hypervisor/fpu.rs +++ b/src/hyperlight_host/src/hypervisor/regs.rs @@ -14,6 +14,23 @@ See the License for the specific language governing permissions and limitations under the License. */ -pub(crate) const FP_CONTROL_WORD_DEFAULT: u16 = 0x37f; // mask all fp-exception, set rounding to nearest, set precision to 64-bit -pub(crate) const FP_TAG_WORD_DEFAULT: u8 = 0xff; // each 8 of x87 fpu registers is empty -pub(crate) const MXCSR_DEFAULT: u32 = 0x1f80; // mask simd fp-exceptions, clear exception flags, set rounding to nearest, disable flush-to-zero mode, disable denormals-are-zero mode +mod fpu; +mod special_regs; +mod standard_regs; + +#[cfg(target_os = "windows")] +use std::collections::HashSet; + +pub(crate) use fpu::*; +pub(crate) use special_regs::*; +pub(crate) use standard_regs::*; + +#[cfg(target_os = "windows")] +#[derive(Debug, PartialEq)] +pub(crate) enum FromWhpRegisterError { + MissingRegister(HashSet), + InvalidLength(usize), + InvalidEncoding, + DuplicateRegister(i32), + InvalidRegister(i32), +} diff --git a/src/hyperlight_host/src/hypervisor/regs/fpu.rs b/src/hyperlight_host/src/hypervisor/regs/fpu.rs new file mode 100644 index 000000000..0ccd080ab --- /dev/null +++ b/src/hyperlight_host/src/hypervisor/regs/fpu.rs @@ -0,0 +1,438 @@ +/* +Copyright 2024 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#[cfg(mshv2)] +extern crate mshv_bindings2 as mshv_bindings; +#[cfg(mshv2)] +extern crate mshv_ioctls2 as mshv_ioctls; + +#[cfg(mshv3)] +extern crate mshv_bindings3 as mshv_bindings; +#[cfg(mshv3)] +extern crate mshv_ioctls3 as mshv_ioctls; + +#[cfg(target_os = "windows")] +use std::collections::HashSet; + +#[cfg(kvm)] +use kvm_bindings::kvm_fpu; +#[cfg(mshv)] +use mshv_bindings::FloatingPointUnit; + +#[cfg(target_os = "windows")] +use super::Align16; +#[cfg(target_os = "windows")] +use crate::hypervisor::regs::FromWhpRegisterError; + +pub(crate) const FP_CONTROL_WORD_DEFAULT: u16 = 0x37f; // mask all fp-exception, set rounding to nearest, set precision to 64-bit +pub(crate) const MXCSR_DEFAULT: u32 = 0x1f80; // mask simd fp-exceptions, clear exception flags, set rounding to nearest, disable flush-to-zero mode, disable denormals-are-zero mode + +#[derive(Debug, Clone, Copy, PartialEq)] +pub(crate) struct CommonFpu { + pub fpr: [[u8; 16]; 8], + pub fcw: u16, + pub fsw: u16, + pub ftwx: u8, + pub pad1: u8, + pub last_opcode: u16, + pub last_ip: u64, + pub last_dp: u64, + pub xmm: [[u8; 16]; 16], + pub mxcsr: u32, + pub pad2: u32, +} + +impl Default for CommonFpu { + fn default() -> Self { + Self { + fpr: [[0u8; 16]; 8], + fcw: FP_CONTROL_WORD_DEFAULT, + fsw: 0, + ftwx: 0, + pad1: 0, + last_opcode: 0, + last_ip: 0, + last_dp: 0, + xmm: [[0u8; 16]; 16], + mxcsr: MXCSR_DEFAULT, + pad2: 0, + } + } +} + +#[cfg(kvm)] +impl From<&CommonFpu> for kvm_fpu { + fn from(common_fpu: &CommonFpu) -> Self { + kvm_fpu { + fpr: common_fpu.fpr, + fcw: common_fpu.fcw, + fsw: common_fpu.fsw, + ftwx: common_fpu.ftwx, + pad1: common_fpu.pad1, + last_opcode: common_fpu.last_opcode, + last_ip: common_fpu.last_ip, + last_dp: common_fpu.last_dp, + xmm: common_fpu.xmm, + mxcsr: common_fpu.mxcsr, + pad2: common_fpu.pad2, + } + } +} + +#[cfg(mshv)] +impl From<&CommonFpu> for FloatingPointUnit { + fn from(common_fpu: &CommonFpu) -> FloatingPointUnit { + FloatingPointUnit { + fpr: common_fpu.fpr, + fcw: common_fpu.fcw, + fsw: common_fpu.fsw, + ftwx: common_fpu.ftwx, + pad1: common_fpu.pad1, + last_opcode: common_fpu.last_opcode, + last_ip: common_fpu.last_ip, + last_dp: common_fpu.last_dp, + xmm: common_fpu.xmm, + mxcsr: common_fpu.mxcsr, + pad2: common_fpu.pad2, + } + } +} + +#[cfg(kvm)] +impl From<&kvm_fpu> for CommonFpu { + fn from(kvm_fpu: &kvm_fpu) -> Self { + Self { + fpr: kvm_fpu.fpr, + fcw: kvm_fpu.fcw, + fsw: kvm_fpu.fsw, + ftwx: kvm_fpu.ftwx, + pad1: kvm_fpu.pad1, + last_opcode: kvm_fpu.last_opcode, + last_ip: kvm_fpu.last_ip, + last_dp: kvm_fpu.last_dp, + xmm: kvm_fpu.xmm, + mxcsr: kvm_fpu.mxcsr, + pad2: kvm_fpu.pad2, + } + } +} + +#[cfg(mshv)] +impl From<&FloatingPointUnit> for CommonFpu { + fn from(mshv_fpu: &FloatingPointUnit) -> Self { + Self { + fpr: mshv_fpu.fpr, + fcw: mshv_fpu.fcw, + fsw: mshv_fpu.fsw, + ftwx: mshv_fpu.ftwx, + pad1: mshv_fpu.pad1, + last_opcode: mshv_fpu.last_opcode, + last_ip: mshv_fpu.last_ip, + last_dp: mshv_fpu.last_dp, + xmm: mshv_fpu.xmm, + mxcsr: mshv_fpu.mxcsr, + pad2: mshv_fpu.pad2, + } + } +} + +#[cfg(target_os = "windows")] +use windows::Win32::System::Hypervisor::*; + +#[cfg(target_os = "windows")] +impl From<&CommonFpu> for [(WHV_REGISTER_NAME, Align16); WHP_FPU_NAMES_LEN] { + fn from(fpu: &CommonFpu) -> Self { + let mut regs: [(WHV_REGISTER_NAME, Align16); WHP_FPU_NAMES_LEN] = + [Default::default(); WHP_FPU_NAMES_LEN]; + let mut idx = 0; + + // FPU/MMX registers (8 x 128-bit) + for (i, reg) in fpu.fpr.iter().enumerate() { + let mut value = WHV_REGISTER_VALUE::default(); + value.Reg128 = WHV_UINT128 { + Dword: [ + u32::from_le_bytes([reg[0], reg[1], reg[2], reg[3]]), + u32::from_le_bytes([reg[4], reg[5], reg[6], reg[7]]), + u32::from_le_bytes([reg[8], reg[9], reg[10], reg[11]]), + u32::from_le_bytes([reg[12], reg[13], reg[14], reg[15]]), + ], + }; + regs[idx] = ( + WHV_REGISTER_NAME(WHvX64RegisterFpMmx0.0 + i as i32), + Align16(value), + ); + idx += 1; + } + + // FpControlStatus + let mut fp_control_status = WHV_REGISTER_VALUE::default(); + fp_control_status.FpControlStatus = WHV_X64_FP_CONTROL_STATUS_REGISTER { + Anonymous: WHV_X64_FP_CONTROL_STATUS_REGISTER_0 { + FpControl: fpu.fcw, + FpStatus: fpu.fsw, + FpTag: fpu.ftwx, + Reserved: fpu.pad1, + LastFpOp: fpu.last_opcode, + Anonymous: WHV_X64_FP_CONTROL_STATUS_REGISTER_0_0 { + LastFpRip: fpu.last_ip, + }, + }, + }; + regs[idx] = (WHvX64RegisterFpControlStatus, Align16(fp_control_status)); + idx += 1; + + // XMM registers (16 x 128-bit) + for (i, reg) in fpu.xmm.iter().enumerate() { + let mut value = WHV_REGISTER_VALUE::default(); + value.Reg128 = WHV_UINT128 { + Dword: [ + u32::from_le_bytes([reg[0], reg[1], reg[2], reg[3]]), + u32::from_le_bytes([reg[4], reg[5], reg[6], reg[7]]), + u32::from_le_bytes([reg[8], reg[9], reg[10], reg[11]]), + u32::from_le_bytes([reg[12], reg[13], reg[14], reg[15]]), + ], + }; + regs[idx] = ( + WHV_REGISTER_NAME(WHvX64RegisterXmm0.0 + i as i32), + Align16(value), + ); + idx += 1; + } + + // XmmControlStatus + let mut xmm_control_status = WHV_REGISTER_VALUE::default(); + xmm_control_status.XmmControlStatus = WHV_X64_XMM_CONTROL_STATUS_REGISTER { + Anonymous: WHV_X64_XMM_CONTROL_STATUS_REGISTER_0 { + XmmStatusControl: fpu.mxcsr, + XmmStatusControlMask: !0, + Anonymous: WHV_X64_XMM_CONTROL_STATUS_REGISTER_0_0 { + LastFpRdp: fpu.last_dp, + }, + }, + }; + regs[idx] = (WHvX64RegisterXmmControlStatus, Align16(xmm_control_status)); + + regs + } +} + +#[cfg(target_os = "windows")] +pub(crate) const WHP_FPU_NAMES_LEN: usize = 26; +#[cfg(target_os = "windows")] +pub(crate) const WHP_FPU_NAMES: [WHV_REGISTER_NAME; WHP_FPU_NAMES_LEN] = [ + WHvX64RegisterFpMmx0, + WHvX64RegisterFpMmx1, + WHvX64RegisterFpMmx2, + WHvX64RegisterFpMmx3, + WHvX64RegisterFpMmx4, + WHvX64RegisterFpMmx5, + WHvX64RegisterFpMmx6, + WHvX64RegisterFpMmx7, + WHvX64RegisterFpControlStatus, + WHvX64RegisterXmm0, + WHvX64RegisterXmm1, + WHvX64RegisterXmm2, + WHvX64RegisterXmm3, + WHvX64RegisterXmm4, + WHvX64RegisterXmm5, + WHvX64RegisterXmm6, + WHvX64RegisterXmm7, + WHvX64RegisterXmm8, + WHvX64RegisterXmm9, + WHvX64RegisterXmm10, + WHvX64RegisterXmm11, + WHvX64RegisterXmm12, + WHvX64RegisterXmm13, + WHvX64RegisterXmm14, + WHvX64RegisterXmm15, + WHvX64RegisterXmmControlStatus, +]; + +#[cfg(target_os = "windows")] +impl TryFrom<&[(WHV_REGISTER_NAME, Align16)]> for CommonFpu { + type Error = FromWhpRegisterError; + + fn try_from( + regs: &[(WHV_REGISTER_NAME, Align16)], + ) -> Result { + if regs.len() != WHP_FPU_NAMES_LEN { + return Err(FromWhpRegisterError::InvalidLength(regs.len())); + } + + let mut fpu = CommonFpu::default(); + let mut seen_registers = HashSet::new(); + + for (name, value) in regs { + let name_id = name.0; + + // Check for duplicates + if !seen_registers.insert(name_id) { + return Err(FromWhpRegisterError::DuplicateRegister(name_id)); + } + + match name_id { + id if (WHvX64RegisterFpMmx0.0..WHvX64RegisterFpMmx0.0 + 8).contains(&id) => { + let idx = (id - WHvX64RegisterFpMmx0.0) as usize; + let dwords = unsafe { value.0.Reg128.Dword }; + fpu.fpr[idx] = [ + dwords[0].to_le_bytes(), + dwords[1].to_le_bytes(), + dwords[2].to_le_bytes(), + dwords[3].to_le_bytes(), + ] + .concat() + .try_into() + .map_err(|_| FromWhpRegisterError::InvalidEncoding)?; + } + + id if id == WHvX64RegisterFpControlStatus.0 => { + let control = unsafe { value.0.FpControlStatus.Anonymous }; + fpu.fcw = control.FpControl; + fpu.fsw = control.FpStatus; + fpu.ftwx = control.FpTag; + fpu.pad1 = control.Reserved; + fpu.last_opcode = control.LastFpOp; + fpu.last_ip = unsafe { control.Anonymous.LastFpRip }; + } + + id if (WHvX64RegisterXmm0.0..WHvX64RegisterXmm0.0 + 16).contains(&id) => { + let idx = (id - WHvX64RegisterXmm0.0) as usize; + let dwords = unsafe { value.0.Reg128.Dword }; + fpu.xmm[idx] = [ + dwords[0].to_le_bytes(), + dwords[1].to_le_bytes(), + dwords[2].to_le_bytes(), + dwords[3].to_le_bytes(), + ] + .concat() + .try_into() + .map_err(|_| FromWhpRegisterError::InvalidEncoding)?; + } + + id if id == WHvX64RegisterXmmControlStatus.0 => { + let control = unsafe { value.0.XmmControlStatus.Anonymous }; + fpu.mxcsr = control.XmmStatusControl; + fpu.last_dp = unsafe { control.Anonymous.LastFpRdp }; + } + + _ => { + return Err(FromWhpRegisterError::InvalidRegister(name_id)); + } + } + } + + // Set of all expected register names + let expected_registers: HashSet = WHP_FPU_NAMES.iter().map(|reg| reg.0).collect(); + + // Technically it should not be possible to have any missing registers at this point + // since we are guaranteed to have WHP_FPU_NAMES_LEN non-duplicate registers that have passed the match-arm above, but leaving this here for safety anyway + let missing: HashSet = expected_registers + .difference(&seen_registers) + .cloned() + .collect(); + + if !missing.is_empty() { + return Err(FromWhpRegisterError::MissingRegister(missing)); + } + + Ok(fpu) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn sample_common_fpu() -> CommonFpu { + CommonFpu { + fpr: [ + [1u8; 16], [2u8; 16], [3u8; 16], [4u8; 16], [5u8; 16], [6u8; 16], [7u8; 16], + [8u8; 16], + ], + fcw: 0x1234, + fsw: 0x5678, + ftwx: 0x9a, + pad1: 0xbc, + last_opcode: 0xdef0, + last_ip: 0xdeadbeefcafebabe, + last_dp: 0xabad1deaf00dbabe, + xmm: [ + [8u8; 16], [9u8; 16], [10u8; 16], [11u8; 16], [12u8; 16], [13u8; 16], [14u8; 16], + [15u8; 16], [16u8; 16], [17u8; 16], [18u8; 16], [19u8; 16], [20u8; 16], [21u8; 16], + [22u8; 16], [23u8; 16], + ], + mxcsr: 0x1f80, + pad2: 0, + } + } + + #[cfg(kvm)] + #[test] + fn round_trip_kvm_fpu() { + use kvm_bindings::kvm_fpu; + + let original = sample_common_fpu(); + let kvm: kvm_fpu = (&original).into(); + let round_tripped = CommonFpu::from(&kvm); + + assert_eq!(original, round_tripped); + } + + #[cfg(mshv)] + #[test] + fn round_trip_mshv_fpu() { + use mshv_bindings::FloatingPointUnit; + + let original = sample_common_fpu(); + let mshv: FloatingPointUnit = (&original).into(); + let round_tripped = CommonFpu::from(&mshv); + + assert_eq!(original, round_tripped); + } + + #[cfg(target_os = "windows")] + #[test] + fn round_trip_windows_fpu() { + use windows::Win32::System::Hypervisor::*; + + let original = sample_common_fpu(); + let windows: [(WHV_REGISTER_NAME, Align16); WHP_FPU_NAMES_LEN] = + (&original).into(); + let round_tripped = CommonFpu::try_from(windows.as_ref()).unwrap(); + assert_eq!(original, round_tripped); + + // test for duplicate register error handling + let original = sample_common_fpu(); + let mut windows: [(WHV_REGISTER_NAME, Align16); WHP_FPU_NAMES_LEN] = + (&original).into(); + windows[0].0 = WHvX64RegisterFpMmx1; + let err = CommonFpu::try_from(windows.as_ref()).unwrap_err(); + assert_eq!( + err, + FromWhpRegisterError::DuplicateRegister(WHvX64RegisterFpMmx1.0) + ); + + // test for passing non-fpu register (e.g. RAX) + let original = sample_common_fpu(); + let mut windows: [(WHV_REGISTER_NAME, Align16); WHP_FPU_NAMES_LEN] = + (&original).into(); + windows[0] = (WHvX64RegisterRax, windows[0].1); + let err = CommonFpu::try_from(windows.as_ref()).unwrap_err(); + assert_eq!( + err, + FromWhpRegisterError::InvalidRegister(WHvX64RegisterRax.0) + ); + } +} diff --git a/src/hyperlight_host/src/hypervisor/regs/special_regs.rs b/src/hyperlight_host/src/hypervisor/regs/special_regs.rs new file mode 100644 index 000000000..b20291d16 --- /dev/null +++ b/src/hyperlight_host/src/hypervisor/regs/special_regs.rs @@ -0,0 +1,667 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#[cfg(mshv2)] +extern crate mshv_bindings2 as mshv_bindings; +#[cfg(mshv2)] +extern crate mshv_ioctls2 as mshv_ioctls; + +#[cfg(mshv3)] +extern crate mshv_bindings3 as mshv_bindings; +#[cfg(mshv3)] +extern crate mshv_ioctls3 as mshv_ioctls; + +#[cfg(target_os = "windows")] +use std::collections::HashSet; + +#[cfg(kvm)] +use kvm_bindings::{kvm_dtable, kvm_segment, kvm_sregs}; +#[cfg(mshv)] +use mshv_bindings::{SegmentRegister, SpecialRegisters, TableRegister}; +#[cfg(target_os = "windows")] +use windows::Win32::System::Hypervisor::*; + +#[cfg(target_os = "windows")] +use super::FromWhpRegisterError; + +#[derive(Debug, Default, Copy, Clone, PartialEq)] +pub(crate) struct CommonSpecialRegisters { + pub cs: CommonSegmentRegister, + pub ds: CommonSegmentRegister, + pub es: CommonSegmentRegister, + pub fs: CommonSegmentRegister, + pub gs: CommonSegmentRegister, + pub ss: CommonSegmentRegister, + pub tr: CommonSegmentRegister, + pub ldt: CommonSegmentRegister, + pub gdt: CommonTableRegister, + pub idt: CommonTableRegister, + pub cr0: u64, + pub cr2: u64, + pub cr3: u64, + pub cr4: u64, + pub cr8: u64, + pub efer: u64, + pub apic_base: u64, + pub interrupt_bitmap: [u64; 4], +} + +#[cfg(mshv)] +impl From<&SpecialRegisters> for CommonSpecialRegisters { + fn from(value: &SpecialRegisters) -> Self { + CommonSpecialRegisters { + cs: value.cs.into(), + ds: value.ds.into(), + es: value.es.into(), + fs: value.fs.into(), + gs: value.gs.into(), + ss: value.ss.into(), + tr: value.tr.into(), + ldt: value.ldt.into(), + gdt: value.gdt.into(), + idt: value.idt.into(), + cr0: value.cr0, + cr2: value.cr2, + cr3: value.cr3, + cr4: value.cr4, + cr8: value.cr8, + efer: value.efer, + apic_base: value.apic_base, + interrupt_bitmap: value.interrupt_bitmap, + } + } +} + +#[cfg(mshv)] +impl From<&CommonSpecialRegisters> for SpecialRegisters { + fn from(other: &CommonSpecialRegisters) -> Self { + SpecialRegisters { + cs: other.cs.into(), + ds: other.ds.into(), + es: other.es.into(), + fs: other.fs.into(), + gs: other.gs.into(), + ss: other.ss.into(), + tr: other.tr.into(), + ldt: other.ldt.into(), + gdt: other.gdt.into(), + idt: other.idt.into(), + cr0: other.cr0, + cr2: other.cr2, + cr3: other.cr3, + cr4: other.cr4, + cr8: other.cr8, + efer: other.efer, + apic_base: other.apic_base, + interrupt_bitmap: other.interrupt_bitmap, + } + } +} + +#[cfg(kvm)] +impl From<&kvm_sregs> for CommonSpecialRegisters { + fn from(kvm_sregs: &kvm_sregs) -> Self { + CommonSpecialRegisters { + cs: kvm_sregs.cs.into(), + ds: kvm_sregs.ds.into(), + es: kvm_sregs.es.into(), + fs: kvm_sregs.fs.into(), + gs: kvm_sregs.gs.into(), + ss: kvm_sregs.ss.into(), + tr: kvm_sregs.tr.into(), + ldt: kvm_sregs.ldt.into(), + gdt: kvm_sregs.gdt.into(), + idt: kvm_sregs.idt.into(), + cr0: kvm_sregs.cr0, + cr2: kvm_sregs.cr2, + cr3: kvm_sregs.cr3, + cr4: kvm_sregs.cr4, + cr8: kvm_sregs.cr8, + efer: kvm_sregs.efer, + apic_base: kvm_sregs.apic_base, + interrupt_bitmap: kvm_sregs.interrupt_bitmap, + } + } +} + +#[cfg(kvm)] +impl From<&CommonSpecialRegisters> for kvm_sregs { + fn from(common_sregs: &CommonSpecialRegisters) -> Self { + kvm_sregs { + cs: common_sregs.cs.into(), + ds: common_sregs.ds.into(), + es: common_sregs.es.into(), + fs: common_sregs.fs.into(), + gs: common_sregs.gs.into(), + ss: common_sregs.ss.into(), + tr: common_sregs.tr.into(), + ldt: common_sregs.ldt.into(), + gdt: common_sregs.gdt.into(), + idt: common_sregs.idt.into(), + cr0: common_sregs.cr0, + cr2: common_sregs.cr2, + cr3: common_sregs.cr3, + cr4: common_sregs.cr4, + cr8: common_sregs.cr8, + efer: common_sregs.efer, + apic_base: common_sregs.apic_base, + interrupt_bitmap: common_sregs.interrupt_bitmap, + } + } +} + +/// WHV_REGISTER_VALUE must be 16-byte aligned, but the rust struct is incorrectly generated +/// as 8-byte aligned. This is a workaround to ensure that the struct is 16-byte aligned. +#[cfg(target_os = "windows")] +#[repr(C, align(16))] +#[derive(Debug, Default, Copy, Clone, PartialEq)] +pub(crate) struct Align16(pub(crate) T); + +#[cfg(target_os = "windows")] +#[allow(clippy::disallowed_macros)] // compile time +const _: () = { + assert!( + std::mem::size_of::>() + == std::mem::size_of::() + ); +}; + +#[cfg(target_os = "windows")] +pub(crate) const WHP_SREGS_NAMES_LEN: usize = 17; +#[cfg(target_os = "windows")] +pub(crate) static WHP_SREGS_NAMES: [WHV_REGISTER_NAME; WHP_SREGS_NAMES_LEN] = [ + WHvX64RegisterCs, + WHvX64RegisterDs, + WHvX64RegisterEs, + WHvX64RegisterFs, + WHvX64RegisterGs, + WHvX64RegisterSs, + WHvX64RegisterTr, + WHvX64RegisterLdtr, + WHvX64RegisterGdtr, + WHvX64RegisterIdtr, + WHvX64RegisterCr0, + WHvX64RegisterCr2, + WHvX64RegisterCr3, + WHvX64RegisterCr4, + WHvX64RegisterCr8, + WHvX64RegisterEfer, + WHvX64RegisterApicBase, +]; + +#[cfg(target_os = "windows")] +impl From<&CommonSpecialRegisters> + for [(WHV_REGISTER_NAME, Align16); WHP_SREGS_NAMES_LEN] +{ + fn from(other: &CommonSpecialRegisters) -> Self { + [ + (WHvX64RegisterCs, Align16(other.cs.into())), + (WHvX64RegisterDs, Align16(other.ds.into())), + (WHvX64RegisterEs, Align16(other.es.into())), + (WHvX64RegisterFs, Align16(other.fs.into())), + (WHvX64RegisterGs, Align16(other.gs.into())), + (WHvX64RegisterSs, Align16(other.ss.into())), + (WHvX64RegisterTr, Align16(other.tr.into())), + (WHvX64RegisterLdtr, Align16(other.ldt.into())), + (WHvX64RegisterGdtr, Align16(other.gdt.into())), + (WHvX64RegisterIdtr, Align16(other.idt.into())), + ( + WHvX64RegisterCr0, + Align16(WHV_REGISTER_VALUE { Reg64: other.cr0 }), + ), + ( + WHvX64RegisterCr2, + Align16(WHV_REGISTER_VALUE { Reg64: other.cr2 }), + ), + ( + WHvX64RegisterCr3, + Align16(WHV_REGISTER_VALUE { Reg64: other.cr3 }), + ), + ( + WHvX64RegisterCr4, + Align16(WHV_REGISTER_VALUE { Reg64: other.cr4 }), + ), + ( + WHvX64RegisterCr8, + Align16(WHV_REGISTER_VALUE { Reg64: other.cr8 }), + ), + ( + WHvX64RegisterEfer, + Align16(WHV_REGISTER_VALUE { Reg64: other.efer }), + ), + ( + WHvX64RegisterApicBase, + Align16(WHV_REGISTER_VALUE { + Reg64: other.apic_base, + }), + ), + ] + } +} + +#[cfg(target_os = "windows")] +impl TryFrom<&[(WHV_REGISTER_NAME, Align16)]> for CommonSpecialRegisters { + type Error = FromWhpRegisterError; + + #[expect( + non_upper_case_globals, + reason = "Windows API has lowercase register names" + )] + fn try_from( + regs: &[(WHV_REGISTER_NAME, Align16)], + ) -> Result { + if regs.len() != WHP_SREGS_NAMES_LEN { + return Err(FromWhpRegisterError::InvalidLength(regs.len())); + } + let mut registers = CommonSpecialRegisters::default(); + let mut seen_registers = HashSet::new(); + + for &(name, ref value) in regs { + let name_id = name.0; + + // Check for duplicates + if !seen_registers.insert(name_id) { + return Err(FromWhpRegisterError::DuplicateRegister(name_id)); + } + + unsafe { + match name { + WHvX64RegisterCs => registers.cs = value.0.into(), + WHvX64RegisterDs => registers.ds = value.0.into(), + WHvX64RegisterEs => registers.es = value.0.into(), + WHvX64RegisterFs => registers.fs = value.0.into(), + WHvX64RegisterGs => registers.gs = value.0.into(), + WHvX64RegisterSs => registers.ss = value.0.into(), + WHvX64RegisterTr => registers.tr = value.0.into(), + WHvX64RegisterLdtr => registers.ldt = value.0.into(), + WHvX64RegisterGdtr => registers.gdt = value.0.into(), + WHvX64RegisterIdtr => registers.idt = value.0.into(), + WHvX64RegisterCr0 => registers.cr0 = value.0.Reg64, + WHvX64RegisterCr2 => registers.cr2 = value.0.Reg64, + WHvX64RegisterCr3 => registers.cr3 = value.0.Reg64, + WHvX64RegisterCr4 => registers.cr4 = value.0.Reg64, + WHvX64RegisterCr8 => registers.cr8 = value.0.Reg64, + WHvX64RegisterEfer => registers.efer = value.0.Reg64, + WHvX64RegisterApicBase => registers.apic_base = value.0.Reg64, + _ => { + // Given unexpected register + return Err(FromWhpRegisterError::InvalidRegister(name_id)); + } + } + } + } + + // TODO: I'm not sure how to get this from WHP at the moment + registers.interrupt_bitmap = Default::default(); + + // Set of all expected register names + let expected_registers: HashSet = + WHP_SREGS_NAMES.map(|name| name.0).into_iter().collect(); + + // Technically it should not be possible to have any missing registers at this point + // since we are guaranteed to have WHP_SREGS_NAMES_LEN (17) non-duplicate registers that have passed the match-arm above, but leaving this here for safety anyway + let missing: HashSet<_> = expected_registers + .difference(&seen_registers) + .cloned() + .collect(); + + if !missing.is_empty() { + return Err(FromWhpRegisterError::MissingRegister(missing)); + } + + Ok(registers) + } +} + +// --- Segment Register --- + +#[derive(Debug, Default, Copy, Clone, PartialEq)] +pub(crate) struct CommonSegmentRegister { + pub base: u64, + pub limit: u32, + pub selector: u16, + pub type_: u8, + pub present: u8, + pub dpl: u8, + pub db: u8, + pub s: u8, + pub l: u8, + pub g: u8, + pub avl: u8, + pub unusable: u8, + pub padding: u8, +} + +#[cfg(mshv)] +impl From for CommonSegmentRegister { + fn from(other: SegmentRegister) -> Self { + CommonSegmentRegister { + base: other.base, + limit: other.limit, + selector: other.selector, + type_: other.type_, + present: other.present, + dpl: other.dpl, + db: other.db, + s: other.s, + l: other.l, + g: other.g, + avl: other.avl, + unusable: other.unusable, + padding: other.padding, + } + } +} + +#[cfg(mshv)] +impl From for SegmentRegister { + fn from(other: CommonSegmentRegister) -> Self { + SegmentRegister { + base: other.base, + limit: other.limit, + selector: other.selector, + type_: other.type_, + present: other.present, + dpl: other.dpl, + db: other.db, + s: other.s, + l: other.l, + g: other.g, + avl: other.avl, + unusable: other.unusable, + padding: other.padding, + } + } +} + +#[cfg(kvm)] +impl From for CommonSegmentRegister { + fn from(kvm_segment: kvm_segment) -> Self { + CommonSegmentRegister { + base: kvm_segment.base, + limit: kvm_segment.limit, + selector: kvm_segment.selector, + type_: kvm_segment.type_, + present: kvm_segment.present, + dpl: kvm_segment.dpl, + db: kvm_segment.db, + s: kvm_segment.s, + l: kvm_segment.l, + g: kvm_segment.g, + avl: kvm_segment.avl, + unusable: kvm_segment.unusable, + padding: kvm_segment.padding, + } + } +} + +#[cfg(kvm)] +impl From for kvm_segment { + fn from(common_segment: CommonSegmentRegister) -> Self { + kvm_segment { + base: common_segment.base, + limit: common_segment.limit, + selector: common_segment.selector, + type_: common_segment.type_, + present: common_segment.present, + dpl: common_segment.dpl, + db: common_segment.db, + s: common_segment.s, + l: common_segment.l, + g: common_segment.g, + avl: common_segment.avl, + unusable: common_segment.unusable, + padding: common_segment.padding, + } + } +} + +#[cfg(target_os = "windows")] +impl From for CommonSegmentRegister { + fn from(other: WHV_REGISTER_VALUE) -> Self { + unsafe { + let segment = other.Segment; + let bits = segment.Anonymous.Attributes; + + // Source of bit layout: https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvvirtualprocessordatatypes + CommonSegmentRegister { + base: segment.Base, + limit: segment.Limit, + selector: segment.Selector, + type_: (bits & 0b1111) as u8, // bits 0–3: SegmentType + s: ((bits >> 4) & 0b1) as u8, // bit 4: NonSystemSegment + dpl: ((bits >> 5) & 0b11) as u8, // bits 5–6: DPL + present: ((bits >> 7) & 0b1) as u8, // bit 7: Present + // bits 8–11: Reserved + avl: ((bits >> 12) & 0b1) as u8, // bit 12: Available + l: ((bits >> 13) & 0b1) as u8, // bit 13: Long mode + db: ((bits >> 14) & 0b1) as u8, // bit 14: Default + g: ((bits >> 15) & 0b1) as u8, // bit 15: Granularity + unusable: 0, + padding: 0, + } + } + } +} + +#[cfg(target_os = "windows")] +impl From for WHV_REGISTER_VALUE { + fn from(other: CommonSegmentRegister) -> Self { + // Truncate each field to its valid bit width before composing `Attributes`. + let type_ = other.type_ & 0xF; // 4 bits + let s = other.s & 0x1; // 1 bit + let dpl = other.dpl & 0x3; // 2 bits + let present = other.present & 0x1; // 1 bit + let avl = other.avl & 0x1; // 1 bit + let l = other.l & 0x1; // 1 bit + let db = other.db & 0x1; // 1 bit + let g = other.g & 0x1; // 1 bit + + WHV_REGISTER_VALUE { + Segment: WHV_X64_SEGMENT_REGISTER { + Base: other.base, + Limit: other.limit, + Selector: other.selector, + Anonymous: WHV_X64_SEGMENT_REGISTER_0 { + Attributes: (type_ as u16) // bit 0-3 + | ((s as u16) << 4) // bit 4 + | ((dpl as u16) << 5) // bit 5-6 + | ((present as u16) << 7) // bit 7 + | ((avl as u16) << 12) // bit 12 + | ((l as u16) << 13) // bit 13 + | ((db as u16) << 14) // bit 14 + | ((g as u16) << 15), // bit 15 + }, + }, + } + } +} + +// --- Table Register --- + +#[derive(Debug, Default, Copy, Clone, PartialEq)] +pub(crate) struct CommonTableRegister { + pub base: u64, + pub limit: u16, +} + +#[cfg(mshv)] +impl From for CommonTableRegister { + fn from(other: TableRegister) -> Self { + CommonTableRegister { + base: other.base, + limit: other.limit, + } + } +} + +#[cfg(mshv)] +impl From for TableRegister { + fn from(other: CommonTableRegister) -> Self { + TableRegister { + base: other.base, + limit: other.limit, + } + } +} + +#[cfg(kvm)] +impl From for CommonTableRegister { + fn from(kvm_dtable: kvm_dtable) -> Self { + CommonTableRegister { + base: kvm_dtable.base, + limit: kvm_dtable.limit, + } + } +} + +#[cfg(kvm)] +impl From for kvm_dtable { + fn from(common_dtable: CommonTableRegister) -> Self { + kvm_dtable { + base: common_dtable.base, + limit: common_dtable.limit, + padding: Default::default(), + } + } +} + +#[cfg(target_os = "windows")] +impl From for CommonTableRegister { + fn from(other: WHV_REGISTER_VALUE) -> Self { + unsafe { + let table = other.Table; + CommonTableRegister { + base: table.Base, + limit: table.Limit, + } + } + } +} + +#[cfg(target_os = "windows")] +impl From for WHV_REGISTER_VALUE { + fn from(other: CommonTableRegister) -> Self { + WHV_REGISTER_VALUE { + Table: WHV_X64_TABLE_REGISTER { + Base: other.base, + Limit: other.limit, + Pad: Default::default(), + }, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn sample_common_special_registers() -> CommonSpecialRegisters { + let sample_segment = CommonSegmentRegister { + base: 0x1000, + limit: 0xFFFF, + selector: 0x10, + type_: 0xB, + present: 1, + dpl: 0, + db: 1, + s: 1, + l: 0, + g: 1, + avl: 0, + unusable: 0, + padding: 0, + }; + + let sample_table = CommonTableRegister { + base: 0x2000, + limit: 0x1000, + }; + + CommonSpecialRegisters { + cs: sample_segment, + ds: sample_segment, + es: sample_segment, + fs: sample_segment, + gs: sample_segment, + ss: sample_segment, + tr: sample_segment, + ldt: sample_segment, + gdt: sample_table, + idt: sample_table, + cr0: 0xDEAD_BEEF, + cr2: 0xBAD_C0DE, + cr3: 0xC0FFEE, + cr4: 0xFACE_CAFE, + cr8: 0x1234, + efer: 0x5678, + apic_base: 0x9ABC, + interrupt_bitmap: [0; 4], + } + } + + #[cfg(kvm)] + #[test] + fn round_trip_kvm_sregs() { + let original = sample_common_special_registers(); + let kvm_sregs: kvm_sregs = (&original).into(); + let roundtrip = CommonSpecialRegisters::from(&kvm_sregs); + + assert_eq!(original, roundtrip); + } + + #[cfg(mshv)] + #[test] + fn round_trip_mshv_sregs() { + let original = sample_common_special_registers(); + let mshv_sregs: SpecialRegisters = (&original).into(); + let roundtrip = CommonSpecialRegisters::from(&mshv_sregs); + + assert_eq!(original, roundtrip); + } + + #[cfg(target_os = "windows")] + #[test] + fn round_trip_whp_sregs() { + let original = sample_common_special_registers(); + let whp_sregs: [(WHV_REGISTER_NAME, Align16); WHP_SREGS_NAMES_LEN] = + (&original).into(); + let roundtrip = CommonSpecialRegisters::try_from(whp_sregs.as_ref()).unwrap(); + assert_eq!(original, roundtrip); + + // Test duplicate register error + let original = sample_common_special_registers(); + let mut whp_sregs: [(WHV_REGISTER_NAME, Align16); WHP_SREGS_NAMES_LEN] = + (&original).into(); + whp_sregs[0].0 = WHvX64RegisterDs; + let err = CommonSpecialRegisters::try_from(whp_sregs.as_ref()).unwrap_err(); + assert_eq!( + err, + FromWhpRegisterError::DuplicateRegister(WHvX64RegisterDs.0) + ); + + // Test passing non-sregs register (e.g. RIP) + let original = sample_common_special_registers(); + let mut whp_sregs: [(WHV_REGISTER_NAME, Align16); WHP_SREGS_NAMES_LEN] = + (&original).into(); + whp_sregs[0].0 = WHvX64RegisterRip; + let err = CommonSpecialRegisters::try_from(whp_sregs.as_ref()).unwrap_err(); + assert_eq!( + err, + FromWhpRegisterError::InvalidRegister(WHvX64RegisterRip.0) + ); + } +} diff --git a/src/hyperlight_host/src/hypervisor/regs/standard_regs.rs b/src/hyperlight_host/src/hypervisor/regs/standard_regs.rs new file mode 100644 index 000000000..cc39b3247 --- /dev/null +++ b/src/hyperlight_host/src/hypervisor/regs/standard_regs.rs @@ -0,0 +1,423 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#[cfg(mshv2)] +extern crate mshv_bindings2 as mshv_bindings; +#[cfg(mshv2)] +extern crate mshv_ioctls2 as mshv_ioctls; + +#[cfg(mshv3)] +extern crate mshv_bindings3 as mshv_bindings; +#[cfg(mshv3)] +extern crate mshv_ioctls3 as mshv_ioctls; + +#[cfg(kvm)] +use kvm_bindings::kvm_regs; +#[cfg(mshv)] +use mshv_bindings::StandardRegisters; + +#[derive(Debug, Default, Copy, Clone, PartialEq)] +pub(crate) struct CommonRegisters { + pub rax: u64, + pub rbx: u64, + pub rcx: u64, + pub rdx: u64, + pub rsi: u64, + pub rdi: u64, + pub rsp: u64, + pub rbp: u64, + pub r8: u64, + pub r9: u64, + pub r10: u64, + pub r11: u64, + pub r12: u64, + pub r13: u64, + pub r14: u64, + pub r15: u64, + pub rip: u64, + pub rflags: u64, +} + +// --- KVM --- +#[cfg(kvm)] +impl From<&kvm_regs> for CommonRegisters { + fn from(kvm_regs: &kvm_regs) -> Self { + CommonRegisters { + rax: kvm_regs.rax, + rbx: kvm_regs.rbx, + rcx: kvm_regs.rcx, + rdx: kvm_regs.rdx, + rsi: kvm_regs.rsi, + rdi: kvm_regs.rdi, + rsp: kvm_regs.rsp, + rbp: kvm_regs.rbp, + r8: kvm_regs.r8, + r9: kvm_regs.r9, + r10: kvm_regs.r10, + r11: kvm_regs.r11, + r12: kvm_regs.r12, + r13: kvm_regs.r13, + r14: kvm_regs.r14, + r15: kvm_regs.r15, + rip: kvm_regs.rip, + rflags: kvm_regs.rflags, + } + } +} + +#[cfg(kvm)] +impl From<&CommonRegisters> for kvm_regs { + fn from(regs: &CommonRegisters) -> Self { + kvm_regs { + rax: regs.rax, + rbx: regs.rbx, + rcx: regs.rcx, + rdx: regs.rdx, + rsi: regs.rsi, + rdi: regs.rdi, + rsp: regs.rsp, + rbp: regs.rbp, + r8: regs.r8, + r9: regs.r9, + r10: regs.r10, + r11: regs.r11, + r12: regs.r12, + r13: regs.r13, + r14: regs.r14, + r15: regs.r15, + rip: regs.rip, + rflags: regs.rflags, + } + } +} + +// --- MSHV --- + +#[cfg(mshv)] +impl From<&StandardRegisters> for CommonRegisters { + fn from(mshv_regs: &StandardRegisters) -> Self { + CommonRegisters { + rax: mshv_regs.rax, + rbx: mshv_regs.rbx, + rcx: mshv_regs.rcx, + rdx: mshv_regs.rdx, + rsi: mshv_regs.rsi, + rdi: mshv_regs.rdi, + rsp: mshv_regs.rsp, + rbp: mshv_regs.rbp, + r8: mshv_regs.r8, + r9: mshv_regs.r9, + r10: mshv_regs.r10, + r11: mshv_regs.r11, + r12: mshv_regs.r12, + r13: mshv_regs.r13, + r14: mshv_regs.r14, + r15: mshv_regs.r15, + rip: mshv_regs.rip, + rflags: mshv_regs.rflags, + } + } +} + +#[cfg(mshv)] +impl From<&CommonRegisters> for StandardRegisters { + fn from(regs: &CommonRegisters) -> Self { + StandardRegisters { + rax: regs.rax, + rbx: regs.rbx, + rcx: regs.rcx, + rdx: regs.rdx, + rsi: regs.rsi, + rdi: regs.rdi, + rsp: regs.rsp, + rbp: regs.rbp, + r8: regs.r8, + r9: regs.r9, + r10: regs.r10, + r11: regs.r11, + r12: regs.r12, + r13: regs.r13, + r14: regs.r14, + r15: regs.r15, + rip: regs.rip, + rflags: regs.rflags, + } + } +} + +#[cfg(target_os = "windows")] +use windows::Win32::System::Hypervisor::*; + +#[cfg(target_os = "windows")] +impl From<&CommonRegisters> + for [(WHV_REGISTER_NAME, Align16); WHP_REGS_NAMES_LEN] +{ + fn from(regs: &CommonRegisters) -> Self { + [ + ( + WHvX64RegisterRax, + Align16(WHV_REGISTER_VALUE { Reg64: regs.rax }), + ), + ( + WHvX64RegisterRbx, + Align16(WHV_REGISTER_VALUE { Reg64: regs.rbx }), + ), + ( + WHvX64RegisterRcx, + Align16(WHV_REGISTER_VALUE { Reg64: regs.rcx }), + ), + ( + WHvX64RegisterRdx, + Align16(WHV_REGISTER_VALUE { Reg64: regs.rdx }), + ), + ( + WHvX64RegisterRsi, + Align16(WHV_REGISTER_VALUE { Reg64: regs.rsi }), + ), + ( + WHvX64RegisterRdi, + Align16(WHV_REGISTER_VALUE { Reg64: regs.rdi }), + ), + ( + WHvX64RegisterRsp, + Align16(WHV_REGISTER_VALUE { Reg64: regs.rsp }), + ), + ( + WHvX64RegisterRbp, + Align16(WHV_REGISTER_VALUE { Reg64: regs.rbp }), + ), + ( + WHvX64RegisterR8, + Align16(WHV_REGISTER_VALUE { Reg64: regs.r8 }), + ), + ( + WHvX64RegisterR9, + Align16(WHV_REGISTER_VALUE { Reg64: regs.r9 }), + ), + ( + WHvX64RegisterR10, + Align16(WHV_REGISTER_VALUE { Reg64: regs.r10 }), + ), + ( + WHvX64RegisterR11, + Align16(WHV_REGISTER_VALUE { Reg64: regs.r11 }), + ), + ( + WHvX64RegisterR12, + Align16(WHV_REGISTER_VALUE { Reg64: regs.r12 }), + ), + ( + WHvX64RegisterR13, + Align16(WHV_REGISTER_VALUE { Reg64: regs.r13 }), + ), + ( + WHvX64RegisterR14, + Align16(WHV_REGISTER_VALUE { Reg64: regs.r14 }), + ), + ( + WHvX64RegisterR15, + Align16(WHV_REGISTER_VALUE { Reg64: regs.r15 }), + ), + ( + WHvX64RegisterRip, + Align16(WHV_REGISTER_VALUE { Reg64: regs.rip }), + ), + ( + WHvX64RegisterRflags, + Align16(WHV_REGISTER_VALUE { Reg64: regs.rflags }), + ), + ] + } +} + +#[cfg(target_os = "windows")] +use std::collections::HashSet; + +#[cfg(target_os = "windows")] +use super::{Align16, FromWhpRegisterError}; + +#[cfg(target_os = "windows")] +pub(crate) const WHP_REGS_NAMES_LEN: usize = 18; +#[cfg(target_os = "windows")] +pub(crate) const WHP_REGS_NAMES: [WHV_REGISTER_NAME; WHP_REGS_NAMES_LEN] = [ + WHvX64RegisterRax, + WHvX64RegisterRbx, + WHvX64RegisterRcx, + WHvX64RegisterRdx, + WHvX64RegisterRsi, + WHvX64RegisterRdi, + WHvX64RegisterRsp, + WHvX64RegisterRbp, + WHvX64RegisterR8, + WHvX64RegisterR9, + WHvX64RegisterR10, + WHvX64RegisterR11, + WHvX64RegisterR12, + WHvX64RegisterR13, + WHvX64RegisterR14, + WHvX64RegisterR15, + WHvX64RegisterRip, + WHvX64RegisterRflags, +]; + +#[cfg(target_os = "windows")] +impl TryFrom<&[(WHV_REGISTER_NAME, Align16)]> for CommonRegisters { + type Error = FromWhpRegisterError; + + #[expect( + non_upper_case_globals, + reason = "Windows API has lowercase register names" + )] + fn try_from( + regs: &[(WHV_REGISTER_NAME, Align16)], + ) -> Result { + if regs.len() != WHP_REGS_NAMES_LEN { + return Err(FromWhpRegisterError::InvalidLength(regs.len())); + } + let mut registers = CommonRegisters::default(); + let mut seen_registers = HashSet::new(); + + for &(name, value) in regs { + let name_id = name.0; + + // Check for duplicates + if !seen_registers.insert(name_id) { + return Err(FromWhpRegisterError::DuplicateRegister(name_id)); + } + + unsafe { + match name { + WHvX64RegisterRax => registers.rax = value.0.Reg64, + WHvX64RegisterRbx => registers.rbx = value.0.Reg64, + WHvX64RegisterRcx => registers.rcx = value.0.Reg64, + WHvX64RegisterRdx => registers.rdx = value.0.Reg64, + WHvX64RegisterRsi => registers.rsi = value.0.Reg64, + WHvX64RegisterRdi => registers.rdi = value.0.Reg64, + WHvX64RegisterRsp => registers.rsp = value.0.Reg64, + WHvX64RegisterRbp => registers.rbp = value.0.Reg64, + WHvX64RegisterR8 => registers.r8 = value.0.Reg64, + WHvX64RegisterR9 => registers.r9 = value.0.Reg64, + WHvX64RegisterR10 => registers.r10 = value.0.Reg64, + WHvX64RegisterR11 => registers.r11 = value.0.Reg64, + WHvX64RegisterR12 => registers.r12 = value.0.Reg64, + WHvX64RegisterR13 => registers.r13 = value.0.Reg64, + WHvX64RegisterR14 => registers.r14 = value.0.Reg64, + WHvX64RegisterR15 => registers.r15 = value.0.Reg64, + WHvX64RegisterRip => registers.rip = value.0.Reg64, + WHvX64RegisterRflags => registers.rflags = value.0.Reg64, + _ => { + // Given unexpected register + return Err(FromWhpRegisterError::InvalidRegister(name_id)); + } + } + } + } + + // Set of all expected register names + let expected_registers: HashSet = + WHP_REGS_NAMES.map(|name| name.0).into_iter().collect(); + + // Technically it should not be possible to have any missing registers at this point + // since we are guaranteed to have WHP_REGS_NAMES_LEN (18) non-duplicate registers that have passed the match-arm above, but leaving this here for safety anyway + let missing: HashSet<_> = expected_registers + .difference(&seen_registers) + .cloned() + .collect(); + + if !missing.is_empty() { + return Err(FromWhpRegisterError::MissingRegister(missing)); + } + + Ok(registers) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn common_regs() -> CommonRegisters { + CommonRegisters { + rax: 1, + rbx: 2, + rcx: 3, + rdx: 4, + rsi: 5, + rdi: 6, + rsp: 7, + rbp: 8, + r8: 9, + r9: 10, + r10: 11, + r11: 12, + r12: 13, + r13: 14, + r14: 15, + r15: 16, + rip: 17, + rflags: 18, + } + } + #[cfg(kvm)] + #[test] + fn round_trip_kvm_regs() { + let original = common_regs(); + let kvm_regs: kvm_regs = (&original).into(); + let converted: CommonRegisters = (&kvm_regs).into(); + assert_eq!(original, converted); + } + + #[cfg(mshv)] + #[test] + fn round_trip_mshv_regs() { + let original = common_regs(); + let mshv_regs: StandardRegisters = (&original).into(); + let converted: CommonRegisters = (&mshv_regs).into(); + assert_eq!(original, converted); + } + + #[cfg(target_os = "windows")] + #[test] + fn round_trip_whp_regs() { + let original = common_regs(); + let whp_regs: [(WHV_REGISTER_NAME, Align16); WHP_REGS_NAMES_LEN] = + (&original).into(); + let converted: CommonRegisters = whp_regs.as_ref().try_into().unwrap(); + assert_eq!(original, converted); + + // test for duplicate register error handling + let original = common_regs(); + let mut whp_regs: [(WHV_REGISTER_NAME, Align16); WHP_REGS_NAMES_LEN] = + (&original).into(); + whp_regs[0].0 = WHvX64RegisterRbx; + let err = CommonRegisters::try_from(whp_regs.as_ref()).unwrap_err(); + assert_eq!( + err, + FromWhpRegisterError::DuplicateRegister(WHvX64RegisterRbx.0) + ); + + // test for passing non-standard register (e.g. CR8) + let original = common_regs(); + let mut whp_regs: [(WHV_REGISTER_NAME, Align16); WHP_REGS_NAMES_LEN] = + (&original).into(); + whp_regs[0].0 = WHvX64RegisterCr8; + let err = CommonRegisters::try_from(whp_regs.as_ref()).unwrap_err(); + assert_eq!( + err, + FromWhpRegisterError::InvalidRegister(WHvX64RegisterCr8.0) + ); + } +} diff --git a/src/hyperlight_host/src/hypervisor/windows_hypervisor_platform.rs b/src/hyperlight_host/src/hypervisor/windows_hypervisor_platform.rs index 2212fd433..4f4e82555 100644 --- a/src/hyperlight_host/src/hypervisor/windows_hypervisor_platform.rs +++ b/src/hyperlight_host/src/hypervisor/windows_hypervisor_platform.rs @@ -24,12 +24,16 @@ use windows::Win32::System::LibraryLoader::*; use windows::core::s; use windows_result::HRESULT; +use super::regs::{ + Align16, CommonFpu, CommonRegisters, CommonSpecialRegisters, WHP_FPU_NAMES_LEN, WHP_REGS_NAMES, + WHP_REGS_NAMES_LEN, WHP_SREGS_NAMES, WHP_SREGS_NAMES_LEN, +}; use super::surrogate_process::SurrogateProcess; #[cfg(crashdump)] use crate::HyperlightError; +use crate::hypervisor::regs::WHP_FPU_NAMES; #[cfg(gdb)] use crate::hypervisor::wrappers::WHvDebugRegisters; -use crate::hypervisor::wrappers::{WHvFPURegisters, WHvGeneralRegisters, WHvSpecialRegisters}; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::{Result, new_error}; @@ -303,15 +307,16 @@ impl VMProcessor { part.0 } + /// Helper for setting arbitrary registers. #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] pub(super) fn set_registers( &self, - registers: &[(WHV_REGISTER_NAME, WHV_REGISTER_VALUE)], + registers: &[(WHV_REGISTER_NAME, Align16)], ) -> Result<()> { - let partition_handle = self.get_partition_hdl(); let register_count = registers.len(); - let mut register_names: Vec = vec![]; - let mut register_values: Vec = vec![]; + + let mut register_names = Vec::with_capacity(register_count); + let mut register_values = Vec::with_capacity(register_count); for (key, value) in registers.iter() { register_names.push(*key); @@ -320,188 +325,115 @@ impl VMProcessor { unsafe { WHvSetVirtualProcessorRegisters( - partition_handle, + self.get_partition_hdl(), 0, register_names.as_ptr(), register_count as u32, - register_values.as_ptr(), + register_values.as_ptr() as *const WHV_REGISTER_VALUE, )?; } Ok(()) } - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - pub(super) fn get_sregs(&self) -> Result { - const LEN: usize = 17; - - let names: [WHV_REGISTER_NAME; LEN] = [ - WHvX64RegisterCr0, - WHvX64RegisterCr2, - WHvX64RegisterCr3, - WHvX64RegisterCr4, - WHvX64RegisterCr8, - WHvX64RegisterEfer, - WHvX64RegisterApicBase, - WHvX64RegisterCs, - WHvX64RegisterDs, - WHvX64RegisterEs, - WHvX64RegisterFs, - WHvX64RegisterGs, - WHvX64RegisterSs, - WHvX64RegisterTr, - WHvX64RegisterLdtr, - WHvX64RegisterGdtr, - WHvX64RegisterIdtr, - ]; + pub(super) fn regs(&self) -> Result { + let mut whv_regs_values: [Align16; WHP_REGS_NAMES_LEN] = + unsafe { std::mem::zeroed() }; - let mut out: [WHV_REGISTER_VALUE; LEN] = unsafe { std::mem::zeroed() }; unsafe { WHvGetVirtualProcessorRegisters( self.get_partition_hdl(), 0, - names.as_ptr(), - LEN as u32, - out.as_mut_ptr(), + WHP_REGS_NAMES.as_ptr(), + whv_regs_values.len() as u32, + whv_regs_values.as_mut_ptr() as *mut WHV_REGISTER_VALUE, )?; } - let res: WHvSpecialRegisters = WHvSpecialRegisters { - cr0: out[0], - cr2: out[1], - cr3: out[2], - cr4: out[3], - cr8: out[4], - efer: out[5], - apic_base: out[6], - cs: out[7], - ds: out[8], - es: out[9], - fs: out[10], - gs: out[11], - ss: out[12], - tr: out[13], - ldtr: out[14], - gdtr: out[15], - idtr: out[16], - }; - - Ok(res) + WHP_REGS_NAMES + .into_iter() + .zip(whv_regs_values) + .collect::)>>() + .as_slice() + .try_into() + .map_err(|e| { + new_error!( + "Failed to convert WHP registers to CommonRegisters: {:?}", + e + ) + }) } - // Sets the registers for the VMProcessor to the given general purpose registers. - // If you want to set other registers, use `set_registers` instead. - pub(super) fn set_general_purpose_registers(&self, regs: &WHvGeneralRegisters) -> Result<()> { - const LEN: usize = 18; - - let names: [WHV_REGISTER_NAME; LEN] = [ - WHvX64RegisterRax, - WHvX64RegisterRbx, - WHvX64RegisterRcx, - WHvX64RegisterRdx, - WHvX64RegisterRsi, - WHvX64RegisterRdi, - WHvX64RegisterRsp, - WHvX64RegisterRbp, - WHvX64RegisterR8, - WHvX64RegisterR9, - WHvX64RegisterR10, - WHvX64RegisterR11, - WHvX64RegisterR12, - WHvX64RegisterR13, - WHvX64RegisterR14, - WHvX64RegisterR15, - WHvX64RegisterRip, - WHvX64RegisterRflags, - ]; + pub(super) fn set_regs(&self, regs: &CommonRegisters) -> Result<()> { + let whp_regs: [(WHV_REGISTER_NAME, Align16); WHP_REGS_NAMES_LEN] = + regs.into(); + self.set_registers(&whp_regs)?; + Ok(()) + } - let values: [WHV_REGISTER_VALUE; LEN] = [ - WHV_REGISTER_VALUE { Reg64: regs.rax }, - WHV_REGISTER_VALUE { Reg64: regs.rbx }, - WHV_REGISTER_VALUE { Reg64: regs.rcx }, - WHV_REGISTER_VALUE { Reg64: regs.rdx }, - WHV_REGISTER_VALUE { Reg64: regs.rsi }, - WHV_REGISTER_VALUE { Reg64: regs.rdi }, - WHV_REGISTER_VALUE { Reg64: regs.rsp }, - WHV_REGISTER_VALUE { Reg64: regs.rbp }, - WHV_REGISTER_VALUE { Reg64: regs.r8 }, - WHV_REGISTER_VALUE { Reg64: regs.r9 }, - WHV_REGISTER_VALUE { Reg64: regs.r10 }, - WHV_REGISTER_VALUE { Reg64: regs.r11 }, - WHV_REGISTER_VALUE { Reg64: regs.r12 }, - WHV_REGISTER_VALUE { Reg64: regs.r13 }, - WHV_REGISTER_VALUE { Reg64: regs.r14 }, - WHV_REGISTER_VALUE { Reg64: regs.r15 }, - WHV_REGISTER_VALUE { Reg64: regs.rip }, - WHV_REGISTER_VALUE { Reg64: regs.rflags }, - ]; + pub(super) fn sregs(&self) -> Result { + let mut whp_sregs_values: [Align16; WHP_SREGS_NAMES_LEN] = + unsafe { std::mem::zeroed() }; unsafe { - WHvSetVirtualProcessorRegisters( + WHvGetVirtualProcessorRegisters( self.get_partition_hdl(), 0, - names.as_ptr(), - LEN as u32, - values.as_ptr(), + WHP_SREGS_NAMES.as_ptr(), + whp_sregs_values.len() as u32, + whp_sregs_values.as_mut_ptr() as *mut WHV_REGISTER_VALUE, )?; } + + WHP_SREGS_NAMES + .into_iter() + .zip(whp_sregs_values) + .collect::)>>() + .as_slice() + .try_into() + .map_err(|e| { + new_error!( + "Failed to convert WHP registers to CommonSpecialRegisters: {:?}", + e + ) + }) + } + + pub(super) fn set_sregs(&self, sregs: &CommonSpecialRegisters) -> Result<()> { + let whp_regs: [(WHV_REGISTER_NAME, Align16); WHP_SREGS_NAMES_LEN] = + sregs.into(); + self.set_registers(&whp_regs)?; Ok(()) } - pub(super) fn get_regs(&self) -> Result { - const LEN: usize = 18; + pub(super) fn fpu(&self) -> Result { + let mut whp_fpu_values: [Align16; WHP_FPU_NAMES_LEN] = + unsafe { std::mem::zeroed() }; - let names: [WHV_REGISTER_NAME; LEN] = [ - WHvX64RegisterRax, - WHvX64RegisterRbx, - WHvX64RegisterRcx, - WHvX64RegisterRdx, - WHvX64RegisterRsi, - WHvX64RegisterRdi, - WHvX64RegisterRsp, - WHvX64RegisterRbp, - WHvX64RegisterR8, - WHvX64RegisterR9, - WHvX64RegisterR10, - WHvX64RegisterR11, - WHvX64RegisterR12, - WHvX64RegisterR13, - WHvX64RegisterR14, - WHvX64RegisterR15, - WHvX64RegisterRip, - WHvX64RegisterRflags, - ]; - - let mut out: [WHV_REGISTER_VALUE; LEN] = unsafe { std::mem::zeroed() }; unsafe { WHvGetVirtualProcessorRegisters( self.get_partition_hdl(), 0, - names.as_ptr(), - LEN as u32, - out.as_mut_ptr(), + WHP_FPU_NAMES.as_ptr(), + whp_fpu_values.len() as u32, + whp_fpu_values.as_mut_ptr() as *mut WHV_REGISTER_VALUE, )?; - Ok(WHvGeneralRegisters { - rax: out[0].Reg64, - rbx: out[1].Reg64, - rcx: out[2].Reg64, - rdx: out[3].Reg64, - rsi: out[4].Reg64, - rdi: out[5].Reg64, - rsp: out[6].Reg64, - rbp: out[7].Reg64, - r8: out[8].Reg64, - r9: out[9].Reg64, - r10: out[10].Reg64, - r11: out[11].Reg64, - r12: out[12].Reg64, - r13: out[13].Reg64, - r14: out[14].Reg64, - r15: out[15].Reg64, - rip: out[16].Reg64, - rflags: out[17].Reg64, - }) } + + WHP_FPU_NAMES + .into_iter() + .zip(whp_fpu_values) + .collect::)>>() + .as_slice() + .try_into() + .map_err(|e| new_error!("Failed to convert WHP registers to CommonFpu: {:?}", e)) + } + + pub(super) fn set_fpu(&self, fpu: &CommonFpu) -> Result<()> { + let whp_fpu: [(WHV_REGISTER_NAME, Align16); WHP_FPU_NAMES_LEN] = + fpu.into(); + self.set_registers(&whp_fpu)?; + Ok(()) } #[cfg(crashdump)] @@ -560,12 +492,30 @@ impl VMProcessor { #[cfg(gdb)] pub(super) fn set_debug_regs(&self, regs: &WHvDebugRegisters) -> Result<()> { let registers = vec![ - (WHvX64RegisterDr0, WHV_REGISTER_VALUE { Reg64: regs.dr0 }), - (WHvX64RegisterDr1, WHV_REGISTER_VALUE { Reg64: regs.dr1 }), - (WHvX64RegisterDr2, WHV_REGISTER_VALUE { Reg64: regs.dr2 }), - (WHvX64RegisterDr3, WHV_REGISTER_VALUE { Reg64: regs.dr3 }), - (WHvX64RegisterDr6, WHV_REGISTER_VALUE { Reg64: regs.dr6 }), - (WHvX64RegisterDr7, WHV_REGISTER_VALUE { Reg64: regs.dr7 }), + ( + WHvX64RegisterDr0, + Align16(WHV_REGISTER_VALUE { Reg64: regs.dr0 }), + ), + ( + WHvX64RegisterDr1, + Align16(WHV_REGISTER_VALUE { Reg64: regs.dr1 }), + ), + ( + WHvX64RegisterDr2, + Align16(WHV_REGISTER_VALUE { Reg64: regs.dr2 }), + ), + ( + WHvX64RegisterDr3, + Align16(WHV_REGISTER_VALUE { Reg64: regs.dr3 }), + ), + ( + WHvX64RegisterDr6, + Align16(WHV_REGISTER_VALUE { Reg64: regs.dr6 }), + ), + ( + WHvX64RegisterDr7, + Align16(WHV_REGISTER_VALUE { Reg64: regs.dr7 }), + ), ]; self.set_registers(®isters) @@ -584,233 +534,22 @@ impl VMProcessor { WHvX64RegisterDr7, ]; - let mut out: [WHV_REGISTER_VALUE; LEN] = unsafe { std::mem::zeroed() }; + let mut out: [Align16; LEN] = unsafe { std::mem::zeroed() }; unsafe { WHvGetVirtualProcessorRegisters( self.get_partition_hdl(), 0, names.as_ptr(), LEN as u32, - out.as_mut_ptr(), + out.as_mut_ptr() as *mut WHV_REGISTER_VALUE, )?; Ok(WHvDebugRegisters { - dr0: out[0].Reg64, - dr1: out[1].Reg64, - dr2: out[2].Reg64, - dr3: out[3].Reg64, - dr6: out[4].Reg64, - dr7: out[5].Reg64, - }) - } - } - - pub(super) fn set_fpu(&self, regs: &WHvFPURegisters) -> Result<()> { - const LEN: usize = 26; - - let names: [WHV_REGISTER_NAME; LEN] = [ - WHvX64RegisterXmm0, - WHvX64RegisterXmm1, - WHvX64RegisterXmm2, - WHvX64RegisterXmm3, - WHvX64RegisterXmm4, - WHvX64RegisterXmm5, - WHvX64RegisterXmm6, - WHvX64RegisterXmm7, - WHvX64RegisterXmm8, - WHvX64RegisterXmm9, - WHvX64RegisterXmm10, - WHvX64RegisterXmm11, - WHvX64RegisterXmm12, - WHvX64RegisterXmm13, - WHvX64RegisterXmm14, - WHvX64RegisterXmm15, - WHvX64RegisterFpMmx0, - WHvX64RegisterFpMmx1, - WHvX64RegisterFpMmx2, - WHvX64RegisterFpMmx3, - WHvX64RegisterFpMmx4, - WHvX64RegisterFpMmx5, - WHvX64RegisterFpMmx6, - WHvX64RegisterFpMmx7, - WHvX64RegisterFpControlStatus, - WHvX64RegisterXmmControlStatus, - ]; - - let xmm_regs = [ - regs.xmm0, regs.xmm1, regs.xmm2, regs.xmm3, regs.xmm4, regs.xmm5, regs.xmm6, regs.xmm7, - regs.xmm8, regs.xmm9, regs.xmm10, regs.xmm11, regs.xmm12, regs.xmm13, regs.xmm14, - regs.xmm15, - ]; - - let mut values: Vec = xmm_regs - .iter() - .map(|®| WHV_REGISTER_VALUE { - Fp: WHV_X64_FP_REGISTER { - AsUINT128: WHV_UINT128 { - Anonymous: WHV_UINT128_0 { - Low64: reg as u64, - High64: (reg >> 64) as u64, - }, - }, - }, - }) - .collect(); - - values.extend_from_slice(&[ - WHV_REGISTER_VALUE { Reg64: regs.mmx0 }, - WHV_REGISTER_VALUE { Reg64: regs.mmx1 }, - WHV_REGISTER_VALUE { Reg64: regs.mmx2 }, - WHV_REGISTER_VALUE { Reg64: regs.mmx3 }, - WHV_REGISTER_VALUE { Reg64: regs.mmx4 }, - WHV_REGISTER_VALUE { Reg64: regs.mmx5 }, - WHV_REGISTER_VALUE { Reg64: regs.mmx6 }, - WHV_REGISTER_VALUE { Reg64: regs.mmx7 }, - WHV_REGISTER_VALUE { - FpControlStatus: WHV_X64_FP_CONTROL_STATUS_REGISTER { - Anonymous: WHV_X64_FP_CONTROL_STATUS_REGISTER_0 { - FpControl: regs.fp_control_word, - FpTag: regs.fp_tag_word, - ..Default::default() - }, - }, - }, - WHV_REGISTER_VALUE { - XmmControlStatus: WHV_X64_XMM_CONTROL_STATUS_REGISTER { - Anonymous: WHV_X64_XMM_CONTROL_STATUS_REGISTER_0 { - XmmStatusControl: regs.mxcsr, - ..Default::default() - }, - }, - }, - ]); - - unsafe { - WHvSetVirtualProcessorRegisters( - self.get_partition_hdl(), - 0, - names.as_ptr(), - LEN as u32, - values.as_ptr(), - )?; - } - Ok(()) - } - - #[cfg(gdb)] - pub(super) fn get_fpu(&self) -> Result { - use windows::Win32::System::Hypervisor::*; - - const LEN: usize = 26; - let names: [WHV_REGISTER_NAME; LEN] = [ - WHvX64RegisterXmm0, - WHvX64RegisterXmm1, - WHvX64RegisterXmm2, - WHvX64RegisterXmm3, - WHvX64RegisterXmm4, - WHvX64RegisterXmm5, - WHvX64RegisterXmm6, - WHvX64RegisterXmm7, - WHvX64RegisterXmm8, - WHvX64RegisterXmm9, - WHvX64RegisterXmm10, - WHvX64RegisterXmm11, - WHvX64RegisterXmm12, - WHvX64RegisterXmm13, - WHvX64RegisterXmm14, - WHvX64RegisterXmm15, - WHvX64RegisterFpMmx0, - WHvX64RegisterFpMmx1, - WHvX64RegisterFpMmx2, - WHvX64RegisterFpMmx3, - WHvX64RegisterFpMmx4, - WHvX64RegisterFpMmx5, - WHvX64RegisterFpMmx6, - WHvX64RegisterFpMmx7, - WHvX64RegisterFpControlStatus, - WHvX64RegisterXmmControlStatus, - ]; - - let mut out: [WHV_REGISTER_VALUE; LEN] = unsafe { std::mem::zeroed() }; - unsafe { - WHvGetVirtualProcessorRegisters( - self.get_partition_hdl(), - 0, - names.as_ptr(), - LEN as u32, - out.as_mut_ptr(), - )?; - - // Helper to read a WHV_UINT128 -> u128 - fn u128_from_whv(fp: WHV_REGISTER_VALUE) -> u128 { - unsafe { - let low = fp.Fp.AsUINT128.Anonymous.Low64 as u128; - let high = fp.Fp.AsUINT128.Anonymous.High64 as u128; - (high << 64) | low - } - } - - let xmm = [ - u128_from_whv(out[0]), - u128_from_whv(out[1]), - u128_from_whv(out[2]), - u128_from_whv(out[3]), - u128_from_whv(out[4]), - u128_from_whv(out[5]), - u128_from_whv(out[6]), - u128_from_whv(out[7]), - u128_from_whv(out[8]), - u128_from_whv(out[9]), - u128_from_whv(out[10]), - u128_from_whv(out[11]), - u128_from_whv(out[12]), - u128_from_whv(out[13]), - u128_from_whv(out[14]), - u128_from_whv(out[15]), - ]; - - let mmx = [ - out[16].Reg64, - out[17].Reg64, - out[18].Reg64, - out[19].Reg64, - out[20].Reg64, - out[21].Reg64, - out[22].Reg64, - out[23].Reg64, - ]; - - let fp_control_word = out[24].FpControlStatus.Anonymous.FpControl; - let fp_tag_word = out[24].FpControlStatus.Anonymous.FpTag; - let mxcsr = out[25].XmmControlStatus.Anonymous.XmmStatusControl; - - Ok(WHvFPURegisters { - xmm0: xmm[0], - xmm1: xmm[1], - xmm2: xmm[2], - xmm3: xmm[3], - xmm4: xmm[4], - xmm5: xmm[5], - xmm6: xmm[6], - xmm7: xmm[7], - xmm8: xmm[8], - xmm9: xmm[9], - xmm10: xmm[10], - xmm11: xmm[11], - xmm12: xmm[12], - xmm13: xmm[13], - xmm14: xmm[14], - xmm15: xmm[15], - mmx0: mmx[0], - mmx1: mmx[1], - mmx2: mmx[2], - mmx3: mmx[3], - mmx4: mmx[4], - mmx5: mmx[5], - mmx6: mmx[6], - mmx7: mmx[7], - fp_control_word, - fp_tag_word, - mxcsr, + dr0: out[0].0.Reg64, + dr1: out[1].0.Reg64, + dr2: out[2].0.Reg64, + dr3: out[3].0.Reg64, + dr6: out[4].0.Reg64, + dr7: out[5].0.Reg64, }) } } diff --git a/src/hyperlight_host/src/hypervisor/wrappers.rs b/src/hyperlight_host/src/hypervisor/wrappers.rs index 4a2a1ff8b..135ae2b82 100644 --- a/src/hyperlight_host/src/hypervisor/wrappers.rs +++ b/src/hyperlight_host/src/hypervisor/wrappers.rs @@ -18,7 +18,6 @@ use std::ffi::CString; use tracing::{Span, instrument}; use windows::Win32::Foundation::{HANDLE, HMODULE}; -use windows::Win32::System::Hypervisor::WHV_REGISTER_VALUE; use windows::core::PSTR; use crate::{HyperlightError, Result}; @@ -57,29 +56,6 @@ impl From<&PSTRWrapper> for PSTR { } } -// only used on windows. mshv and kvm already has this implemented -#[derive(Debug, Default, Copy, Clone, PartialEq)] -pub(super) struct WHvGeneralRegisters { - pub rax: u64, - pub rbx: u64, - pub rcx: u64, - pub rdx: u64, - pub rsi: u64, - pub rdi: u64, - pub rsp: u64, - pub rbp: u64, - pub r8: u64, - pub r9: u64, - pub r10: u64, - pub r11: u64, - pub r12: u64, - pub r13: u64, - pub r14: u64, - pub r15: u64, - pub rip: u64, - pub rflags: u64, -} - /// only used on widos for handling debug registers with the VMProcessor #[cfg(gdb)] #[derive(Debug, Default, Copy, Clone, PartialEq)] @@ -92,61 +68,6 @@ pub(super) struct WHvDebugRegisters { pub dr7: u64, } -#[derive(Debug, Default, Copy, Clone, PartialEq)] -pub(super) struct WHvFPURegisters { - pub xmm0: u128, - pub xmm1: u128, - pub xmm2: u128, - pub xmm3: u128, - pub xmm4: u128, - pub xmm5: u128, - pub xmm6: u128, - pub xmm7: u128, - pub xmm8: u128, - pub xmm9: u128, - pub xmm10: u128, - pub xmm11: u128, - pub xmm12: u128, - pub xmm13: u128, - pub xmm14: u128, - pub xmm15: u128, - - pub mmx0: u64, - pub mmx1: u64, - pub mmx2: u64, - pub mmx3: u64, - pub mmx4: u64, - pub mmx5: u64, - pub mmx6: u64, - pub mmx7: u64, - - pub fp_control_word: u16, - pub fp_tag_word: u8, - - pub mxcsr: u32, -} - -#[derive(Default, Copy, Clone)] -pub(super) struct WHvSpecialRegisters { - pub cr0: WHV_REGISTER_VALUE, - pub cr2: WHV_REGISTER_VALUE, - pub cr3: WHV_REGISTER_VALUE, - pub cr4: WHV_REGISTER_VALUE, - pub cr8: WHV_REGISTER_VALUE, - pub efer: WHV_REGISTER_VALUE, - pub apic_base: WHV_REGISTER_VALUE, - pub cs: WHV_REGISTER_VALUE, - pub ds: WHV_REGISTER_VALUE, - pub es: WHV_REGISTER_VALUE, - pub fs: WHV_REGISTER_VALUE, - pub gs: WHV_REGISTER_VALUE, - pub ss: WHV_REGISTER_VALUE, - pub tr: WHV_REGISTER_VALUE, - pub ldtr: WHV_REGISTER_VALUE, - pub gdtr: WHV_REGISTER_VALUE, - pub idtr: WHV_REGISTER_VALUE, -} - /// Wrapper for HANDLE, required since HANDLE is no longer Send. #[derive(Debug, Copy, Clone)] pub struct HandleWrapper(HANDLE); diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index 6e59c5367..038d9d780 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -170,13 +170,10 @@ fn unwind( .unwind_cache .try_lock() .map_err(|e| new_error!("could not lock unwinder cache {}\n", e))?; + let regs = hv.regs()?; let iter = trace_info.unwinder.iter_frames( - hv.read_trace_reg(crate::hypervisor::TraceRegister::RIP)?, - framehop::x86_64::UnwindRegsX86_64::new( - hv.read_trace_reg(crate::hypervisor::TraceRegister::RIP)?, - hv.read_trace_reg(crate::hypervisor::TraceRegister::RSP)?, - hv.read_trace_reg(crate::hypervisor::TraceRegister::RBP)?, - ), + regs.rip, + framehop::x86_64::UnwindRegsX86_64::new(regs.rip, regs.rsp, regs.rbp), &mut *cache, &mut read_stack, ); @@ -315,13 +312,15 @@ pub(crate) fn handle_outb( } #[cfg(feature = "mem_profile")] OutBAction::TraceMemoryAlloc => { + use crate::hypervisor::regs::CommonRegisters; + let Ok(stack) = unwind(_hv, mem_mgr, _hv.trace_info_as_ref()) else { return Ok(()); }; - let Ok(amt) = _hv.read_trace_reg(crate::hypervisor::TraceRegister::RAX) else { - return Ok(()); - }; - let Ok(ptr) = _hv.read_trace_reg(crate::hypervisor::TraceRegister::RCX) else { + let Ok(CommonRegisters { + rax: amt, rcx: ptr, .. + }) = _hv.regs() + else { return Ok(()); }; record_trace_frame(_hv.trace_info_as_ref(), 2u64, |f| { @@ -332,23 +331,27 @@ pub(crate) fn handle_outb( } #[cfg(feature = "mem_profile")] OutBAction::TraceMemoryFree => { + use crate::hypervisor::regs::CommonRegisters; + let Ok(stack) = unwind(_hv, mem_mgr, _hv.trace_info_as_ref()) else { return Ok(()); }; - let Ok(ptr) = _hv.read_trace_reg(crate::hypervisor::TraceRegister::RCX) else { + let Ok(CommonRegisters { rcx, .. }) = _hv.regs() else { return Ok(()); }; record_trace_frame(_hv.trace_info_as_ref(), 3u64, |f| { - let _ = f.write_all(&ptr.to_ne_bytes()); + let _ = f.write_all(&rcx.to_ne_bytes()); write_stack(f, &stack); }) } #[cfg(feature = "trace_guest")] OutBAction::TraceRecord => { - let Ok(len) = _hv.read_trace_reg(crate::hypervisor::TraceRegister::RAX) else { - return Ok(()); - }; - let Ok(ptr) = _hv.read_trace_reg(crate::hypervisor::TraceRegister::RCX) else { + use crate::hypervisor::regs::CommonRegisters; + + let Ok(CommonRegisters { + rax: len, rcx: ptr, .. + }) = _hv.regs() + else { return Ok(()); }; let mut buffer = vec![0u8; len as usize * std::mem::size_of::()]; diff --git a/typos.toml b/typos.toml index c05ec808d..07ffa9dee 100644 --- a/typos.toml +++ b/typos.toml @@ -8,3 +8,4 @@ extend-exclude = ["**/*.patch", "src/hyperlight_guest_bin/third_party/**/*", "NO # typ is used for field name as type is a reserved keyword typ="typ" mmaped="mmapped" +fpr="fpr" From 2eb9210b709ef43ff8df768a7f0c1f7ae8e23993 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 04:08:55 +0000 Subject: [PATCH 242/271] Bump goblin from 0.10.2 to 0.10.3 (#960) Bumps [goblin](https://github.com/m4b/goblin) from 0.10.2 to 0.10.3. - [Changelog](https://github.com/m4b/goblin/blob/master/CHANGELOG.md) - [Commits](https://github.com/m4b/goblin/commits) --- updated-dependencies: - dependency-name: goblin dependency-version: 0.10.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e312fab4c..aa01a1041 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1186,9 +1186,9 @@ dependencies = [ [[package]] name = "goblin" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be320f077239a0361c20d608b4768c62a1b77aa4946dd76395aa4cd502cba7d" +checksum = "51876e3748c4a347fe65b906f2b1ae46a1e55a497b22c94c1f4f2c469ff7673a" dependencies = [ "log", "plain", From c6076b510c68abe176a74fd6fbe57f109a32e366 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 04:15:35 +0000 Subject: [PATCH 243/271] Bump syn from 2.0.106 to 2.0.107 (#961) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.106 to 2.0.107. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.106...2.0.107) --- updated-dependencies: - dependency-name: syn dependency-version: 2.0.107 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- src/hyperlight_guest_tracing_macro/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa01a1041..31b188e63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3246,9 +3246,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.106" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index af05ad5e5..239a7ba6d 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -19,7 +19,7 @@ proc-macro = true wasmparser = { version = "0.240.0" } quote = { version = "1.0.41" } proc-macro2 = { version = "1.0.101" } -syn = { version = "2.0.106" } +syn = { version = "2.0.107" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.37" } hyperlight-component-util = { workspace = true } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index 301ce0f3f..9618a8d45 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -18,7 +18,7 @@ name = "hyperlight_component_util" wasmparser = { version = "0.240.0" } quote = { version = "1.0.41" } proc-macro2 = { version = "1.0.101" } -syn = { version = "2.0.106" } +syn = { version = "2.0.107" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.37" } log = { version = "0.4" } \ No newline at end of file diff --git a/src/hyperlight_guest_tracing_macro/Cargo.toml b/src/hyperlight_guest_tracing_macro/Cargo.toml index 7688232a4..88d06022d 100644 --- a/src/hyperlight_guest_tracing_macro/Cargo.toml +++ b/src/hyperlight_guest_tracing_macro/Cargo.toml @@ -12,7 +12,7 @@ description = """Provides the tracing macros for the hyperlight guest, enabling [dependencies] proc-macro2 = "1.0" quote = "1.0.41" -syn = { version = "2.0.106", features = ["full"] } +syn = { version = "2.0.107", features = ["full"] } [features] default = [] From 5380f1e4f2cc2a61da8505e98004002f0b941081 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 04:18:00 +0000 Subject: [PATCH 244/271] Bump rust-embed from 8.7.2 to 8.8.0 (#962) Bumps rust-embed from 8.7.2 to 8.8.0. --- updated-dependencies: - dependency-name: rust-embed dependency-version: 8.8.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 12 ++++++------ src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 31b188e63..6e4b88be2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2862,9 +2862,9 @@ dependencies = [ [[package]] name = "rust-embed" -version = "8.7.2" +version = "8.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "025908b8682a26ba8d12f6f2d66b987584a4a87bc024abc5bbc12553a8cd178a" +checksum = "fb44e1917075637ee8c7bcb865cf8830e3a92b5b1189e44e3a0ab5a0d5be314b" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -2873,9 +2873,9 @@ dependencies = [ [[package]] name = "rust-embed-impl" -version = "8.7.2" +version = "8.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6065f1a4392b71819ec1ea1df1120673418bf386f50de1d6f54204d836d4349c" +checksum = "382499b49db77a7c19abd2a574f85ada7e9dbe125d5d1160fa5cad7c4cf71fc9" dependencies = [ "proc-macro2", "quote", @@ -2887,9 +2887,9 @@ dependencies = [ [[package]] name = "rust-embed-utils" -version = "8.7.2" +version = "8.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6cc0c81648b20b70c491ff8cce00c1c3b223bb8ed2b5d41f0e54c6c4c0a3594" +checksum = "21fcbee55c2458836bcdbfffb6ec9ba74bbc23ca7aa6816015a3dd2c4d8fc185" dependencies = [ "globset", "sha2", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 0b003b20d..5d64ff1df 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -67,7 +67,7 @@ windows = { version = "0.62", features = [ ] } windows-sys = { version = "0.61", features = ["Win32"] } windows-result = "0.4" -rust-embed = { version = "8.7.2", features = ["debug-embed", "include-exclude", "interpolate-folder-path"] } +rust-embed = { version = "8.8.0", features = ["debug-embed", "include-exclude", "interpolate-folder-path"] } sha256 = "1.6.0" windows-version = "0.1" lazy_static = "1.4.0" From 42b4811d4a7f1c363590932db88c2d5d265bff39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 09:48:27 +0000 Subject: [PATCH 245/271] Bump opentelemetry-otlp from 0.30.0 to 0.31.0 (#913) --- Cargo.lock | 54 +++++++++++++++++++++------------- src/hyperlight_host/Cargo.toml | 8 ++--- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e4b88be2..ace2f64d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2165,9 +2165,9 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "opentelemetry" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf416e4cb72756655126f7dd7bb0af49c674f4c1b9903e80c009e0c37e552e6" +checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" dependencies = [ "futures-core", "futures-sink", @@ -2179,9 +2179,9 @@ dependencies = [ [[package]] name = "opentelemetry-http" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f6639e842a97dbea8886e3439710ae463120091e2e064518ba8e716e6ac36d" +checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" dependencies = [ "async-trait", "bytes", @@ -2192,9 +2192,9 @@ dependencies = [ [[package]] name = "opentelemetry-otlp" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbee664a43e07615731afc539ca60c6d9f1a9425e25ca09c57bc36c87c55852b" +checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf" dependencies = [ "http", "opentelemetry", @@ -2208,14 +2208,15 @@ dependencies = [ [[package]] name = "opentelemetry-proto" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e046fd7660710fe5a05e8748e70d9058dc15c94ba914e7c4faa7c728f0e8ddc" +checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" dependencies = [ "opentelemetry", "opentelemetry_sdk", "prost", "tonic", + "tonic-prost", ] [[package]] @@ -2226,9 +2227,9 @@ checksum = "e62e29dfe041afb8ed2a6c9737ab57db4907285d999ef8ad3a59092a36bdc846" [[package]] name = "opentelemetry_sdk" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f644aa9e5e31d11896e024305d7e3c98a88884d9f8919dbf37a9991bc47a4b" +checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" dependencies = [ "futures-channel", "futures-executor", @@ -2236,7 +2237,6 @@ dependencies = [ "opentelemetry", "percent-encoding", "rand", - "serde_json", "thiserror 2.0.17", "tokio", "tokio-stream", @@ -2634,9 +2634,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" dependencies = [ "bytes", "prost-derive", @@ -2644,9 +2644,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" dependencies = [ "anyhow", "itertools 0.14.0", @@ -3467,9 +3467,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "tonic" -version = "0.13.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e581ba15a835f4d9ea06c55ab1bd4dce26fc53752c69a04aac00703bfb49ba9" +checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" dependencies = [ "async-trait", "base64", @@ -3479,13 +3479,24 @@ dependencies = [ "http-body-util", "percent-encoding", "pin-project", - "prost", + "sync_wrapper", "tokio-stream", "tower-layer", "tower-service", "tracing", ] +[[package]] +name = "tonic-prost" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" +dependencies = [ + "bytes", + "prost", + "tonic", +] + [[package]] name = "tower" version = "0.5.2" @@ -3612,15 +3623,16 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddcf5959f39507d0d04d6413119c04f33b623f4f951ebcbdddddfad2d0623a9c" +checksum = "1e6e5658463dd88089aba75c7791e1d3120633b1bfde22478b28f625a9bb1b8e" dependencies = [ "js-sys", - "once_cell", "opentelemetry", "opentelemetry_sdk", + "rustversion", "smallvec", + "thiserror 2.0.17", "tracing", "tracing-core", "tracing-log", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 5d64ff1df..f54d74f40 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -96,11 +96,11 @@ env_logger = "0.11.8" tracing-forest = { version = "0.2.0", features = ["uuid", "chrono", "smallvec", "serde", "env-filter"] } tracing = "0.1.41" tracing-subscriber = {version = "0.3.20", features = ["std", "env-filter"]} -tracing-opentelemetry = "0.31.0" -opentelemetry = "0.30.0" -opentelemetry-otlp = { version = "0.30.0", default-features = false, features = ["http-proto", "reqwest-blocking-client"] } +tracing-opentelemetry = "0.32.0" +opentelemetry = "0.31.0" +opentelemetry-otlp = { version = "0.31.0", default-features = false, features = ["http-proto", "reqwest-blocking-client"] } opentelemetry-semantic-conventions = "0.31" -opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio"] } +opentelemetry_sdk = { version = "0.31.0", features = ["rt-tokio"] } tokio = { version = "1.48.0", features = ["full"] } criterion = "0.7.0" tracing-chrome = "0.7.2" From ff7aecc8390308a791028e19d23a8c466e26a1f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 10:14:37 +0000 Subject: [PATCH 246/271] Bump bitflags from 2.9.4 to 2.10.0 (#963) Bumps [bitflags](https://github.com/bitflags/bitflags) from 2.9.4 to 2.10.0. - [Release notes](https://github.com/bitflags/bitflags/releases) - [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md) - [Commits](https://github.com/bitflags/bitflags/compare/2.9.4...2.10.0) --- updated-dependencies: - dependency-name: bitflags dependency-version: 2.10.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 40 +++++++++++++++++----------------- src/hyperlight_host/Cargo.toml | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ace2f64d9..94cdc8432 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -178,7 +178,7 @@ version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cexpr", "clang-sys", "itertools 0.13.0", @@ -215,9 +215,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "blake3" @@ -294,7 +294,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1158f326d7b755a9ae2b36c5b5391400e3431f3b77418cedb6d7130126628f10" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cairo-sys-rs", "glib", "libc", @@ -491,7 +491,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation", "core-graphics-types", "foreign-types", @@ -504,7 +504,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation", "libc", ] @@ -821,7 +821,7 @@ version = "25.9.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09b6620799e7340ebd9968d2e0708eb82cf1971e9a16821e2091b6d6e475eed5" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "rustc_version", ] @@ -992,7 +992,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72742d2b395902caf8a5d520d0dd3334ba6d1138938429200e58d5174e275f3f" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cfg-if", "log", "managed", @@ -1103,7 +1103,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "libc", "libgit2-sys", "log", @@ -1116,7 +1116,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60bdc26493257b5794ba9301f7cbaf7ab0d69a570bfbefa4d7d360e781cb5205" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "futures-channel", "futures-core", "futures-executor", @@ -1411,7 +1411,7 @@ name = "hyperlight-host" version = "0.10.0" dependencies = [ "anyhow", - "bitflags 2.9.4", + "bitflags 2.10.0", "blake3", "built", "cfg-if", @@ -1766,7 +1766,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "333f77a20344a448f3f70664918135fddeb804e938f28a99d685bd92926e0b19" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "kvm-bindings", "libc", "vmm-sys-util", @@ -1833,7 +1833,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "libc", ] @@ -2353,7 +2353,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97f6fccfd2d9d2df765ca23ff85fe5cc437fb0e6d3e164e4d3cbe09d14780c93" dependencies = [ "arrayvec", - "bitflags 2.9.4", + "bitflags 2.10.0", "thiserror 2.0.17", "zerocopy 0.8.26", "zerocopy-derive 0.8.26", @@ -2620,7 +2620,7 @@ checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.9.4", + "bitflags 2.10.0", "lazy_static", "num-traits", "rand", @@ -2754,7 +2754,7 @@ version = "11.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", ] [[package]] @@ -2783,7 +2783,7 @@ version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", ] [[package]] @@ -2923,7 +2923,7 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys", @@ -3518,7 +3518,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "bytes", "futures-util", "http", @@ -3989,7 +3989,7 @@ version = "0.240.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b722dcf61e0ea47440b53ff83ccb5df8efec57a69d150e4f24882e4eba7e24a4" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "hashbrown", "indexmap", "semver", diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index f54d74f40..1210abd15 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -33,7 +33,7 @@ fallible-iterator = { version = "0.3.0", optional = true } blake3 = "1.8.2" page_size = "0.6.0" termcolor = "1.2.0" -bitflags = "2.9.4" +bitflags = "2.10.0" log = "0.4.28" tracing = { version = "0.1.41", features = ["log"] } tracing-log = "0.2.0" From 7a266216c658331d9ff6f7315ba8c3f6a4926ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Mon, 20 Oct 2025 13:33:25 +0300 Subject: [PATCH 247/271] Add support for mmaped memory in crashdumps and guest debugging (#943) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [dbg] Add debug support for memory mapped regions in Hypervisors Signed-off-by: Doru Blânzeanu * [crashdump] Fix mmaped memory not included in dump Signed-off-by: Doru Blânzeanu --------- Signed-off-by: Doru Blânzeanu --- .../src/hypervisor/crashdump.rs | 14 +- src/hyperlight_host/src/hypervisor/gdb/mod.rs | 368 ++++++++++++++++-- .../src/hypervisor/hyperv_linux.rs | 50 ++- .../src/hypervisor/hyperv_windows.rs | 39 +- src/hyperlight_host/src/hypervisor/kvm.rs | 54 ++- src/hyperlight_host/src/hypervisor/mod.rs | 2 +- src/tests/rust_guests/dummyguest/Cargo.lock | 4 +- src/tests/rust_guests/simpleguest/Cargo.lock | 4 +- src/tests/rust_guests/witguest/Cargo.lock | 4 +- 9 files changed, 418 insertions(+), 121 deletions(-) diff --git a/src/hyperlight_host/src/hypervisor/crashdump.rs b/src/hyperlight_host/src/hypervisor/crashdump.rs index ae865ef56..86dce75ff 100644 --- a/src/hyperlight_host/src/hypervisor/crashdump.rs +++ b/src/hyperlight_host/src/hypervisor/crashdump.rs @@ -43,8 +43,8 @@ const CORE_DUMP_PAGE_SIZE: usize = 0x1000; /// Structure to hold the crash dump context /// This structure contains the information needed to create a core dump #[derive(Debug)] -pub(crate) struct CrashDumpContext<'a> { - regions: &'a [MemoryRegion], +pub(crate) struct CrashDumpContext { + regions: Vec, regs: [u64; 27], xsave: Vec, entry: u64, @@ -52,9 +52,9 @@ pub(crate) struct CrashDumpContext<'a> { filename: Option, } -impl<'a> CrashDumpContext<'a> { +impl CrashDumpContext { pub(crate) fn new( - regions: &'a [MemoryRegion], + regions: Vec, regs: [u64; 27], xsave: Vec, entry: u64, @@ -208,7 +208,7 @@ struct GuestMemReader { impl GuestMemReader { fn new(ctx: &CrashDumpContext) -> Self { Self { - regions: ctx.regions.to_vec(), + regions: ctx.regions.clone(), } } } @@ -440,7 +440,7 @@ mod test { fn test_crashdump_write_fails_when_no_regions() { // Create a dummy context let ctx = CrashDumpContext::new( - &[], + vec![], [0; 27], vec![], 0, @@ -471,7 +471,7 @@ mod test { }]; // Create a dummy context let ctx = CrashDumpContext::new( - ®ions, + regions, [0; 27], vec![], 0x1000, diff --git a/src/hyperlight_host/src/hypervisor/gdb/mod.rs b/src/hyperlight_host/src/hypervisor/gdb/mod.rs index d6333e456..4c57958e5 100644 --- a/src/hyperlight_host/src/hypervisor/gdb/mod.rs +++ b/src/hyperlight_host/src/hypervisor/gdb/mod.rs @@ -27,9 +27,9 @@ mod x86_64_target; use std::io::{self, ErrorKind}; use std::net::TcpListener; use std::sync::{Arc, Mutex}; -use std::thread; +use std::{slice, thread}; -use arch::{SW_BP, SW_BP_SIZE}; +pub(crate) use arch::{SW_BP, SW_BP_SIZE}; use crossbeam_channel::{Receiver, Sender, TryRecvError}; use event_loop::event_loop_thread; use gdbstub::conn::ConnectionExt; @@ -48,6 +48,7 @@ use x86_64_target::HyperlightSandboxTarget; use super::InterruptHandle; use crate::hypervisor::regs::{CommonFpu, CommonRegisters}; use crate::mem::layout::SandboxMemoryLayout; +use crate::mem::memory_region::MemoryRegion; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; use crate::{HyperlightError, new_error}; @@ -89,6 +90,150 @@ impl From for TargetError { } } +/// This abstracts the memory access functions that debugging needs from a sandbox +pub(crate) struct DebugMemoryAccess { + /// Memory manager that provides access to the guest memory + pub(crate) dbg_mem_access_fn: Arc>>, + /// Guest mapped memory regions + pub(crate) guest_mmap_regions: Vec, +} + +impl DebugMemoryAccess { + /// Reads memory from the guest's address space with a maximum length of a PAGE_SIZE + /// + /// # Arguments + /// * `data` - Buffer to store the read data + /// * `gpa` - Guest physical address to read from. + /// This address is shall be translated before calling this function + /// # Returns + /// * `Result<(), HyperlightError>` - Ok if successful, Err otherwise + fn read(&self, data: &mut [u8], gpa: u64) -> crate::Result<()> { + let read_len = data.len(); + + let mem_offset = (gpa as usize) + .checked_sub(SandboxMemoryLayout::BASE_ADDRESS) + .ok_or_else(|| { + log::warn!( + "gpa={:#X} causes subtract with underflow: \"gpa - BASE_ADDRESS={:#X}-{:#X}\"", + gpa, + gpa, + SandboxMemoryLayout::BASE_ADDRESS + ); + HyperlightError::TranslateGuestAddress(gpa) + })?; + + // First check the mapped memory regions to see if the address is within any of them + let mut region_found = false; + for reg in self.guest_mmap_regions.iter() { + if reg.guest_region.contains(&mem_offset) { + log::debug!("Found mapped region containing {:X}: {:#?}", gpa, reg); + + // Region found - calculate the offset within the region + let region_offset = mem_offset.checked_sub(reg.guest_region.start).ok_or_else(|| { + log::warn!( + "Cannot calculate offset in memory region: mem_offset={:#X}, base={:#X}", + mem_offset, + reg.guest_region.start, + ); + HyperlightError::TranslateGuestAddress(mem_offset as u64) + })?; + + let bytes: &[u8] = unsafe { + slice::from_raw_parts(reg.host_region.start as *const u8, reg.host_region.len()) + }; + data[..read_len].copy_from_slice(&bytes[region_offset..region_offset + read_len]); + + region_found = true; + break; + } + } + + if !region_found { + log::debug!( + "No mapped region found containing {:X}. Trying shared memory ...", + gpa + ); + + self.dbg_mem_access_fn + .try_lock() + .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? + .get_shared_mem_mut() + .copy_to_slice(&mut data[..read_len], mem_offset)?; + } + + Ok(()) + } + + /// Writes memory from the guest's address space with a maximum length of a PAGE_SIZE + /// + /// # Arguments + /// * `data` - Buffer containing the data to write + /// * `gpa` - Guest physical address to write to. + /// This address is shall be translated before calling this function + /// # Returns + /// * `Result<(), HyperlightError>` - Ok if successful, Err otherwise + fn write(&self, data: &[u8], gpa: u64) -> crate::Result<()> { + let write_len = data.len(); + + let mem_offset = (gpa as usize) + .checked_sub(SandboxMemoryLayout::BASE_ADDRESS) + .ok_or_else(|| { + log::warn!( + "gpa={:#X} causes subtract with underflow: \"gpa - BASE_ADDRESS={:#X}-{:#X}\"", + gpa, + gpa, + SandboxMemoryLayout::BASE_ADDRESS + ); + HyperlightError::TranslateGuestAddress(gpa) + })?; + + // First check the mapped memory regions to see if the address is within any of them + let mut region_found = false; + for reg in self.guest_mmap_regions.iter() { + if reg.guest_region.contains(&mem_offset) { + log::debug!("Found mapped region containing {:X}: {:#?}", gpa, reg); + + // Region found - calculate the offset within the region + let region_offset = mem_offset.checked_sub(reg.guest_region.start).ok_or_else(|| { + log::warn!( + "Cannot calculate offset in memory region: mem_offset={:#X}, base={:#X}", + mem_offset, + reg.guest_region.start, + ); + HyperlightError::TranslateGuestAddress(mem_offset as u64) + })?; + + let bytes: &mut [u8] = unsafe { + slice::from_raw_parts_mut( + reg.host_region.start as *mut u8, + reg.host_region.len(), + ) + }; + bytes[region_offset..region_offset + write_len].copy_from_slice(&data[..write_len]); + + region_found = true; + break; + } + } + + if !region_found { + log::debug!( + "No mapped region found containing {:X}. Trying shared memory at offset {:X} ...", + gpa, + mem_offset + ); + + self.dbg_mem_access_fn + .try_lock() + .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? + .get_shared_mem_mut() + .copy_from_slice(&data[..write_len], mem_offset)?; + } + + Ok(()) + } +} + /// Defines the possible reasons for which a vCPU can be stopped when debugging #[derive(Debug)] pub enum VcpuStopReason { @@ -193,7 +338,7 @@ pub(super) trait GuestDebug { &mut self, vcpu_fd: &Self::Vcpu, addr: u64, - dbg_mem_access_fn: Arc>>, + mem_access: &DebugMemoryAccess, ) -> crate::Result<()> { let addr = self.translate_gva(vcpu_fd, addr)?; @@ -203,8 +348,8 @@ pub(super) trait GuestDebug { // Write breakpoint OP code to write to guest memory let mut save_data = [0; SW_BP_SIZE]; - self.read_addrs(vcpu_fd, addr, &mut save_data[..], dbg_mem_access_fn.clone())?; - self.write_addrs(vcpu_fd, addr, &SW_BP, dbg_mem_access_fn)?; + self.read_addrs(vcpu_fd, addr, &mut save_data[..], mem_access)?; + self.write_addrs(vcpu_fd, addr, &SW_BP, mem_access)?; // Save guest memory to restore when breakpoint is removed self.save_sw_breakpoint_data(addr, save_data); @@ -218,7 +363,7 @@ pub(super) trait GuestDebug { vcpu_fd: &Self::Vcpu, mut gva: u64, mut data: &mut [u8], - dbg_mem_access_fn: Arc>>, + mem_access: &DebugMemoryAccess, ) -> crate::Result<()> { let data_len = data.len(); log::debug!("Read addr: {:X} len: {:X}", gva, data_len); @@ -230,20 +375,8 @@ pub(super) trait GuestDebug { data.len(), (PAGE_SIZE - (gpa & (PAGE_SIZE - 1))).try_into().unwrap(), ); - let offset = (gpa as usize) - .checked_sub(SandboxMemoryLayout::BASE_ADDRESS) - .ok_or_else(|| { - log::warn!( - "gva=0x{:#X} causes subtract with underflow: \"gpa - BASE_ADDRESS={:#X}-{:#X}\"", - gva, gpa, SandboxMemoryLayout::BASE_ADDRESS); - HyperlightError::TranslateGuestAddress(gva) - })?; - dbg_mem_access_fn - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .get_shared_mem_mut() - .copy_to_slice(&mut data[..read_len], offset)?; + mem_access.read(&mut data[..read_len], gpa)?; data = &mut data[read_len..]; gva += read_len as u64; @@ -267,7 +400,7 @@ pub(super) trait GuestDebug { &mut self, vcpu_fd: &Self::Vcpu, addr: u64, - dbg_mem_access_fn: Arc>>, + mem_access: &DebugMemoryAccess, ) -> crate::Result<()> { let addr = self.translate_gva(vcpu_fd, addr)?; @@ -277,7 +410,7 @@ pub(super) trait GuestDebug { .ok_or_else(|| new_error!("Expected to contain the sw breakpoint address"))?; // Restore saved data to the guest's memory - self.write_addrs(vcpu_fd, addr, &save_data, dbg_mem_access_fn)?; + self.write_addrs(vcpu_fd, addr, &save_data, mem_access)?; Ok(()) } else { @@ -291,7 +424,7 @@ pub(super) trait GuestDebug { vcpu_fd: &Self::Vcpu, mut gva: u64, mut data: &[u8], - dbg_mem_access_fn: Arc>>, + mem_access: &DebugMemoryAccess, ) -> crate::Result<()> { let data_len = data.len(); log::debug!("Write addr: {:X} len: {:X}", gva, data_len); @@ -303,20 +436,9 @@ pub(super) trait GuestDebug { data.len(), (PAGE_SIZE - (gpa & (PAGE_SIZE - 1))).try_into().unwrap(), ); - let offset = (gpa as usize) - .checked_sub(SandboxMemoryLayout::BASE_ADDRESS) - .ok_or_else(|| { - log::warn!( - "gva=0x{:#X} causes subtract with underflow: \"gpa - BASE_ADDRESS={:#X}-{:#X}\"", - gva, gpa, SandboxMemoryLayout::BASE_ADDRESS); - HyperlightError::TranslateGuestAddress(gva) - })?; - dbg_mem_access_fn - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .get_shared_mem_mut() - .copy_from_slice(&data[..write_len], offset)?; + // Use the memory access to write to guest memory + mem_access.write(&data[..write_len], gpa)?; data = &data[write_len..]; gva += write_len as u64; @@ -441,4 +563,180 @@ mod tests { let res = gdb_conn.recv(); assert!(res.is_ok()); } + + #[cfg(target_os = "linux")] + mod mem_access_tests { + use std::os::fd::AsRawFd; + use std::os::linux::fs::MetadataExt; + use std::sync::{Arc, Mutex}; + + use hyperlight_testing::dummy_guest_as_string; + + use super::*; + use crate::mem::memory_region::{MemoryRegionFlags, MemoryRegionType}; + use crate::sandbox::UninitializedSandbox; + use crate::sandbox::uninitialized::GuestBinary; + use crate::{log_then_return, new_error}; + + #[cfg(target_os = "linux")] + const BASE_VIRT: usize = 0x10000000 + SandboxMemoryLayout::BASE_ADDRESS; + + /// Dummy memory region to test memory access + /// This maps a file into memory and uses it as guest memory + fn get_mem_access() -> crate::Result { + let filename = dummy_guest_as_string().map_err(|e| new_error!("{}", e))?; + + let file = std::fs::File::options() + .read(true) + .write(true) + .open(&filename)?; + let file_size = file.metadata()?.st_size(); + let page_size = page_size::get(); + let size = (file_size as usize).div_ceil(page_size) * page_size; + let mapped_mem = unsafe { + libc::mmap( + std::ptr::null_mut(), + size, + libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC, + libc::MAP_PRIVATE, + file.as_raw_fd(), + 0, + ) + }; + if mapped_mem == libc::MAP_FAILED { + log_then_return!("mmap error: {:?}", std::io::Error::last_os_error()); + } + + // Create a sandbox memory manager with the mapped memory region + let sandbox = UninitializedSandbox::new(GuestBinary::FilePath(filename.clone()), None) + .inspect_err(|_| unsafe { + libc::munmap(mapped_mem, size); + })?; + let (mem_mgr, _) = sandbox.mgr.build(); + + // Create the memory access struct + let mem_access = DebugMemoryAccess { + dbg_mem_access_fn: Arc::new(Mutex::new(mem_mgr)), + guest_mmap_regions: vec![MemoryRegion { + host_region: mapped_mem as usize..mapped_mem.wrapping_add(size) as usize, + guest_region: BASE_VIRT..BASE_VIRT + size, + flags: MemoryRegionFlags::READ | MemoryRegionFlags::EXECUTE, + region_type: MemoryRegionType::Heap, + }], + }; + + Ok(mem_access) + } + + /// Gets a slice to the mapped memory region to be able to modify it + /// + /// NOTE: By returning a mutable slice from a mutable reference, we ensure + /// that the memory is not deallocated while the slice is in use. + unsafe fn get_mmap_slice(mem_access: &mut DebugMemoryAccess) -> &mut [u8] { + unsafe { + std::slice::from_raw_parts_mut( + mem_access.guest_mmap_regions[0].host_region.start as *mut u8, + mem_access.guest_mmap_regions[0].host_region.end + - mem_access.guest_mmap_regions[0].host_region.start, + ) + } + } + + /// Drops the mapped memory region + fn drop_mem_access(mem_access: DebugMemoryAccess) { + let mapped_mem = + mem_access.guest_mmap_regions[0].host_region.start as *mut libc::c_void; + let size = mem_access.guest_mmap_regions[0].host_region.end + - mem_access.guest_mmap_regions[0].host_region.start; + + unsafe { + libc::munmap(mapped_mem, size); + } + } + + #[test] + fn test_mem_access_read_single_byte() -> crate::Result<()> { + let mut mem_access = get_mem_access()?; + let offset = 2000; + + // Modify the memory directly to have a known value to read + { + let slice = unsafe { get_mmap_slice(&mut mem_access) }; + slice[offset] = 0xAA; + } + + let mut read_data = [0u8; 1]; + mem_access.read(&mut read_data, (BASE_VIRT + offset) as u64)?; + + assert_eq!(read_data[0], 0xAA); + + drop_mem_access(mem_access); + + Ok(()) + } + + #[test] + fn test_mem_access_read_multiple_bytes() -> crate::Result<()> { + let mut mem_access = get_mem_access()?; + let offset = 20; + + // Modify the memory directly to have a known value to read + { + let slice = unsafe { get_mmap_slice(&mut mem_access) }; + for i in 0..16 { + slice[offset + i] = i as u8; + } + } + + let mut read_data = [0u8; 16]; + mem_access.read(&mut read_data, (BASE_VIRT + offset) as u64)?; + + assert_eq!( + read_data, + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + ); + drop_mem_access(mem_access); + Ok(()) + } + + #[test] + fn test_mem_access_write_single_byte() -> crate::Result<()> { + let mut mem_access = get_mem_access()?; + let offset = 3000; + { + let slice = unsafe { get_mmap_slice(&mut mem_access) }; + slice[offset] = 0xBB; + } + + let write_data = [0xCCu8; 1]; + mem_access.write(&write_data, (BASE_VIRT + offset) as u64)?; + + let slice = unsafe { get_mmap_slice(&mut mem_access) }; + assert_eq!(slice[offset], write_data[0]); + drop_mem_access(mem_access); + + Ok(()) + } + + #[test] + fn test_mem_access_write_multiple_bytes() -> crate::Result<()> { + let mut mem_access = get_mem_access()?; + let offset = 56; + { + let slice = unsafe { get_mmap_slice(&mut mem_access) }; + for i in 0..16 { + slice[offset + i] = i as u8; + } + } + + let write_data = [0xAAu8; 16]; + mem_access.write(&write_data, (BASE_VIRT + offset) as u64)?; + + let slice = unsafe { get_mmap_slice(&mut mem_access) }; + assert_eq!(slice[offset..offset + 16], write_data); + drop_mem_access(mem_access); + + Ok(()) + } + } } diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 80ee0b16b..083a2fb8e 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -55,7 +55,8 @@ use {super::crashdump, std::path::Path}; #[cfg(gdb)] use super::gdb::{ - DebugCommChannel, DebugMsg, DebugResponse, GuestDebug, MshvDebug, VcpuStopReason, + DebugCommChannel, DebugMemoryAccess, DebugMsg, DebugResponse, GuestDebug, MshvDebug, + VcpuStopReason, }; use super::{HyperlightExit, Hypervisor, InterruptHandle, LinuxInterruptHandle, VirtualCPU}; #[cfg(gdb)] @@ -77,13 +78,9 @@ use crate::{Result, log_then_return, new_error}; #[cfg(gdb)] mod debug { - use std::sync::{Arc, Mutex}; - use super::mshv_bindings::hv_x64_exception_intercept_message; use super::{HypervLinuxDriver, *}; - use crate::hypervisor::gdb::{DebugMsg, DebugResponse, VcpuStopReason}; - use crate::mem::mgr::SandboxMemoryManager; - use crate::mem::shared_mem::HostSharedMemory; + use crate::hypervisor::gdb::{DebugMemoryAccess, DebugMsg, DebugResponse, VcpuStopReason}; use crate::{Result, new_error}; impl HypervLinuxDriver { @@ -114,7 +111,7 @@ mod debug { pub(crate) fn process_dbg_request( &mut self, req: DebugMsg, - dbg_mem_access_fn: Arc>>, + mem_access: &DebugMemoryAccess, ) -> Result { if let Some(debug) = self.debug.as_mut() { match req { @@ -130,7 +127,7 @@ mod debug { )), DebugMsg::AddSwBreakpoint(addr) => Ok(DebugResponse::AddSwBreakpoint( debug - .add_sw_breakpoint(&self.vcpu_fd, addr, dbg_mem_access_fn) + .add_sw_breakpoint(&self.vcpu_fd, addr, mem_access) .map_err(|e| { log::error!("Failed to add sw breakpoint: {:?}", e); @@ -157,7 +154,8 @@ mod debug { Ok(DebugResponse::DisableDebug) } DebugMsg::GetCodeSectionOffset => { - let offset = dbg_mem_access_fn + let offset = mem_access + .dbg_mem_access_fn .try_lock() .map_err(|e| { new_error!("Error locking at {}:{}: {}", file!(), line!(), e) @@ -170,13 +168,7 @@ mod debug { DebugMsg::ReadAddr(addr, len) => { let mut data = vec![0u8; len]; - debug - .read_addrs(&self.vcpu_fd, addr, &mut data, dbg_mem_access_fn) - .map_err(|e| { - log::error!("Failed to read from address: {:?}", e); - - e - })?; + debug.read_addrs(&self.vcpu_fd, addr, &mut data, mem_access)?; Ok(DebugResponse::ReadAddr(data)) } @@ -200,7 +192,7 @@ mod debug { )), DebugMsg::RemoveSwBreakpoint(addr) => Ok(DebugResponse::RemoveSwBreakpoint( debug - .remove_sw_breakpoint(&self.vcpu_fd, addr, dbg_mem_access_fn) + .remove_sw_breakpoint(&self.vcpu_fd, addr, mem_access) .map_err(|e| { log::error!("Failed to remove sw breakpoint: {:?}", e); @@ -218,13 +210,7 @@ mod debug { Ok(DebugResponse::Step) } DebugMsg::WriteAddr(addr, data) => { - debug - .write_addrs(&self.vcpu_fd, addr, &data, dbg_mem_access_fn) - .map_err(|e| { - log::error!("Failed to write to address: {:?}", e); - - e - })?; + debug.write_addrs(&self.vcpu_fd, addr, &data, mem_access)?; Ok(DebugResponse::WriteAddr) } @@ -901,7 +887,7 @@ impl Hypervisor for HypervLinuxDriver { } #[cfg(crashdump)] - fn crashdump_context(&self) -> Result>> { + fn crashdump_context(&self) -> Result> { if self.rt_cfg.guest_core_dump { let mut regs = [0; 27]; @@ -945,8 +931,11 @@ impl Hypervisor for HypervLinuxDriver { .and_then(|name| name.to_os_string().into_string().ok()) }); + // Include both initial sandbox regions and dynamically mapped regions + let mut regions: Vec = self.sandbox_regions.clone(); + regions.extend(self.mmap_regions.iter().cloned()); Ok(Some(crashdump::CrashDumpContext::new( - &self.sandbox_regions, + regions, regs, xsave.buffer.to_vec(), self.entrypoint, @@ -968,6 +957,11 @@ impl Hypervisor for HypervLinuxDriver { return Err(new_error!("Debugging is not enabled")); } + let mem_access = DebugMemoryAccess { + dbg_mem_access_fn, + guest_mmap_regions: self.mmap_regions.to_vec(), + }; + match stop_reason { // If the vCPU stopped because of a crash, we need to handle it differently // We do not want to allow resuming execution or placing breakpoints @@ -1011,7 +1005,7 @@ impl Hypervisor for HypervLinuxDriver { // For all other requests, we will process them normally _ => { - let result = self.process_dbg_request(req, dbg_mem_access_fn.clone()); + let result = self.process_dbg_request(req, &mem_access); match result { Ok(response) => response, Err(HyperlightError::TranslateGuestAddress(_)) => { @@ -1059,7 +1053,7 @@ impl Hypervisor for HypervLinuxDriver { // Wait for a message from gdb let req = self.recv_dbg_msg()?; - let result = self.process_dbg_request(req, dbg_mem_access_fn.clone()); + let result = self.process_dbg_request(req, &mem_access); let response = match result { Ok(response) => response, diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index 490e1f72e..eeb4e6928 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -31,7 +31,8 @@ use {super::crashdump, std::path::Path}; #[cfg(gdb)] use { super::gdb::{ - DebugCommChannel, DebugMsg, DebugResponse, GuestDebug, HypervDebug, VcpuStopReason, + DebugCommChannel, DebugMemoryAccess, DebugMsg, DebugResponse, GuestDebug, HypervDebug, + VcpuStopReason, }, crate::HyperlightError, }; @@ -58,15 +59,11 @@ use crate::{Result, debug, log_then_return, new_error}; #[cfg(gdb)] mod debug { - use std::sync::{Arc, Mutex}; - use windows::Win32::System::Hypervisor::WHV_VP_EXCEPTION_CONTEXT; use super::{HypervWindowsDriver, *}; use crate::Result; - use crate::hypervisor::gdb::{DebugMsg, DebugResponse, VcpuStopReason}; - use crate::mem::mgr::SandboxMemoryManager; - use crate::mem::shared_mem::HostSharedMemory; + use crate::hypervisor::gdb::{DebugMemoryAccess, DebugMsg, DebugResponse, VcpuStopReason}; impl HypervWindowsDriver { /// Resets the debug information to disable debugging @@ -96,7 +93,7 @@ mod debug { pub(crate) fn process_dbg_request( &mut self, req: DebugMsg, - dbg_mem_access_fn: Arc>>, + mem_access: &DebugMemoryAccess, ) -> Result { if let Some(debug) = self.debug.as_mut() { match req { @@ -112,7 +109,7 @@ mod debug { )), DebugMsg::AddSwBreakpoint(addr) => Ok(DebugResponse::AddSwBreakpoint( debug - .add_sw_breakpoint(&self.processor, addr, dbg_mem_access_fn) + .add_sw_breakpoint(&self.processor, addr, mem_access) .map_err(|e| { log::error!("Failed to add sw breakpoint: {:?}", e); @@ -139,7 +136,8 @@ mod debug { Ok(DebugResponse::DisableDebug) } DebugMsg::GetCodeSectionOffset => { - let offset = dbg_mem_access_fn + let offset = mem_access + .dbg_mem_access_fn .try_lock() .map_err(|e| { new_error!("Error locking at {}:{}: {}", file!(), line!(), e) @@ -153,7 +151,7 @@ mod debug { let mut data = vec![0u8; len]; debug - .read_addrs(&self.processor, addr, &mut data, dbg_mem_access_fn) + .read_addrs(&self.processor, addr, &mut data, mem_access) .map_err(|e| { log::error!("Failed to read from address: {:?}", e); @@ -182,7 +180,7 @@ mod debug { )), DebugMsg::RemoveSwBreakpoint(addr) => Ok(DebugResponse::RemoveSwBreakpoint( debug - .remove_sw_breakpoint(&self.processor, addr, dbg_mem_access_fn) + .remove_sw_breakpoint(&self.processor, addr, mem_access) .map_err(|e| { log::error!("Failed to remove sw breakpoint: {:?}", e); @@ -201,7 +199,7 @@ mod debug { } DebugMsg::WriteAddr(addr, data) => { debug - .write_addrs(&self.processor, addr, &data, dbg_mem_access_fn) + .write_addrs(&self.processor, addr, &data, mem_access) .map_err(|e| { log::error!("Failed to write to address: {:?}", e); @@ -735,7 +733,7 @@ impl Hypervisor for HypervWindowsDriver { } #[cfg(crashdump)] - fn crashdump_context(&self) -> Result>> { + fn crashdump_context(&self) -> Result> { if self.rt_cfg.guest_core_dump { let mut regs = [0; 27]; @@ -779,8 +777,11 @@ impl Hypervisor for HypervWindowsDriver { .and_then(|name| name.to_os_string().into_string().ok()) }); + // Include both initial sandbox regions and dynamically mapped regions + let mut regions: Vec = self.sandbox_regions.clone(); + regions.extend(self.mmap_regions.iter().cloned()); Ok(Some(crashdump::CrashDumpContext::new( - &self.sandbox_regions, + regions, regs, xsave, self.entrypoint, @@ -801,6 +802,12 @@ impl Hypervisor for HypervWindowsDriver { if self.debug.is_none() { return Err(new_error!("Debugging is not enabled")); } + + let mem_access = DebugMemoryAccess { + dbg_mem_access_fn, + guest_mmap_regions: self.mmap_regions.to_vec(), + }; + match stop_reason { // If the vCPU stopped because of a crash, we need to handle it differently // We do not want to allow resuming execution or placing breakpoints @@ -844,7 +851,7 @@ impl Hypervisor for HypervWindowsDriver { // For all other requests, we will process them normally _ => { - let result = self.process_dbg_request(req, dbg_mem_access_fn.clone()); + let result = self.process_dbg_request(req, &mem_access); match result { Ok(response) => response, Err(HyperlightError::TranslateGuestAddress(_)) => { @@ -893,7 +900,7 @@ impl Hypervisor for HypervWindowsDriver { // Wait for a message from gdb let req = self.recv_dbg_msg()?; - let result = self.process_dbg_request(req, dbg_mem_access_fn.clone()); + let result = self.process_dbg_request(req, &mem_access); let response = match result { Ok(response) => response, diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index a42538b33..a5ee24e21 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -27,7 +27,10 @@ use tracing::{Span, instrument}; use {super::crashdump, std::path::Path}; #[cfg(gdb)] -use super::gdb::{DebugCommChannel, DebugMsg, DebugResponse, GuestDebug, KvmDebug, VcpuStopReason}; +use super::gdb::{ + DebugCommChannel, DebugMemoryAccess, DebugMsg, DebugResponse, GuestDebug, KvmDebug, + VcpuStopReason, +}; use super::{HyperlightExit, Hypervisor, InterruptHandle, LinuxInterruptHandle, VirtualCPU}; #[cfg(gdb)] use crate::HyperlightError; @@ -70,14 +73,12 @@ pub(crate) fn is_hypervisor_present() -> bool { #[cfg(gdb)] mod debug { - use std::sync::{Arc, Mutex}; - use kvm_bindings::kvm_debug_exit_arch; use super::KVMDriver; - use crate::hypervisor::gdb::{DebugMsg, DebugResponse, GuestDebug, KvmDebug, VcpuStopReason}; - use crate::mem::mgr::SandboxMemoryManager; - use crate::mem::shared_mem::HostSharedMemory; + use crate::hypervisor::gdb::{ + DebugMemoryAccess, DebugMsg, DebugResponse, GuestDebug, KvmDebug, VcpuStopReason, + }; use crate::{Result, new_error}; impl KVMDriver { @@ -108,7 +109,7 @@ mod debug { pub(crate) fn process_dbg_request( &mut self, req: DebugMsg, - dbg_mem_access_fn: Arc>>, + mem_access: &DebugMemoryAccess, ) -> Result { if let Some(debug) = self.debug.as_mut() { match req { @@ -124,7 +125,7 @@ mod debug { )), DebugMsg::AddSwBreakpoint(addr) => Ok(DebugResponse::AddSwBreakpoint( debug - .add_sw_breakpoint(&self.vcpu_fd, addr, dbg_mem_access_fn) + .add_sw_breakpoint(&self.vcpu_fd, addr, mem_access) .map_err(|e| { log::error!("Failed to add sw breakpoint: {:?}", e); @@ -151,7 +152,8 @@ mod debug { Ok(DebugResponse::DisableDebug) } DebugMsg::GetCodeSectionOffset => { - let offset = dbg_mem_access_fn + let offset = mem_access + .dbg_mem_access_fn .try_lock() .map_err(|e| { new_error!("Error locking at {}:{}: {}", file!(), line!(), e) @@ -164,13 +166,7 @@ mod debug { DebugMsg::ReadAddr(addr, len) => { let mut data = vec![0u8; len]; - debug - .read_addrs(&self.vcpu_fd, addr, &mut data, dbg_mem_access_fn) - .map_err(|e| { - log::error!("Failed to read from address: {:?}", e); - - e - })?; + debug.read_addrs(&self.vcpu_fd, addr, &mut data, mem_access)?; Ok(DebugResponse::ReadAddr(data)) } @@ -194,7 +190,7 @@ mod debug { )), DebugMsg::RemoveSwBreakpoint(addr) => Ok(DebugResponse::RemoveSwBreakpoint( debug - .remove_sw_breakpoint(&self.vcpu_fd, addr, dbg_mem_access_fn) + .remove_sw_breakpoint(&self.vcpu_fd, addr, mem_access) .map_err(|e| { log::error!("Failed to remove sw breakpoint: {:?}", e); @@ -212,13 +208,7 @@ mod debug { Ok(DebugResponse::Step) } DebugMsg::WriteAddr(addr, data) => { - debug - .write_addrs(&self.vcpu_fd, addr, &data, dbg_mem_access_fn) - .map_err(|e| { - log::error!("Failed to write to address: {:?}", e); - - e - })?; + debug.write_addrs(&self.vcpu_fd, addr, &data, mem_access)?; Ok(DebugResponse::WriteAddr) } @@ -827,7 +817,7 @@ impl Hypervisor for KVMDriver { } #[cfg(crashdump)] - fn crashdump_context(&self) -> Result>> { + fn crashdump_context(&self) -> Result> { if self.rt_cfg.guest_core_dump { let mut regs = [0; 27]; @@ -873,8 +863,11 @@ impl Hypervisor for KVMDriver { // The [`CrashDumpContext`] accepts xsave as a vector of u8, so we need to convert the // xsave region to a vector of u8 + // Also include mapped regions in addition to the initial sandbox regions + let mut regions: Vec = self.sandbox_regions.clone(); + regions.extend(self.mmap_regions.iter().map(|(r, _)| r.clone())); Ok(Some(crashdump::CrashDumpContext::new( - &self.sandbox_regions, + regions, regs, xsave .region @@ -900,6 +893,11 @@ impl Hypervisor for KVMDriver { return Err(new_error!("Debugging is not enabled")); } + let mem_access = DebugMemoryAccess { + dbg_mem_access_fn, + guest_mmap_regions: self.mmap_regions.iter().map(|(r, _)| r.clone()).collect(), + }; + match stop_reason { // If the vCPU stopped because of a crash, we need to handle it differently // We do not want to allow resuming execution or placing breakpoints @@ -943,7 +941,7 @@ impl Hypervisor for KVMDriver { // For all other requests, we will process them normally _ => { - let result = self.process_dbg_request(req, dbg_mem_access_fn.clone()); + let result = self.process_dbg_request(req, &mem_access); match result { Ok(response) => response, Err(HyperlightError::TranslateGuestAddress(_)) => { @@ -991,7 +989,7 @@ impl Hypervisor for KVMDriver { // Wait for a message from gdb let req = self.recv_dbg_msg()?; - let result = self.process_dbg_request(req, dbg_mem_access_fn.clone()); + let result = self.process_dbg_request(req, &mem_access); let response = match result { Ok(response) => response, diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index 781099134..7ad183ba9 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -298,7 +298,7 @@ pub(crate) trait Hypervisor: Debug + Send { fn as_mut_hypervisor(&mut self) -> &mut dyn Hypervisor; #[cfg(crashdump)] - fn crashdump_context(&self) -> Result>>; + fn crashdump_context(&self) -> Result>; #[cfg(gdb)] /// handles the cases when the vCPU stops due to a Debug event diff --git a/src/tests/rust_guests/dummyguest/Cargo.lock b/src/tests/rust_guests/dummyguest/Cargo.lock index 4baf80060..1d9d3b354 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.lock +++ b/src/tests/rust_guests/dummyguest/Cargo.lock @@ -254,9 +254,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index 076ef55f3..26e526c37 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -257,9 +257,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index 281181180..3a0f074ae 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -499,9 +499,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", From 4ea81840b6ef8145edfdb69f71237f93042cb30d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Oct 2025 04:05:38 +0000 Subject: [PATCH 248/271] Bump cbindgen from 0.29.0 to 0.29.2 (#965) Bumps [cbindgen](https://github.com/mozilla/cbindgen) from 0.29.0 to 0.29.2. - [Release notes](https://github.com/mozilla/cbindgen/releases) - [Changelog](https://github.com/mozilla/cbindgen/blob/main/CHANGES) - [Commits](https://github.com/mozilla/cbindgen/compare/0.29.0...v0.29.2) --- updated-dependencies: - dependency-name: cbindgen dependency-version: 0.29.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 82 ++++++++++++++++++++++------ src/hyperlight_guest_capi/Cargo.toml | 2 +- 2 files changed, 66 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94cdc8432..870942d1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -319,9 +319,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cbindgen" -version = "0.29.0" +version = "0.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "975982cdb7ad6a142be15bdf84aea7ec6a9e5d4d797c004d43185b24cfe4e684" +checksum = "befbfd072a8e81c02f8c507aefce431fe5e7d051f83d48a23ffc9b9fe5a11799" dependencies = [ "clap", "heck", @@ -333,7 +333,7 @@ dependencies = [ "serde_json", "syn", "tempfile", - "toml", + "toml 0.9.8", ] [[package]] @@ -1215,6 +1215,12 @@ dependencies = [ "serde", ] +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + [[package]] name = "heck" version = "0.5.0" @@ -1641,13 +1647,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.0", "serde", + "serde_core", ] [[package]] @@ -1979,7 +1986,7 @@ dependencies = [ "aho-corasick", "crossbeam-epoch", "crossbeam-utils", - "hashbrown", + "hashbrown 0.15.5", "indexmap", "metrics", "ordered-float", @@ -3086,6 +3093,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" +dependencies = [ + "serde_core", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3284,7 +3300,7 @@ dependencies = [ "cfg-expr", "heck", "pkg-config", - "toml", + "toml 0.8.23", "version-compare", ] @@ -3431,11 +3447,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_edit", ] +[[package]] +name = "toml" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned 1.0.3", + "toml_datetime 0.7.3", + "toml_parser", + "toml_writer", + "winnow", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -3445,6 +3476,15 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.22.27" @@ -3453,17 +3493,25 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", - "serde_spanned", - "toml_datetime", - "toml_write", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "winnow", ] [[package]] -name = "toml_write" -version = "0.1.2" +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" [[package]] name = "tonic" @@ -3990,7 +4038,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b722dcf61e0ea47440b53ff83ccb5df8efec57a69d150e4f24882e4eba7e24a4" dependencies = [ "bitflags 2.10.0", - "hashbrown", + "hashbrown 0.15.5", "indexmap", "semver", "serde", diff --git a/src/hyperlight_guest_capi/Cargo.toml b/src/hyperlight_guest_capi/Cargo.toml index 1a9c277c2..5727fbdf2 100644 --- a/src/hyperlight_guest_capi/Cargo.toml +++ b/src/hyperlight_guest_capi/Cargo.toml @@ -20,4 +20,4 @@ flatbuffers = { version = "25.2.10", default-features = false } log = { version = "0.4", default-features = false } [build-dependencies] -cbindgen = "0.29.0" +cbindgen = "0.29.2" From 34b8fd688eea0965ae87a63e21bde6df3164e845 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Oct 2025 04:05:19 +0000 Subject: [PATCH 249/271] Bump proc-macro2 from 1.0.101 to 1.0.102 (#968) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.101 to 1.0.102. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.101...1.0.102) --- updated-dependencies: - dependency-name: proc-macro2 dependency-version: 1.0.102 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 870942d1d..c95e4000b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2598,9 +2598,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "8e0f6df8eaa422d97d72edcd152e1451618fed47fabbdbd5a8864167b1d4aff7" dependencies = [ "unicode-ident", ] diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index 239a7ba6d..35a452689 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] wasmparser = { version = "0.240.0" } quote = { version = "1.0.41" } -proc-macro2 = { version = "1.0.101" } +proc-macro2 = { version = "1.0.102" } syn = { version = "2.0.107" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.37" } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index 9618a8d45..6a2e942b5 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -17,7 +17,7 @@ name = "hyperlight_component_util" [dependencies] wasmparser = { version = "0.240.0" } quote = { version = "1.0.41" } -proc-macro2 = { version = "1.0.101" } +proc-macro2 = { version = "1.0.102" } syn = { version = "2.0.107" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.37" } From 3c5e38da3de622202b9d885bcb77928605b45f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Fri, 29 Aug 2025 16:34:30 +0300 Subject: [PATCH 250/271] [trace-guest] remove unwind_guest feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - This feature is not used separate from the mem_profile - All the unwind logic is now gated by mem_profile Signed-off-by: Doru Blânzeanu --- Justfile | 2 +- docs/hyperlight-metrics-logs-and-traces.md | 7 ++--- src/hyperlight_common/Cargo.toml | 1 - src/hyperlight_common/src/outb.rs | 4 +-- src/hyperlight_guest_bin/Cargo.toml | 2 +- src/hyperlight_host/Cargo.toml | 5 +--- .../src/hypervisor/hyperv_linux.rs | 4 +-- src/hyperlight_host/src/mem/elf.rs | 18 ++++++------ src/hyperlight_host/src/mem/exe.rs | 14 +++++----- src/hyperlight_host/src/mem/mgr.rs | 2 +- src/hyperlight_host/src/sandbox/mod.rs | 28 +++++++++---------- src/hyperlight_host/src/sandbox/outb.rs | 12 ++++---- .../src/sandbox/uninitialized_evolve.rs | 2 +- src/tests/rust_guests/dummyguest/Cargo.toml | 1 - src/tests/rust_guests/simpleguest/Cargo.toml | 1 - src/tests/rust_guests/witguest/Cargo.toml | 1 - 16 files changed, 48 insertions(+), 56 deletions(-) diff --git a/Justfile b/Justfile index ac664c72a..97e573184 100644 --- a/Justfile +++ b/Justfile @@ -234,7 +234,7 @@ check: {{ cargo-cmd }} check -p hyperlight-host --features crashdump {{ target-triple-flag }} {{ cargo-cmd }} check -p hyperlight-host --features print_debug {{ target-triple-flag }} {{ cargo-cmd }} check -p hyperlight-host --features gdb {{ target-triple-flag }} - {{ cargo-cmd }} check -p hyperlight-host --features trace_guest,unwind_guest,mem_profile {{ target-triple-flag }} + {{ cargo-cmd }} check -p hyperlight-host --features trace_guest,mem_profile {{ target-triple-flag }} fmt-check: cargo +nightly fmt --all -- --check diff --git a/docs/hyperlight-metrics-logs-and-traces.md b/docs/hyperlight-metrics-logs-and-traces.md index 7b90be74e..2dbf7bc25 100644 --- a/docs/hyperlight-metrics-logs-and-traces.md +++ b/docs/hyperlight-metrics-logs-and-traces.md @@ -94,12 +94,11 @@ Once the container or the exe is running, the trace output can be viewed in the ## Guest Tracing, Unwinding, and Memory Profiling -Hyperlight provides advanced observability features for guest code running inside micro virtual machines. You can enable guest-side tracing, stack unwinding, and memory profiling using the `trace_guest`, `unwind_guest`, and `mem_profile` features. This section explains how to build, run, and inspect guest traces. +Hyperlight provides advanced observability features for guest code running inside micro virtual machines. You can enable guest-side tracing, stack unwinding, and memory profiling using the `trace_guest` and `mem_profile` features. This section explains how to build, run, and inspect guest traces. The following features are available for guest tracing: - `trace_guest`: Enables tracing for guest code, capturing function calls and execution time. -- `unwind_guest`: Enables stack unwinding for guest code, allowing you to capture stack traces. -- `mem_profile`: Enables memory profiling for guest code, capturing memory allocations and usage. +- `mem_profile`: Enables memory profiling for guest code with stack uwinding, capturing memory allocations and usage. ### Building a Guest with Tracing Support @@ -140,7 +139,7 @@ This command will list the stack frames and tracing information captured during cargo run -p trace_dump ./src/tests/rust_guests/bin/debug/simpleguest ./trace/.trace list_frames ``` -You can use additional features such as `unwind_guest` and `mem_profile` by enabling them during the build and run steps. +You can use the `mem_profile` additional feature by enabling them during the build and run steps. > **Note:** Make sure to follow the build and run steps in order, and ensure that the guest binaries are up to date before running the host example. diff --git a/src/hyperlight_common/Cargo.toml b/src/hyperlight_common/Cargo.toml index 93854f5d9..a1020a881 100644 --- a/src/hyperlight_common/Cargo.toml +++ b/src/hyperlight_common/Cargo.toml @@ -26,7 +26,6 @@ spin = "0.10.0" default = ["tracing"] fuzzing = ["dep:arbitrary"] trace_guest = [] -unwind_guest = [] mem_profile = [] std = [] diff --git a/src/hyperlight_common/src/outb.rs b/src/hyperlight_common/src/outb.rs index 6211c8cf1..9ed240744 100644 --- a/src/hyperlight_common/src/outb.rs +++ b/src/hyperlight_common/src/outb.rs @@ -99,7 +99,7 @@ pub enum OutBAction { CallFunction = 101, Abort = 102, DebugPrint = 103, - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] TraceRecordStack = 104, #[cfg(feature = "mem_profile")] TraceMemoryAlloc = 105, @@ -117,7 +117,7 @@ impl TryFrom for OutBAction { 101 => Ok(OutBAction::CallFunction), 102 => Ok(OutBAction::Abort), 103 => Ok(OutBAction::DebugPrint), - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] 104 => Ok(OutBAction::TraceRecordStack), #[cfg(feature = "mem_profile")] 105 => Ok(OutBAction::TraceMemoryAlloc), diff --git a/src/hyperlight_guest_bin/Cargo.toml b/src/hyperlight_guest_bin/Cargo.toml index 31dfe4030..56c52d240 100644 --- a/src/hyperlight_guest_bin/Cargo.toml +++ b/src/hyperlight_guest_bin/Cargo.toml @@ -18,7 +18,7 @@ default = ["libc", "printf"] libc = [] # compile musl libc printf = [ "libc" ] # compile printf trace_guest = ["hyperlight-common/trace_guest", "hyperlight-guest/trace_guest", "hyperlight-guest-tracing/trace"] -mem_profile = ["hyperlight-common/unwind_guest","hyperlight-common/mem_profile"] +mem_profile = ["hyperlight-common/mem_profile"] [dependencies] hyperlight-guest = { workspace = true, default-features = false } diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 1210abd15..5b3167185 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -133,10 +133,7 @@ print_debug = [] # Dumps the VM state to a file on unexpected errors or crashes. The path of the file will be printed on stdout and logged. crashdump = ["dep:chrono"] trace_guest = ["hyperlight-common/trace_guest", "hyperlight-guest-tracing/trace"] -# This feature enables unwinding the guest stack from the host, in -# order to produce stack traces for debugging or profiling. -unwind_guest = [ "trace_guest", "dep:framehop", "dep:fallible-iterator", "hyperlight-common/unwind_guest" ] -mem_profile = [ "unwind_guest", "hyperlight-common/mem_profile" ] +mem_profile = [ "trace_guest", "dep:framehop", "dep:fallible-iterator", "hyperlight-common/mem_profile" ] kvm = ["dep:kvm-bindings", "dep:kvm-ioctls"] # This feature is deprecated in favor of mshv3 mshv2 = ["dep:mshv-bindings2", "dep:mshv-ioctls2"] diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 083a2fb8e..9aeb07a38 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -1121,7 +1121,7 @@ impl Drop for HypervLinuxDriver { #[cfg(test)] mod tests { use super::*; - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] use crate::mem::exe::DummyUnwindInfo; use crate::mem::memory_region::MemoryRegionVecBuilder; use crate::mem::shared_mem::{ExclusiveSharedMemory, SharedMemory}; @@ -1192,7 +1192,7 @@ mod tests { }, #[cfg(feature = "trace_guest")] TraceInfo::new( - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] Arc::new(DummyUnwindInfo {}), ) .unwrap(), diff --git a/src/hyperlight_host/src/mem/elf.rs b/src/hyperlight_host/src/mem/elf.rs index ff83d42c8..3a30354ef 100644 --- a/src/hyperlight_host/src/mem/elf.rs +++ b/src/hyperlight_host/src/mem/elf.rs @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] use std::sync::Arc; #[cfg(target_arch = "aarch64")] @@ -29,7 +29,7 @@ use goblin::elf64::program_header::PT_LOAD; use crate::{Result, log_then_return, new_error}; -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] struct ResolvedSectionHeader { name: String, addr: u64, @@ -40,13 +40,13 @@ struct ResolvedSectionHeader { pub(crate) struct ElfInfo { payload: Vec, phdrs: ProgramHeaders, - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] shdrs: Vec, entry: u64, relocs: Vec, } -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] struct UnwindInfo { payload: Vec, load_addr: u64, @@ -55,7 +55,7 @@ struct UnwindInfo { shdrs: Vec, } -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] impl super::exe::UnwindInfo for UnwindInfo { fn as_module(&self) -> framehop::Module> { framehop::Module::new( @@ -72,7 +72,7 @@ impl super::exe::UnwindInfo for UnwindInfo { } } -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] impl UnwindInfo { fn resolved_section_header(&self, name: &[u8]) -> Option<&ResolvedSectionHeader> { self.shdrs @@ -81,7 +81,7 @@ impl UnwindInfo { } } -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] impl framehop::ModuleSectionInfo> for &UnwindInfo { fn base_svma(&self) -> u64 { self.base_svma @@ -122,7 +122,7 @@ impl ElfInfo { Ok(ElfInfo { payload: bytes.to_vec(), phdrs: elf.program_headers, - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] shdrs: elf .section_headers .iter() @@ -206,7 +206,7 @@ impl ElfInfo { } } cfg_if::cfg_if! { - if #[cfg(feature = "unwind_guest")] { + if #[cfg(feature = "mem_profile")] { let va_size = self.get_va_size() as u64; let base_svma = self.get_base_va(); Ok(Arc::new(UnwindInfo { diff --git a/src/hyperlight_host/src/mem/exe.rs b/src/hyperlight_host/src/mem/exe.rs index 064d58cde..19b6a9f41 100644 --- a/src/hyperlight_host/src/mem/exe.rs +++ b/src/hyperlight_host/src/mem/exe.rs @@ -16,7 +16,7 @@ limitations under the License. use std::fs::File; use std::io::Read; -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] use std::sync::Arc; use std::vec::Vec; @@ -39,15 +39,15 @@ pub enum ExeInfo { const DEFAULT_ELF_STACK_RESERVE: u64 = 65536; const DEFAULT_ELF_HEAP_RESERVE: u64 = 131072; -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] pub(crate) trait UnwindInfo: Send + Sync { fn as_module(&self) -> framehop::Module>; fn hash(&self) -> blake3::Hash; } -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] pub(crate) struct DummyUnwindInfo {} -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] impl UnwindInfo for DummyUnwindInfo { fn as_module(&self) -> framehop::Module> { framehop::Module::new("unsupported".to_string(), 0..0, 0, self) @@ -56,7 +56,7 @@ impl UnwindInfo for DummyUnwindInfo { blake3::Hash::from_bytes([0; 32]) } } -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] impl framehop::ModuleSectionInfo for &DummyUnwindInfo { fn base_svma(&self) -> u64 { 0 @@ -69,9 +69,9 @@ impl framehop::ModuleSectionInfo for &DummyUnwindInfo { } } -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] pub(crate) type LoadInfo = Arc; -#[cfg(not(feature = "unwind_guest"))] +#[cfg(not(feature = "mem_profile"))] pub(crate) type LoadInfo = (); impl ExeInfo { diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 0a5e0916e..2434dd118 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -347,7 +347,7 @@ impl SandboxMemoryManager { } // The load method returns a LoadInfo which can also be a different type once the - // `unwind_guest` feature is enabled. + // `mem_profile` feature is enabled. #[allow(clippy::let_unit_value)] let load_info = exe_info.load( load_addr.clone().try_into()?, diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index b63357d40..b22dd417a 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -37,7 +37,7 @@ pub mod snapshot; /// Trait used by the macros to paper over the differences between hyperlight and hyperlight-wasm mod callable; -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] use std::io::Write; #[cfg(feature = "trace_guest")] use std::sync::{Arc, Mutex}; @@ -46,7 +46,7 @@ use std::sync::{Arc, Mutex}; pub use callable::Callable; /// Re-export for `SandboxConfiguration` type pub use config::SandboxConfiguration; -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] use framehop::Unwinder; /// Re-export for the `MultiUseSandbox` type pub use initialized_multi_use::MultiUseSandbox; @@ -88,10 +88,10 @@ pub fn is_hypervisor_present() -> bool { hypervisor::get_available_hypervisor().is_some() } -#[cfg(feature = "trace_guest")] -#[derive(Clone)] /// The information that trace collection requires in order to write /// an accurate trace. +#[derive(Clone)] +#[cfg(feature = "trace_guest")] pub(crate) struct TraceInfo { /// The epoch against which trace events are timed; at least as /// early as the creation of the sandbox being traced. @@ -117,14 +117,14 @@ pub(crate) struct TraceInfo { #[allow(dead_code)] pub file: Arc>, /// The unwind information for the current guest - #[cfg(feature = "unwind_guest")] #[allow(dead_code)] + #[cfg(feature = "mem_profile")] pub unwind_module: Arc, /// The framehop unwinder for the current guest - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] pub unwinder: framehop::x86_64::UnwinderX86_64>, /// The framehop cache - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] pub unwind_cache: Arc>, } #[cfg(feature = "trace_guest")] @@ -132,7 +132,7 @@ impl TraceInfo { /// Create a new TraceInfo by saving the current time as the epoch /// and generating a random filename. pub fn new( - #[cfg(feature = "unwind_guest")] unwind_module: Arc, + #[cfg(feature = "mem_profile")] unwind_module: Arc, ) -> crate::Result { let mut path = std::env::current_dir()?; path.push("trace"); @@ -147,9 +147,9 @@ impl TraceInfo { log::info!("Creating trace file at: {}", path.display()); println!("Creating trace file at: {}", path.display()); - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] let hash = unwind_module.hash(); - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] let (unwinder, unwind_cache) = { let mut unwinder = framehop::x86_64::UnwinderX86_64::new(); unwinder.add_module(unwind_module.clone().as_module()); @@ -170,15 +170,15 @@ impl TraceInfo { guest_start_epoch: None, guest_start_tsc: None, file: Arc::new(Mutex::new(std::fs::File::create_new(path)?)), - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] unwind_module, - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] unwinder, - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] unwind_cache, }; /* write a frame identifying the binary */ - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] self::outb::record_trace_frame(&ret, 0, |f| { let _ = f.write_all(hash.as_bytes()); })?; diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index 038d9d780..515d140b7 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -18,9 +18,9 @@ limitations under the License. use std::io::Write; use std::sync::{Arc, Mutex}; -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] use fallible_iterator::FallibleIterator; -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] use framehop::Unwinder; use hyperlight_common::flatbuffer_wrappers::function_types::{FunctionCallResult, ParameterValue}; use hyperlight_common::flatbuffer_wrappers::guest_error::{ErrorCode, GuestError}; @@ -155,7 +155,7 @@ fn outb_abort(mem_mgr: &mut SandboxMemoryManager, data: u32) - Ok(()) } -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] fn unwind( hv: &dyn Hypervisor, mem: &SandboxMemoryManager, @@ -182,7 +182,7 @@ fn unwind( .map_err(|e| new_error!("couldn't unwind: {}", e)) } -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] fn write_stack(out: &mut std::fs::File, stack: &[u64]) { let _ = out.write_all(&stack.len().to_ne_bytes()); for frame in stack { @@ -190,7 +190,7 @@ fn write_stack(out: &mut std::fs::File, stack: &[u64]) { } } -#[cfg(feature = "unwind_guest")] +#[cfg(feature = "mem_profile")] pub(super) fn record_trace_frame( trace_info: &TraceInfo, frame_id: u64, @@ -301,7 +301,7 @@ pub(crate) fn handle_outb( eprint!("{}", ch); Ok(()) } - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] OutBAction::TraceRecordStack => { let Ok(stack) = unwind(_hv, mem_mgr, _hv.trace_info_as_ref()) else { return Ok(()); diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index 637d71998..44183c858 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -166,7 +166,7 @@ pub(crate) fn set_up_hypervisor_partition( #[cfg(feature = "trace_guest")] let trace_info = TraceInfo::new( - #[cfg(feature = "unwind_guest")] + #[cfg(feature = "mem_profile")] _load_info, )?; diff --git a/src/tests/rust_guests/dummyguest/Cargo.toml b/src/tests/rust_guests/dummyguest/Cargo.toml index 6c39889b1..ccf3a7010 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.toml +++ b/src/tests/rust_guests/dummyguest/Cargo.toml @@ -11,5 +11,4 @@ hyperlight-common = { path = "../../../hyperlight_common", default-features = fa [features] default = [] trace_guest = ["hyperlight-guest-bin/trace_guest"] -unwind_guest = ["hyperlight-common/unwind_guest"] mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] diff --git a/src/tests/rust_guests/simpleguest/Cargo.toml b/src/tests/rust_guests/simpleguest/Cargo.toml index 7700a0758..1e0be5af0 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.toml +++ b/src/tests/rust_guests/simpleguest/Cargo.toml @@ -13,6 +13,5 @@ log = {version = "0.4", default-features = false } [features] default = [] trace_guest = ["hyperlight-guest-bin/trace_guest", "hyperlight-guest/trace_guest", "hyperlight-guest-tracing/trace"] -unwind_guest = ["hyperlight-common/unwind_guest"] mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] diff --git a/src/tests/rust_guests/witguest/Cargo.toml b/src/tests/rust_guests/witguest/Cargo.toml index fbdb6b15e..4db4984ab 100644 --- a/src/tests/rust_guests/witguest/Cargo.toml +++ b/src/tests/rust_guests/witguest/Cargo.toml @@ -13,5 +13,4 @@ spin = "0.10.0" [features] default = [] trace_guest = ["hyperlight-guest-bin/trace_guest", "hyperlight-guest/trace_guest"] -unwind_guest = ["hyperlight-common/unwind_guest"] mem_profile = ["hyperlight-common/mem_profile", "hyperlight-guest-bin/mem_profile"] From b50d37a7f2b7ed75a6a91ac65f5b8081fe36a1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Fri, 29 Aug 2025 16:38:49 +0300 Subject: [PATCH 251/271] [trace-host] remove unused `OutBAction::TraceRecordStack` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - The guest side does not use this type of OutBAction - The stack unwinding is done either way when the mem_profile feature is enabled Signed-off-by: Doru Blânzeanu --- src/hyperlight_common/src/outb.rs | 13 ++++--------- src/hyperlight_host/src/sandbox/outb.rs | 9 --------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/hyperlight_common/src/outb.rs b/src/hyperlight_common/src/outb.rs index 9ed240744..4eeb17af7 100644 --- a/src/hyperlight_common/src/outb.rs +++ b/src/hyperlight_common/src/outb.rs @@ -90,7 +90,6 @@ impl TryFrom for Exception { /// - CallFunction: makes a call to a host function, /// - Abort: aborts the execution of the guest, /// - DebugPrint: prints a message to the host -/// - TraceRecordStack: records the stack trace of the guest /// - TraceMemoryAlloc: records memory allocation events /// - TraceMemoryFree: records memory deallocation events /// - TraceRecord: records a trace event in the guest @@ -99,14 +98,12 @@ pub enum OutBAction { CallFunction = 101, Abort = 102, DebugPrint = 103, - #[cfg(feature = "mem_profile")] - TraceRecordStack = 104, + #[cfg(feature = "trace_guest")] + TraceRecord = 104, #[cfg(feature = "mem_profile")] TraceMemoryAlloc = 105, #[cfg(feature = "mem_profile")] TraceMemoryFree = 106, - #[cfg(feature = "trace_guest")] - TraceRecord = 107, } impl TryFrom for OutBAction { @@ -117,14 +114,12 @@ impl TryFrom for OutBAction { 101 => Ok(OutBAction::CallFunction), 102 => Ok(OutBAction::Abort), 103 => Ok(OutBAction::DebugPrint), - #[cfg(feature = "mem_profile")] - 104 => Ok(OutBAction::TraceRecordStack), + #[cfg(feature = "trace_guest")] + 104 => Ok(OutBAction::TraceRecord), #[cfg(feature = "mem_profile")] 105 => Ok(OutBAction::TraceMemoryAlloc), #[cfg(feature = "mem_profile")] 106 => Ok(OutBAction::TraceMemoryFree), - #[cfg(feature = "trace_guest")] - 107 => Ok(OutBAction::TraceRecord), _ => Err(anyhow::anyhow!("Invalid OutBAction value: {}", val)), } } diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index 515d140b7..880d8cc18 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -302,15 +302,6 @@ pub(crate) fn handle_outb( Ok(()) } #[cfg(feature = "mem_profile")] - OutBAction::TraceRecordStack => { - let Ok(stack) = unwind(_hv, mem_mgr, _hv.trace_info_as_ref()) else { - return Ok(()); - }; - record_trace_frame(_hv.trace_info_as_ref(), 1u64, |f| { - write_stack(f, &stack); - }) - } - #[cfg(feature = "mem_profile")] OutBAction::TraceMemoryAlloc => { use crate::hypervisor::regs::CommonRegisters; From f0f7825df9321c3d8b6be1fa56edc2263f645097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Thu, 28 Aug 2025 15:32:23 +0300 Subject: [PATCH 252/271] [trace-host] move trace related logic to separate module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - This helps with keeping code separate and easily gating it out Signed-off-by: Doru Blânzeanu --- .../src/hypervisor/hyperv_linux.rs | 10 +- .../src/hypervisor/hyperv_windows.rs | 6 +- src/hyperlight_host/src/hypervisor/kvm.rs | 10 +- src/hyperlight_host/src/hypervisor/mod.rs | 7 +- src/hyperlight_host/src/sandbox/mod.rs | 141 +------ src/hyperlight_host/src/sandbox/outb.rs | 210 +---------- src/hyperlight_host/src/sandbox/trace/mod.rs | 357 ++++++++++++++++++ .../src/sandbox/uninitialized_evolve.rs | 4 +- 8 files changed, 376 insertions(+), 369 deletions(-) create mode 100644 src/hyperlight_host/src/sandbox/trace/mod.rs diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 9aeb07a38..35ddc634b 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -68,10 +68,10 @@ use crate::mem::mgr::SandboxMemoryManager; use crate::mem::ptr::{GuestPtr, RawPtr}; use crate::mem::shared_mem::HostSharedMemory; use crate::sandbox::SandboxConfiguration; -#[cfg(feature = "trace_guest")] -use crate::sandbox::TraceInfo; use crate::sandbox::host_funcs::FunctionRegistry; use crate::sandbox::outb::handle_outb; +#[cfg(feature = "trace_guest")] +use crate::sandbox::trace::TraceInfo; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; use crate::{Result, log_then_return, new_error}; @@ -1095,11 +1095,7 @@ impl Hypervisor for HypervLinuxDriver { } #[cfg(feature = "trace_guest")] - fn trace_info_as_ref(&self) -> &TraceInfo { - &self.trace_info - } - #[cfg(feature = "trace_guest")] - fn trace_info_as_mut(&mut self) -> &mut TraceInfo { + fn trace_info_mut(&mut self) -> &mut TraceInfo { &mut self.trace_info } } diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index eeb4e6928..e506f7dea 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -941,11 +941,7 @@ impl Hypervisor for HypervWindowsDriver { } #[cfg(feature = "trace_guest")] - fn trace_info_as_ref(&self) -> &TraceInfo { - &self.trace_info - } - #[cfg(feature = "trace_guest")] - fn trace_info_as_mut(&mut self) -> &mut TraceInfo { + fn trace_info_mut(&mut self) -> &mut TraceInfo { &mut self.trace_info } } diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index a5ee24e21..cfaf442f8 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -41,10 +41,10 @@ use crate::mem::mgr::SandboxMemoryManager; use crate::mem::ptr::{GuestPtr, RawPtr}; use crate::mem::shared_mem::HostSharedMemory; use crate::sandbox::SandboxConfiguration; -#[cfg(feature = "trace_guest")] -use crate::sandbox::TraceInfo; use crate::sandbox::host_funcs::FunctionRegistry; use crate::sandbox::outb::handle_outb; +#[cfg(feature = "trace_guest")] +use crate::sandbox::trace::TraceInfo; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; use crate::{Result, log_then_return, new_error}; @@ -1031,11 +1031,7 @@ impl Hypervisor for KVMDriver { } #[cfg(feature = "trace_guest")] - fn trace_info_as_ref(&self) -> &TraceInfo { - &self.trace_info - } - #[cfg(feature = "trace_guest")] - fn trace_info_as_mut(&mut self) -> &mut TraceInfo { + fn trace_info_mut(&mut self) -> &mut TraceInfo { &mut self.trace_info } } diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index 7ad183ba9..7e8b8220b 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -25,7 +25,7 @@ use crate::hypervisor::regs::{ use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::metrics::METRIC_GUEST_CANCELLATION; #[cfg(feature = "trace_guest")] -use crate::sandbox::TraceInfo; +use crate::sandbox::trace::TraceInfo; use crate::{HyperlightError, Result, log_then_return}; /// HyperV-on-linux functionality @@ -313,12 +313,9 @@ pub(crate) trait Hypervisor: Debug + Send { /// Check stack guard to see if the stack is still valid fn check_stack_guard(&self) -> Result; - /// Get a reference of the trace info for the guest - #[cfg(feature = "trace_guest")] - fn trace_info_as_ref(&self) -> &TraceInfo; /// Get a mutable reference of the trace info for the guest #[cfg(feature = "trace_guest")] - fn trace_info_as_mut(&mut self) -> &mut TraceInfo; + fn trace_info_mut(&mut self) -> &mut TraceInfo; } /// Returns a Some(HyperlightExit::AccessViolation(..)) if the given gpa doesn't have diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index b22dd417a..381b6a89e 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -37,17 +37,14 @@ pub mod snapshot; /// Trait used by the macros to paper over the differences between hyperlight and hyperlight-wasm mod callable; -#[cfg(feature = "mem_profile")] -use std::io::Write; +/// Module for tracing guest execution #[cfg(feature = "trace_guest")] -use std::sync::{Arc, Mutex}; +pub(crate) mod trace; /// Trait used by the macros to paper over the differences between hyperlight and hyperlight-wasm pub use callable::Callable; /// Re-export for `SandboxConfiguration` type pub use config::SandboxConfiguration; -#[cfg(feature = "mem_profile")] -use framehop::Unwinder; /// Re-export for the `MultiUseSandbox` type pub use initialized_multi_use::MultiUseSandbox; use tracing::{Span, instrument}; @@ -88,140 +85,6 @@ pub fn is_hypervisor_present() -> bool { hypervisor::get_available_hypervisor().is_some() } -/// The information that trace collection requires in order to write -/// an accurate trace. -#[derive(Clone)] -#[cfg(feature = "trace_guest")] -pub(crate) struct TraceInfo { - /// The epoch against which trace events are timed; at least as - /// early as the creation of the sandbox being traced. - pub epoch: std::time::Instant, - /// The frequency of the timestamp counter. - pub tsc_freq: Option, - /// The epoch at which the guest started, if it has started. - /// This is used to calculate the time spent in the guest relative to the - /// time when the host started. - pub guest_start_epoch: Option, - /// The start guest time, in TSC cycles, for the current guest has a double purpose. - /// This field is used in two ways: - /// 1. It contains the TSC value recorded on the host when the guest started. - /// This is used to calculate the TSC frequency which is the same on the host and guest. - /// The TSC frequency is used to convert TSC values to timestamps in the trace. - /// **NOTE**: This is only used until the TSC frequency is calculated, when the first - /// records are received. - /// 2. To store the TSC value at recorded on the guest when the guest started (first record - /// received) - /// This is used to calculate the records timestamps relative to when guest started. - pub guest_start_tsc: Option, - /// The file to which the trace is being written - #[allow(dead_code)] - pub file: Arc>, - /// The unwind information for the current guest - #[allow(dead_code)] - #[cfg(feature = "mem_profile")] - pub unwind_module: Arc, - /// The framehop unwinder for the current guest - #[cfg(feature = "mem_profile")] - pub unwinder: framehop::x86_64::UnwinderX86_64>, - /// The framehop cache - #[cfg(feature = "mem_profile")] - pub unwind_cache: Arc>, -} -#[cfg(feature = "trace_guest")] -impl TraceInfo { - /// Create a new TraceInfo by saving the current time as the epoch - /// and generating a random filename. - pub fn new( - #[cfg(feature = "mem_profile")] unwind_module: Arc, - ) -> crate::Result { - let mut path = std::env::current_dir()?; - path.push("trace"); - - // create directory if it does not exist - if !path.exists() { - std::fs::create_dir(&path)?; - } - path.push(uuid::Uuid::new_v4().to_string()); - path.set_extension("trace"); - - log::info!("Creating trace file at: {}", path.display()); - println!("Creating trace file at: {}", path.display()); - - #[cfg(feature = "mem_profile")] - let hash = unwind_module.hash(); - #[cfg(feature = "mem_profile")] - let (unwinder, unwind_cache) = { - let mut unwinder = framehop::x86_64::UnwinderX86_64::new(); - unwinder.add_module(unwind_module.clone().as_module()); - let cache = framehop::x86_64::CacheX86_64::new(); - (unwinder, Arc::new(Mutex::new(cache))) - }; - if !hyperlight_guest_tracing::invariant_tsc::has_invariant_tsc() { - // If the platform does not support invariant TSC, warn the user. - // On Azure nested virtualization, the TSC invariant bit is not correctly reported, this is a known issue. - log::warn!( - "Invariant TSC is not supported on this platform, trace timestamps may be inaccurate" - ); - } - - let ret = Self { - epoch: std::time::Instant::now(), - tsc_freq: None, - guest_start_epoch: None, - guest_start_tsc: None, - file: Arc::new(Mutex::new(std::fs::File::create_new(path)?)), - #[cfg(feature = "mem_profile")] - unwind_module, - #[cfg(feature = "mem_profile")] - unwinder, - #[cfg(feature = "mem_profile")] - unwind_cache, - }; - /* write a frame identifying the binary */ - #[cfg(feature = "mem_profile")] - self::outb::record_trace_frame(&ret, 0, |f| { - let _ = f.write_all(hash.as_bytes()); - })?; - Ok(ret) - } - - /// Calculate the TSC frequency based on the RDTSC instruction on the host. - fn calculate_tsc_freq(&mut self) -> crate::Result<()> { - let (start, start_time) = match ( - self.guest_start_tsc.as_ref(), - self.guest_start_epoch.as_ref(), - ) { - (Some(start), Some(start_time)) => (*start, *start_time), - _ => { - // If the guest start TSC and time are not set, we use the current time and TSC. - // This is not ideal, but it allows us to calculate the TSC frequency without - // failing. - // This is a fallback mechanism to ensure that we can still calculate, however it - // should be noted that this may lead to inaccuracies in the TSC frequency. - // The start time should be already set before running the guest for each sandbox. - log::error!( - "Guest start TSC and time are not set. Calculating TSC frequency will use current time and TSC." - ); - ( - hyperlight_guest_tracing::invariant_tsc::read_tsc(), - std::time::Instant::now(), - ) - } - }; - - let end_time = std::time::Instant::now(); - let end = hyperlight_guest_tracing::invariant_tsc::read_tsc(); - - let elapsed = end_time.duration_since(start_time).as_secs_f64(); - let tsc_freq = ((end - start) as f64 / elapsed) as u64; - - log::info!("Calculated TSC frequency: {} Hz", tsc_freq); - self.tsc_freq = Some(tsc_freq); - - Ok(()) - } -} - #[cfg(test)] mod tests { use std::sync::Arc; diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index 880d8cc18..3e53c6f3e 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -14,20 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -#[cfg(feature = "trace_guest")] -use std::io::Write; use std::sync::{Arc, Mutex}; -#[cfg(feature = "mem_profile")] -use fallible_iterator::FallibleIterator; -#[cfg(feature = "mem_profile")] -use framehop::Unwinder; use hyperlight_common::flatbuffer_wrappers::function_types::{FunctionCallResult, ParameterValue}; use hyperlight_common::flatbuffer_wrappers::guest_error::{ErrorCode, GuestError}; use hyperlight_common::flatbuffer_wrappers::guest_log_data::GuestLogData; use hyperlight_common::outb::{Exception, OutBAction}; -#[cfg(feature = "trace_guest")] -use hyperlight_guest_tracing::TraceRecord; use log::{Level, Record}; use tracing::{Span, instrument}; use tracing_log::format_trace; @@ -35,12 +27,8 @@ use tracing_log::format_trace; use super::host_funcs::FunctionRegistry; #[cfg(feature = "trace_guest")] use crate::hypervisor::Hypervisor; -#[cfg(feature = "trace_guest")] -use crate::mem::layout::SandboxMemoryLayout; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; -#[cfg(feature = "trace_guest")] -use crate::sandbox::TraceInfo; use crate::{HyperlightError, Result, new_error}; #[instrument(err(Debug), skip_all, parent = Span::current(), level="Trace")] @@ -155,113 +143,6 @@ fn outb_abort(mem_mgr: &mut SandboxMemoryManager, data: u32) - Ok(()) } -#[cfg(feature = "mem_profile")] -fn unwind( - hv: &dyn Hypervisor, - mem: &SandboxMemoryManager, - trace_info: &TraceInfo, -) -> Result> { - let mut read_stack = |addr| { - mem.shared_mem - .read::((addr - SandboxMemoryLayout::BASE_ADDRESS as u64) as usize) - .map_err(|_| ()) - }; - let mut cache = trace_info - .unwind_cache - .try_lock() - .map_err(|e| new_error!("could not lock unwinder cache {}\n", e))?; - let regs = hv.regs()?; - let iter = trace_info.unwinder.iter_frames( - regs.rip, - framehop::x86_64::UnwindRegsX86_64::new(regs.rip, regs.rsp, regs.rbp), - &mut *cache, - &mut read_stack, - ); - iter.map(|f| Ok(f.address() - mem.layout.get_guest_code_address() as u64)) - .collect() - .map_err(|e| new_error!("couldn't unwind: {}", e)) -} - -#[cfg(feature = "mem_profile")] -fn write_stack(out: &mut std::fs::File, stack: &[u64]) { - let _ = out.write_all(&stack.len().to_ne_bytes()); - for frame in stack { - let _ = out.write_all(&frame.to_ne_bytes()); - } -} - -#[cfg(feature = "mem_profile")] -pub(super) fn record_trace_frame( - trace_info: &TraceInfo, - frame_id: u64, - write_frame: F, -) -> Result<()> { - let Ok(mut out) = trace_info.file.lock() else { - return Ok(()); - }; - // frame structure: - // 16 bytes timestamp - let now = std::time::Instant::now().saturating_duration_since(trace_info.epoch); - let _ = out.write_all(&now.as_micros().to_ne_bytes()); - // 8 bytes frame type id - let _ = out.write_all(&frame_id.to_ne_bytes()); - // frame data - write_frame(&mut out); - Ok(()) -} - -#[cfg(feature = "trace_guest")] -pub(super) fn record_guest_trace_frame( - trace_info: &TraceInfo, - frame_id: u64, - cycles: u64, - write_frame: F, -) -> Result<()> { - let Ok(mut out) = trace_info.file.lock() else { - return Ok(()); - }; - // frame structure: - // 16 bytes timestamp - - // The number of cycles spent in the guest relative to the first received trace record - let cycles_spent = cycles - - trace_info - .guest_start_tsc - .as_ref() - .map_or_else(|| 0, |c| *c); - - // Convert cycles to microseconds based on the TSC frequency - let tsc_freq = trace_info - .tsc_freq - .as_ref() - .ok_or_else(|| new_error!("TSC frequency not set in TraceInfo"))?; - let micros = cycles_spent as f64 / *tsc_freq as f64 * 1_000_000f64; - - // Convert to a Duration - let guest_duration = std::time::Duration::from_micros(micros as u64); - - // Calculate the time when the guest started execution relative to the host epoch - // Note: This is relative to the time saved when the `TraceInfo` was created (before the - // Hypervisor is created). - let guest_start_time = trace_info - .guest_start_epoch - .as_ref() - .unwrap_or(&trace_info.epoch) - .saturating_duration_since(trace_info.epoch); - - // Calculate the timestamp when the actual frame was recorded relative to the host epoch - let timestamp = guest_start_time - .checked_add(guest_duration) - .unwrap_or(guest_duration); - - let _ = out.write_all(×tamp.as_micros().to_ne_bytes()); - // 8 bytes frame type id - let _ = out.write_all(&frame_id.to_ne_bytes()); - // frame data - write_frame(&mut out); - Ok(()) -} - /// Handles OutB operations from the guest. #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] pub(crate) fn handle_outb( @@ -303,97 +184,18 @@ pub(crate) fn handle_outb( } #[cfg(feature = "mem_profile")] OutBAction::TraceMemoryAlloc => { - use crate::hypervisor::regs::CommonRegisters; - - let Ok(stack) = unwind(_hv, mem_mgr, _hv.trace_info_as_ref()) else { - return Ok(()); - }; - let Ok(CommonRegisters { - rax: amt, rcx: ptr, .. - }) = _hv.regs() - else { - return Ok(()); - }; - record_trace_frame(_hv.trace_info_as_ref(), 2u64, |f| { - let _ = f.write_all(&ptr.to_ne_bytes()); - let _ = f.write_all(&amt.to_ne_bytes()); - write_stack(f, &stack); - }) + let regs = _hv.regs()?; + crate::sandbox::trace::handle_trace_memory_alloc(®s, mem_mgr, _hv.trace_info_mut()) } #[cfg(feature = "mem_profile")] OutBAction::TraceMemoryFree => { - use crate::hypervisor::regs::CommonRegisters; - - let Ok(stack) = unwind(_hv, mem_mgr, _hv.trace_info_as_ref()) else { - return Ok(()); - }; - let Ok(CommonRegisters { rcx, .. }) = _hv.regs() else { - return Ok(()); - }; - record_trace_frame(_hv.trace_info_as_ref(), 3u64, |f| { - let _ = f.write_all(&rcx.to_ne_bytes()); - write_stack(f, &stack); - }) + let regs = _hv.regs()?; + crate::sandbox::trace::handle_trace_memory_free(®s, mem_mgr, _hv.trace_info_mut()) } #[cfg(feature = "trace_guest")] OutBAction::TraceRecord => { - use crate::hypervisor::regs::CommonRegisters; - - let Ok(CommonRegisters { - rax: len, rcx: ptr, .. - }) = _hv.regs() - else { - return Ok(()); - }; - let mut buffer = vec![0u8; len as usize * std::mem::size_of::()]; - let buffer = &mut buffer[..]; - - // Read the trace records from the guest memory - mem_mgr - .shared_mem - .copy_to_slice(buffer, ptr as usize - SandboxMemoryLayout::BASE_ADDRESS) - .map_err(|e| { - new_error!( - "Failed to copy trace records from guest memory to host: {:?}", - e - ) - })?; - - let traces = unsafe { - std::slice::from_raw_parts(buffer.as_ptr() as *const TraceRecord, len as usize) - }; - - { - let trace_info = _hv.trace_info_as_mut(); - - // Calculate the TSC frequency based on the current TSC reading - // This is done only once, when the first trace record is received - // Ideally, we should use a timer or a clock to measure the time elapsed, - // but that adds delays. - // To avoid that we store the TSC value and a timestamp right - // before starting the guest execution and then calculate the TSC frequency when - // the first trace record is received, based on the current TSC value and clock. - if trace_info.tsc_freq.is_none() { - trace_info.calculate_tsc_freq()?; - - // After the TSC frequency is calculated, we no longer need the value of TSC - // recorded on the host when the guest started, so we can set the guest_start_tsc field - // to store the TSC value recorded on the guest when the guest started executing. - // This is used to calculate the records timestamps relative to the first trace record. - if !traces.is_empty() { - trace_info.guest_start_tsc = Some(traces[0].cycles); - } - } - } - - for record in traces { - record_guest_trace_frame(_hv.trace_info_as_ref(), 4u64, record.cycles, |f| { - let _ = f.write_all(&record.msg_len.to_ne_bytes()); - let _ = f.write_all(&record.msg[..record.msg_len]); - })? - } - - Ok(()) + let regs = _hv.regs()?; + crate::sandbox::trace::handle_trace_record(®s, mem_mgr, _hv.trace_info_mut()) } } } diff --git a/src/hyperlight_host/src/sandbox/trace/mod.rs b/src/hyperlight_host/src/sandbox/trace/mod.rs new file mode 100644 index 000000000..e16749c52 --- /dev/null +++ b/src/hyperlight_host/src/sandbox/trace/mod.rs @@ -0,0 +1,357 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +use std::io::Write; +use std::sync::{Arc, Mutex}; + +use hyperlight_guest_tracing::TraceRecord; +#[cfg(feature = "mem_profile")] +use {fallible_iterator::FallibleIterator, framehop::Unwinder}; + +use crate::hypervisor::regs::CommonRegisters; +use crate::mem::layout::SandboxMemoryLayout; +use crate::mem::mgr::SandboxMemoryManager; +use crate::mem::shared_mem::HostSharedMemory; +use crate::{Result, new_error}; + +/// The information that trace collection requires in order to write +/// an accurate trace. +#[derive(Clone)] +pub(crate) struct TraceInfo { + /// The epoch against which trace events are timed; at least as + /// early as the creation of the sandbox being traced. + pub epoch: std::time::Instant, + /// The frequency of the timestamp counter. + pub tsc_freq: Option, + /// The epoch at which the guest started, if it has started. + /// This is used to calculate the time spent in the guest relative to the + /// time when the host started. + pub guest_start_epoch: Option, + /// The start guest time, in TSC cycles, for the current guest has a double purpose. + /// This field is used in two ways: + /// 1. It contains the TSC value recorded on the host when the guest started. + /// This is used to calculate the TSC frequency which is the same on the host and guest. + /// The TSC frequency is used to convert TSC values to timestamps in the trace. + /// **NOTE**: This is only used until the TSC frequency is calculated, when the first + /// records are received. + /// 2. To store the TSC value at recorded on the guest when the guest started (first record + /// received) + /// This is used to calculate the records timestamps relative to when guest started. + pub guest_start_tsc: Option, + /// The file to which the trace is being written + #[allow(dead_code)] + pub file: Arc>, + /// The unwind information for the current guest + #[allow(dead_code)] + #[cfg(feature = "mem_profile")] + pub unwind_module: Arc, + /// The framehop unwinder for the current guest + #[cfg(feature = "mem_profile")] + pub unwinder: framehop::x86_64::UnwinderX86_64>, + /// The framehop cache + #[cfg(feature = "mem_profile")] + pub unwind_cache: Arc>, +} + +impl TraceInfo { + /// Create a new TraceInfo by saving the current time as the epoch + /// and generating a random filename. + pub fn new( + #[cfg(feature = "mem_profile")] unwind_module: Arc, + ) -> crate::Result { + let mut path = std::env::current_dir()?; + path.push("trace"); + + // create directory if it does not exist + if !path.exists() { + std::fs::create_dir(&path)?; + } + path.push(uuid::Uuid::new_v4().to_string()); + path.set_extension("trace"); + + log::info!("Creating trace file at: {}", path.display()); + println!("Creating trace file at: {}", path.display()); + + #[cfg(feature = "mem_profile")] + let hash = unwind_module.hash(); + #[cfg(feature = "mem_profile")] + let (unwinder, unwind_cache) = { + let mut unwinder = framehop::x86_64::UnwinderX86_64::new(); + unwinder.add_module(unwind_module.clone().as_module()); + let cache = framehop::x86_64::CacheX86_64::new(); + (unwinder, Arc::new(Mutex::new(cache))) + }; + if !hyperlight_guest_tracing::invariant_tsc::has_invariant_tsc() { + // If the platform does not support invariant TSC, warn the user. + // On Azure nested virtualization, the TSC invariant bit is not correctly reported, this is a known issue. + log::warn!( + "Invariant TSC is not supported on this platform, trace timestamps may be inaccurate" + ); + } + + let ret = Self { + epoch: std::time::Instant::now(), + tsc_freq: None, + guest_start_epoch: None, + guest_start_tsc: None, + file: Arc::new(Mutex::new(std::fs::File::create_new(path)?)), + #[cfg(feature = "mem_profile")] + unwind_module, + #[cfg(feature = "mem_profile")] + unwinder, + #[cfg(feature = "mem_profile")] + unwind_cache, + }; + /* write a frame identifying the binary */ + #[cfg(feature = "mem_profile")] + record_trace_frame(&ret, 0, |f| { + let _ = f.write_all(hash.as_bytes()); + })?; + Ok(ret) + } + + /// Calculate the TSC frequency based on the RDTSC instruction on the host. + pub(crate) fn calculate_tsc_freq(&mut self) -> crate::Result<()> { + let (start, start_time) = match ( + self.guest_start_tsc.as_ref(), + self.guest_start_epoch.as_ref(), + ) { + (Some(start), Some(start_time)) => (*start, *start_time), + _ => { + // If the guest start TSC and time are not set, we use the current time and TSC. + // This is not ideal, but it allows us to calculate the TSC frequency without + // failing. + // This is a fallback mechanism to ensure that we can still calculate, however it + // should be noted that this may lead to inaccuracies in the TSC frequency. + // The start time should be already set before running the guest for each sandbox. + log::error!( + "Guest start TSC and time are not set. Calculating TSC frequency will use current time and TSC." + ); + ( + hyperlight_guest_tracing::invariant_tsc::read_tsc(), + std::time::Instant::now(), + ) + } + }; + + let end_time = std::time::Instant::now(); + let end = hyperlight_guest_tracing::invariant_tsc::read_tsc(); + + let elapsed = end_time.duration_since(start_time).as_secs_f64(); + let tsc_freq = ((end - start) as f64 / elapsed) as u64; + + log::info!("Calculated TSC frequency: {} Hz", tsc_freq); + self.tsc_freq = Some(tsc_freq); + + Ok(()) + } +} + +#[cfg(feature = "mem_profile")] +fn unwind( + regs: &CommonRegisters, + mem: &SandboxMemoryManager, + trace_info: &TraceInfo, +) -> Result> { + let mut read_stack = |addr| { + mem.shared_mem + .read::((addr - SandboxMemoryLayout::BASE_ADDRESS as u64) as usize) + .map_err(|_| ()) + }; + let mut cache = trace_info + .unwind_cache + .try_lock() + .map_err(|e| new_error!("could not lock unwinder cache {}\n", e))?; + let iter = trace_info.unwinder.iter_frames( + regs.rip, + framehop::x86_64::UnwindRegsX86_64::new(regs.rip, regs.rsp, regs.rbp), + &mut *cache, + &mut read_stack, + ); + iter.map(|f| Ok(f.address() - mem.layout.get_guest_code_address() as u64)) + .collect() + .map_err(|e| new_error!("couldn't unwind: {}", e)) +} + +#[cfg(feature = "mem_profile")] +fn write_stack(out: &mut std::fs::File, stack: &[u64]) { + let _ = out.write_all(&stack.len().to_ne_bytes()); + for frame in stack { + let _ = out.write_all(&frame.to_ne_bytes()); + } +} + +#[cfg(feature = "mem_profile")] +fn record_trace_frame( + trace_info: &TraceInfo, + frame_id: u64, + write_frame: F, +) -> Result<()> { + let Ok(mut out) = trace_info.file.lock() else { + return Ok(()); + }; + // frame structure: + // 16 bytes timestamp + let now = std::time::Instant::now().saturating_duration_since(trace_info.epoch); + let _ = out.write_all(&now.as_micros().to_ne_bytes()); + // 8 bytes frame type id + let _ = out.write_all(&frame_id.to_ne_bytes()); + // frame data + write_frame(&mut out); + Ok(()) +} + +fn record_guest_trace_frame( + trace_info: &TraceInfo, + frame_id: u64, + cycles: u64, + write_frame: F, +) -> Result<()> { + let Ok(mut out) = trace_info.file.lock() else { + return Ok(()); + }; + // frame structure: + // 16 bytes timestamp + + // The number of cycles spent in the guest relative to the first received trace record + let cycles_spent = cycles + - trace_info + .guest_start_tsc + .as_ref() + .map_or_else(|| 0, |c| *c); + + // Convert cycles to microseconds based on the TSC frequency + let tsc_freq = trace_info + .tsc_freq + .as_ref() + .ok_or_else(|| new_error!("TSC frequency not set in TraceInfo"))?; + let micros = cycles_spent as f64 / *tsc_freq as f64 * 1_000_000f64; + + // Convert to a Duration + let guest_duration = std::time::Duration::from_micros(micros as u64); + + // Calculate the time when the guest started execution relative to the host epoch + // Note: This is relative to the time saved when the `TraceInfo` was created (before the + // Hypervisor is created). + let guest_start_time = trace_info + .guest_start_epoch + .as_ref() + .unwrap_or(&trace_info.epoch) + .saturating_duration_since(trace_info.epoch); + + // Calculate the timestamp when the actual frame was recorded relative to the host epoch + let timestamp = guest_start_time + .checked_add(guest_duration) + .unwrap_or(guest_duration); + + let _ = out.write_all(×tamp.as_micros().to_ne_bytes()); + // 8 bytes frame type id + let _ = out.write_all(&frame_id.to_ne_bytes()); + // frame data + write_frame(&mut out); + Ok(()) +} + +#[cfg(feature = "mem_profile")] +pub(crate) fn handle_trace_memory_alloc( + regs: &CommonRegisters, + mem_mgr: &SandboxMemoryManager, + trace_info: &TraceInfo, +) -> Result<()> { + let Ok(stack) = unwind(regs, mem_mgr, trace_info) else { + return Ok(()); + }; + let amt = regs.rax; + let ptr = regs.rcx; + + record_trace_frame(trace_info, 2u64, |f| { + let _ = f.write_all(&ptr.to_ne_bytes()); + let _ = f.write_all(&amt.to_ne_bytes()); + write_stack(f, &stack); + }) +} + +#[cfg(feature = "mem_profile")] +pub(crate) fn handle_trace_memory_free( + regs: &CommonRegisters, + mem_mgr: &SandboxMemoryManager, + trace_info: &TraceInfo, +) -> Result<()> { + let Ok(stack) = unwind(regs, mem_mgr, trace_info) else { + return Ok(()); + }; + let ptr = regs.rcx; + + record_trace_frame(trace_info, 3u64, |f| { + let _ = f.write_all(&ptr.to_ne_bytes()); + write_stack(f, &stack); + }) +} + +pub(crate) fn handle_trace_record( + regs: &CommonRegisters, + mem_mgr: &SandboxMemoryManager, + trace_info: &mut TraceInfo, +) -> Result<()> { + let len = regs.rax; + let ptr = regs.rcx; + let mut buffer = vec![0u8; len as usize * std::mem::size_of::()]; + let buffer = &mut buffer[..]; + + // Read the trace records from the guest memory + mem_mgr + .shared_mem + .copy_to_slice(buffer, ptr as usize - SandboxMemoryLayout::BASE_ADDRESS) + .map_err(|e| { + new_error!( + "Failed to copy trace records from guest memory to host: {:?}", + e + ) + })?; + + let traces = + unsafe { std::slice::from_raw_parts(buffer.as_ptr() as *const TraceRecord, len as usize) }; + + { + // Calculate the TSC frequency based on the current TSC reading + // This is done only once, when the first trace record is received + // Ideally, we should use a timer or a clock to measure the time elapsed, + // but that adds delays. + // To avoid that we store the TSC value and a timestamp right + // before starting the guest execution and then calculate the TSC frequency when + // the first trace record is received, based on the current TSC value and clock. + if trace_info.tsc_freq.is_none() { + trace_info.calculate_tsc_freq()?; + + // After the TSC frequency is calculated, we no longer need the value of TSC + // recorded on the host when the guest started, so we can set the guest_start_tsc field + // to store the TSC value recorded on the guest when the guest started executing. + // This is used to calculate the records timestamps relative to the first trace record. + if !traces.is_empty() { + trace_info.guest_start_tsc = Some(traces[0].cycles); + } + } + } + + for record in traces { + record_guest_trace_frame(trace_info, 4u64, record.cycles, |f| { + let _ = f.write_all(&record.msg_len.to_ne_bytes()); + let _ = f.write_all(&record.msg[..record.msg_len]); + })? + } + + Ok(()) +} diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index 44183c858..92030138a 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -34,10 +34,10 @@ use crate::mem::ptr_offset::Offset; use crate::mem::shared_mem::GuestSharedMemory; #[cfg(any(feature = "init-paging", target_os = "windows"))] use crate::mem::shared_mem::SharedMemory; -#[cfg(feature = "trace_guest")] -use crate::sandbox::TraceInfo; #[cfg(gdb)] use crate::sandbox::config::DebugInfo; +#[cfg(feature = "trace_guest")] +use crate::sandbox::trace::TraceInfo; #[cfg(target_os = "linux")] use crate::signal_handlers::setup_signal_handlers; use crate::{MultiUseSandbox, Result, UninitializedSandbox, log_then_return, new_error}; From 0b8da89a03b8a522dd42ce06eff2fb6b28018861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Fri, 29 Aug 2025 15:45:02 +0300 Subject: [PATCH 253/271] [trace] remove old tracing functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - This steps cleans up codebase for the new way of tracing guests - The current method involves custom macros and logic that are not the best for maintainability Signed-off-by: Doru Blânzeanu --- .github/workflows/CargoPublish.yml | 10 +- Cargo.lock | 33 +- Cargo.toml | 2 - Justfile | 19 +- src/hyperlight_common/src/outb.rs | 5 - src/hyperlight_guest/src/exit.rs | 9 - .../src/guest_handle/host_comm.rs | 6 - src/hyperlight_guest/src/guest_handle/io.rs | 25 +- .../src/exceptions/gdt.rs | 1 - .../src/exceptions/handler.rs | 7 - .../src/exceptions/idt.rs | 1 - .../src/exceptions/idtr.rs | 1 - .../src/guest_function/call.rs | 9 +- src/hyperlight_guest_bin/src/lib.rs | 6 +- src/hyperlight_guest_bin/src/paging.rs | 1 - src/hyperlight_guest_tracing/Cargo.toml | 6 +- src/hyperlight_guest_tracing/src/lib.rs | 326 ------------------ src/hyperlight_guest_tracing_macro/Cargo.toml | 25 -- src/hyperlight_guest_tracing_macro/src/lib.rs | 209 ----------- .../src/hypervisor/hyperv_linux.rs | 1 - src/hyperlight_host/src/sandbox/outb.rs | 5 - src/hyperlight_host/src/sandbox/trace/mod.rs | 125 +------ src/tests/rust_guests/dummyguest/Cargo.lock | 79 ++++- src/tests/rust_guests/simpleguest/Cargo.lock | 79 ++++- src/tests/rust_guests/simpleguest/src/main.rs | 62 ---- src/tests/rust_guests/witguest/Cargo.lock | 79 ++++- src/trace_dump/main.rs | 80 +---- 27 files changed, 261 insertions(+), 950 deletions(-) delete mode 100644 src/hyperlight_guest_tracing_macro/Cargo.toml delete mode 100644 src/hyperlight_guest_tracing_macro/src/lib.rs diff --git a/.github/workflows/CargoPublish.yml b/.github/workflows/CargoPublish.yml index 7bebfb28c..ac24250b4 100644 --- a/.github/workflows/CargoPublish.yml +++ b/.github/workflows/CargoPublish.yml @@ -45,7 +45,7 @@ jobs: VERSION="${VERSION#refs/heads/release/v}" echo "VERSION=$VERSION" >> $GITHUB_ENV fi - ./dev/verify-version.sh "$VERSION" hyperlight-common hyperlight-guest hyperlight-guest-bin hyperlight-host hyperlight-component-util hyperlight-component-macro hyperlight-guest-tracing-macro hyperlight-guest-tracing + ./dev/verify-version.sh "$VERSION" hyperlight-common hyperlight-guest hyperlight-guest-bin hyperlight-host hyperlight-component-util hyperlight-component-macro hyperlight-guest-tracing - name: Determine which crates need publishing run: | @@ -74,7 +74,6 @@ jobs: needs_publish hyperlight-component-util needs_publish hyperlight-component-macro needs_publish hyperlight-host - needs_publish hyperlight-guest-tracing-macro needs_publish hyperlight-guest-tracing - name: Publish hyperlight-common @@ -84,13 +83,6 @@ jobs: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_PUBLISH_TOKEN }} if: env.PUBLISH_HYPERLIGHT_COMMON != 'false' - - name: Publish hyperlight-guest-tracing-macro - continue-on-error: ${{ inputs.dry_run }} - run: cargo publish --manifest-path ./src/hyperlight_guest_tracing_macro/Cargo.toml ${{ inputs.dry_run && '--dry-run' || '' }} - env: - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_PUBLISH_TOKEN }} - if: env.PUBLISH_HYPERLIGHT_GUEST_TRACING_MACRO != 'false' - - name: Publish hyperlight-guest-tracing continue-on-error: ${{ inputs.dry_run }} run: cargo publish --manifest-path ./src/hyperlight_guest_tracing/Cargo.toml ${{ inputs.dry_run && '--dry-run' || '' }} diff --git a/Cargo.lock b/Cargo.lock index c95e4000b..0b9e7e7c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1205,6 +1205,15 @@ dependencies = [ "crunchy", ] +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -1221,6 +1230,17 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "serde", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.5.0" @@ -1398,18 +1418,11 @@ dependencies = [ name = "hyperlight-guest-tracing" version = "0.10.0" dependencies = [ + "heapless", "hyperlight-common", - "hyperlight-guest-tracing-macro", "spin 0.10.0", -] - -[[package]] -name = "hyperlight-guest-tracing-macro" -version = "0.10.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "tracing", + "tracing-core", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 7e8133bcf..e509372a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,6 @@ members = [ "src/hyperlight_host", "src/hyperlight_guest_capi", "src/hyperlight_guest_tracing", - "src/hyperlight_guest_tracing_macro", "src/hyperlight_testing", "fuzz", "src/hyperlight_guest_bin", @@ -42,7 +41,6 @@ hyperlight-guest = { path = "src/hyperlight_guest", version = "0.10.0", default- hyperlight-guest-bin = { path = "src/hyperlight_guest_bin", version = "0.10.0", default-features = false } hyperlight-testing = { path = "src/hyperlight_testing", default-features = false } hyperlight-guest-tracing = { path = "src/hyperlight_guest_tracing", version = "0.10.0", default-features = false } -hyperlight-guest-tracing-macro = { path = "src/hyperlight_guest_tracing_macro", version = "0.10.0", default-features = false } hyperlight-component-util = { path = "src/hyperlight_component_util", version = "0.10.0", default-features = false } hyperlight-component-macro = { path = "src/hyperlight_component_macro", version = "0.10.0", default-features = false } diff --git a/Justfile b/Justfile index 97e573184..274c076ac 100644 --- a/Justfile +++ b/Justfile @@ -110,7 +110,7 @@ like-ci config=default-target hypervisor="kvm": {{ if os() == "linux" { "just clippy-exhaustive " + config } else { "" } }} @# Verify MSRV - ./dev/verify-msrv.sh hyperlight-common hyperlight-guest hyperlight-guest-bin hyperlight-host hyperlight-component-util hyperlight-component-macro hyperlight-guest-tracing-macro hyperlight-guest-tracing + ./dev/verify-msrv.sh hyperlight-common hyperlight-guest hyperlight-guest-bin hyperlight-host hyperlight-component-util hyperlight-component-macro hyperlight-guest-tracing @# Build and move Rust guests just build-rust-guests {{config}} @@ -200,22 +200,10 @@ test-rust-crashdump target=default-target features="": test-rust-tracing target=default-target features="": # Run tests for the tracing guest and macro {{ cargo-cmd }} test -p hyperlight-guest-tracing --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} - {{ cargo-cmd }} test -p hyperlight-guest-tracing-macro --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} - # Prepare the tracing guest for testing + # Build the tracing guest to ensure it builds with the tracing feature just build-rust-guests {{ target }} trace_guest just move-rust-guests {{ target }} - # Run hello-world example with tracing enabled to get the trace output - # note that trace-dump doesn't run on MUSL target as of now - TRACE_OUTPUT="$({{ cargo-cmd }} run --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --example hello-world --features {{ if features =="" {"trace_guest"} else { "trace_guest," + features } }})" && \ - TRACE_FILE="$(echo "$TRACE_OUTPUT" | grep -oE 'Creating trace file at: [^ ]+' | awk -F': ' '{print $2}')" && \ - TRACE_FILE="$(echo "$TRACE_OUTPUT" | grep -oE 'Creating trace file at: [^ ]+' | awk -F': ' '{print $2}' | sed -E 's|^(trace/[^ ]+\.trace)$|./\1|; s|.*/(trace/[^ ]+\.trace)$|./\1|')" && \ - echo "$TRACE_OUTPUT" && \ - if [ -z "$TRACE_FILE" ]; then \ - echo "Error: Could not extract trace file path from output." >&2 ; \ - exit 1 ; \ - fi && \ - cargo run -p trace_dump ./{{ simpleguest_source }}/{{ target }}/simpleguest "$TRACE_FILE" list_frames # Rebuild the tracing guests without the tracing feature # This is to ensure that the tracing feature does not affect the other tests @@ -275,7 +263,6 @@ clippy-exhaustive target=default-target: (witguest-wit) ./hack/clippy-package-features.sh hyperlight-testing {{ target }} {{ target-triple }} ./hack/clippy-package-features.sh hyperlight-component-macro {{ target }} {{ target-triple }} ./hack/clippy-package-features.sh hyperlight-component-util {{ target }} {{ target-triple }} - ./hack/clippy-package-features.sh hyperlight-guest-tracing-macro {{ target }} ./hack/clippy-package-features.sh hyperlight-guest-tracing {{ target }} just clippy-guests {{ target }} @@ -285,7 +272,7 @@ clippy-package package target=default-target: (witguest-wit) # Verify Minimum Supported Rust Version verify-msrv: - ./dev/verify-msrv.sh hyperlight-common hyperlight-guest hyperlight-guest-bin hyperlight-host hyperlight-component-util hyperlight-component-macro hyperlight-guest-tracing-macro hyperlight-guest-tracing + ./dev/verify-msrv.sh hyperlight-common hyperlight-guest hyperlight-guest-bin hyperlight-host hyperlight-component-util hyperlight-component-macro hyperlight-guest-tracing ##################### ### RUST EXAMPLES ### diff --git a/src/hyperlight_common/src/outb.rs b/src/hyperlight_common/src/outb.rs index 4eeb17af7..9066b4eb6 100644 --- a/src/hyperlight_common/src/outb.rs +++ b/src/hyperlight_common/src/outb.rs @@ -92,14 +92,11 @@ impl TryFrom for Exception { /// - DebugPrint: prints a message to the host /// - TraceMemoryAlloc: records memory allocation events /// - TraceMemoryFree: records memory deallocation events -/// - TraceRecord: records a trace event in the guest pub enum OutBAction { Log = 99, CallFunction = 101, Abort = 102, DebugPrint = 103, - #[cfg(feature = "trace_guest")] - TraceRecord = 104, #[cfg(feature = "mem_profile")] TraceMemoryAlloc = 105, #[cfg(feature = "mem_profile")] @@ -114,8 +111,6 @@ impl TryFrom for OutBAction { 101 => Ok(OutBAction::CallFunction), 102 => Ok(OutBAction::Abort), 103 => Ok(OutBAction::DebugPrint), - #[cfg(feature = "trace_guest")] - 104 => Ok(OutBAction::TraceRecord), #[cfg(feature = "mem_profile")] 105 => Ok(OutBAction::TraceMemoryAlloc), #[cfg(feature = "mem_profile")] diff --git a/src/hyperlight_guest/src/exit.rs b/src/hyperlight_guest/src/exit.rs index a64ae390a..e3429d288 100644 --- a/src/hyperlight_guest/src/exit.rs +++ b/src/hyperlight_guest/src/exit.rs @@ -21,22 +21,17 @@ use hyperlight_common::outb::OutBAction; /// Halt the execution of the guest and returns control to the host. #[inline(never)] -#[hyperlight_guest_tracing::trace_function] pub fn halt() { - // Ensure all tracing data is flushed before halting - hyperlight_guest_tracing::flush!(); unsafe { asm!("hlt", options(nostack)) } } /// Exits the VM with an Abort OUT action and code 0. #[unsafe(no_mangle)] -#[hyperlight_guest_tracing::trace_function] pub extern "C" fn abort() -> ! { abort_with_code(&[0, 0xFF]) } /// Exits the VM with an Abort OUT action and a specific code. -#[hyperlight_guest_tracing::trace_function] pub fn abort_with_code(code: &[u8]) -> ! { outb(OutBAction::Abort as u16, code); outb(OutBAction::Abort as u16, &[0xFF]); // send abort terminator (if not included in code) @@ -47,7 +42,6 @@ pub fn abort_with_code(code: &[u8]) -> ! { /// /// # Safety /// This function is unsafe because it dereferences a raw pointer. -#[hyperlight_guest_tracing::trace_function] pub unsafe fn abort_with_code_and_message(code: &[u8], message_ptr: *const c_char) -> ! { unsafe { // Step 1: Send abort code (typically 1 byte, but `code` allows flexibility) @@ -76,10 +70,8 @@ pub fn write_abort(code: &[u8]) { } /// OUT bytes to the host through multiple exits. -#[hyperlight_guest_tracing::trace_function] pub(crate) fn outb(port: u16, data: &[u8]) { // Ensure all tracing data is flushed before sending OUT bytes - hyperlight_guest_tracing::flush!(); unsafe { let mut i = 0; while i < data.len() { @@ -96,7 +88,6 @@ pub(crate) fn outb(port: u16, data: &[u8]) { } /// OUT function for sending a 32-bit value to the host. -#[hyperlight_guest_tracing::trace_function] pub(crate) unsafe fn out32(port: u16, val: u32) { unsafe { asm!("out dx, eax", in("dx") port, in("eax") val, options(preserves_flags, nomem, nostack)); diff --git a/src/hyperlight_guest/src/guest_handle/host_comm.rs b/src/hyperlight_guest/src/guest_handle/host_comm.rs index 5802d08f7..66429c3a5 100644 --- a/src/hyperlight_guest/src/guest_handle/host_comm.rs +++ b/src/hyperlight_guest/src/guest_handle/host_comm.rs @@ -37,7 +37,6 @@ use crate::exit::out32; impl GuestHandle { /// Get user memory region as bytes. - #[hyperlight_guest_tracing::trace_function] pub fn read_n_bytes_from_user_memory(&self, num: u64) -> Result> { let peb_ptr = self.peb().unwrap(); let user_memory_region_ptr = unsafe { (*peb_ptr).init_data.ptr as *mut u8 }; @@ -66,7 +65,6 @@ impl GuestHandle { /// /// When calling `call_host_function`, this function is called /// internally to get the return value. - #[hyperlight_guest_tracing::trace_function] pub fn get_host_return_value>(&self) -> Result { let inner = self .try_pop_shared_input_data_into::() @@ -93,7 +91,6 @@ impl GuestHandle { /// /// Note: The function return value must be obtained by calling /// `get_host_return_value`. - #[hyperlight_guest_tracing::trace_function] pub fn call_host_function_without_returning_result( &self, function_name: &str, @@ -127,7 +124,6 @@ impl GuestHandle { /// sends it to the host, and then retrieves the return value. /// /// The return value is deserialized into the specified type `T`. - #[hyperlight_guest_tracing::trace_function] pub fn call_host_function>( &self, function_name: &str, @@ -138,7 +134,6 @@ impl GuestHandle { self.get_host_return_value::() } - #[hyperlight_guest_tracing::trace_function] pub fn get_host_function_details(&self) -> HostFunctionDetails { let peb_ptr = self.peb().unwrap(); let host_function_details_buffer = @@ -155,7 +150,6 @@ impl GuestHandle { } /// Log a message with the specified log level, source, caller, source file, and line number. - #[hyperlight_guest_tracing::trace_function] pub fn log_message( &self, log_level: LogLevel, diff --git a/src/hyperlight_guest/src/guest_handle/io.rs b/src/hyperlight_guest/src/guest_handle/io.rs index d8219b270..c3e39512f 100644 --- a/src/hyperlight_guest/src/guest_handle/io.rs +++ b/src/hyperlight_guest/src/guest_handle/io.rs @@ -26,7 +26,6 @@ use crate::error::{HyperlightGuestError, Result}; impl GuestHandle { /// Pops the top element from the shared input data buffer and returns it as a T - #[hyperlight_guest_tracing::trace_function] pub fn try_pop_shared_input_data_into(&self) -> Result where T: for<'a> TryFrom<&'a [u8]>, @@ -68,18 +67,15 @@ impl GuestHandle { let buffer = &idb[last_element_offset_rel as usize..]; // convert the buffer to T - let type_t = hyperlight_guest_tracing::trace!( - "convert buffer", - match T::try_from(buffer) { - Ok(t) => Ok(t), - Err(_e) => { - return Err(HyperlightGuestError::new( - ErrorCode::GuestError, - format!("Unable to convert buffer to {}", type_name::()), - )); - } + let type_t = match T::try_from(buffer) { + Ok(t) => Ok(t), + Err(_e) => { + return Err(HyperlightGuestError::new( + ErrorCode::GuestError, + format!("Unable to convert buffer to {}", type_name::()), + )); } - ); + }; // update the stack pointer to point to the element we just popped of since that is now free idb[..8].copy_from_slice(&last_element_offset_rel.to_le_bytes()); @@ -91,7 +87,6 @@ impl GuestHandle { } /// Pushes the given data onto the shared output data buffer. - #[hyperlight_guest_tracing::trace_function] pub fn push_shared_output_data(&self, data: &[u8]) -> Result<()> { let peb_ptr = self.peb().unwrap(); let output_stack_size = unsafe { (*peb_ptr).output_stack.size as usize }; @@ -137,9 +132,7 @@ impl GuestHandle { } // write the actual data - hyperlight_guest_tracing::trace!("copy data", { - odb[stack_ptr_rel as usize..stack_ptr_rel as usize + data.len()].copy_from_slice(data); - }); + odb[stack_ptr_rel as usize..stack_ptr_rel as usize + data.len()].copy_from_slice(data); // write the offset to the newly written data, to the top of the stack let bytes: [u8; 8] = stack_ptr_rel.to_le_bytes(); diff --git a/src/hyperlight_guest_bin/src/exceptions/gdt.rs b/src/hyperlight_guest_bin/src/exceptions/gdt.rs index 38bdf183e..0a3b2cfb6 100644 --- a/src/hyperlight_guest_bin/src/exceptions/gdt.rs +++ b/src/hyperlight_guest_bin/src/exceptions/gdt.rs @@ -72,7 +72,6 @@ struct GdtPointer { } /// Load the GDT -#[hyperlight_guest_tracing::trace_function] pub unsafe fn load_gdt() { unsafe { let gdt_ptr = GdtPointer { diff --git a/src/hyperlight_guest_bin/src/exceptions/handler.rs b/src/hyperlight_guest_bin/src/exceptions/handler.rs index 838cd582b..ab0da4cfe 100644 --- a/src/hyperlight_guest_bin/src/exceptions/handler.rs +++ b/src/hyperlight_guest_bin/src/exceptions/handler.rs @@ -65,12 +65,6 @@ pub extern "C" fn hl_exception_handler( exception_number: u64, page_fault_address: u64, ) { - // When using the `trace_function` macro, it wraps the function body with create_trace_record - // call, which generates a warning because of the `abort_with_code_and_message` call which does - // not return. - // This is manually added to avoid the warning. - hyperlight_guest_tracing::trace!("> hl_exception_handler"); - let ctx = stack_pointer as *mut Context; let exn_info = (stack_pointer + size_of::() as u64) as *mut ExceptionInfo; @@ -101,7 +95,6 @@ pub extern "C" fn hl_exception_handler( )(exception_number, exn_info, ctx, page_fault_address) } { - hyperlight_guest_tracing::trace!("< hl_exception_handler"); return; } } diff --git a/src/hyperlight_guest_bin/src/exceptions/idt.rs b/src/hyperlight_guest_bin/src/exceptions/idt.rs index 91364cd95..3107c4df4 100644 --- a/src/hyperlight_guest_bin/src/exceptions/idt.rs +++ b/src/hyperlight_guest_bin/src/exceptions/idt.rs @@ -71,7 +71,6 @@ impl IdtEntry { // Architectures Software Developer's Manual). pub(crate) static mut IDT: [IdtEntry; 256] = unsafe { core::mem::zeroed() }; -#[hyperlight_guest_tracing::trace_function] pub(crate) fn init_idt() { set_idt_entry(Exception::DivideByZero as usize, _do_excp0); // Divide by zero set_idt_entry(Exception::Debug as usize, _do_excp1); // Debug diff --git a/src/hyperlight_guest_bin/src/exceptions/idtr.rs b/src/hyperlight_guest_bin/src/exceptions/idtr.rs index e79fb5dcf..d1d54830b 100644 --- a/src/hyperlight_guest_bin/src/exceptions/idtr.rs +++ b/src/hyperlight_guest_bin/src/exceptions/idtr.rs @@ -40,7 +40,6 @@ impl Idtr { } } -#[hyperlight_guest_tracing::trace_function] pub(crate) unsafe fn load_idt() { unsafe { init_idt(); diff --git a/src/hyperlight_guest_bin/src/guest_function/call.rs b/src/hyperlight_guest_bin/src/guest_function/call.rs index 7bc3ca087..50cdffa50 100644 --- a/src/hyperlight_guest_bin/src/guest_function/call.rs +++ b/src/hyperlight_guest_bin/src/guest_function/call.rs @@ -28,7 +28,6 @@ use crate::{GUEST_HANDLE, REGISTERED_GUEST_FUNCTIONS}; type GuestFunc = fn(&FunctionCall) -> Result>; -#[hyperlight_guest_tracing::trace_function] pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result> { // Validate this is a Guest Function Call if function_call.function_call_type() != FunctionCallType::Guest { @@ -63,7 +62,7 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result core::mem::transmute::(function_pointer) }; - hyperlight_guest_tracing::trace!("guest_function", p_function(&function_call)) + p_function(&function_call) } else { // The given function is not registered. The guest should implement a function called guest_dispatch_function to handle this. @@ -74,9 +73,7 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result fn guest_dispatch_function(function_call: FunctionCall) -> Result>; } - hyperlight_guest_tracing::trace!("default guest function", unsafe { - guest_dispatch_function(function_call) - }) + unsafe { guest_dispatch_function(function_call) } } } @@ -86,7 +83,6 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result // This function may panic, as we have no other ways of dealing with errors at this level #[unsafe(no_mangle)] #[inline(never)] -#[hyperlight_guest_tracing::trace_function] fn internal_dispatch_function() { let handle = unsafe { GUEST_HANDLE }; @@ -120,7 +116,6 @@ fn internal_dispatch_function() { // This is implemented as a separate function to make sure that epilogue in the internal_dispatch_function is called before the halt() // which if it were included in the internal_dispatch_function cause the epilogue to not be called because the halt() would not return // when running in the hypervisor. -#[hyperlight_guest_tracing::trace_function] pub(crate) extern "C" fn dispatch_function() { // The hyperlight host likes to use one partition and reset it in // various ways; if that has happened, there might stale TLB diff --git a/src/hyperlight_guest_bin/src/lib.rs b/src/hyperlight_guest_bin/src/lib.rs index 1c6089a0e..b7cd9d43d 100644 --- a/src/hyperlight_guest_bin/src/lib.rs +++ b/src/hyperlight_guest_bin/src/lib.rs @@ -32,7 +32,6 @@ use hyperlight_common::mem::HyperlightPEB; use hyperlight_common::outb::OutBAction; use hyperlight_guest::exit::{halt, write_abort}; use hyperlight_guest::guest_handle::handle::GuestHandle; -use hyperlight_guest_tracing::{trace, trace_function}; use log::LevelFilter; use spin::Once; @@ -181,7 +180,6 @@ unsafe extern "C" { static INIT: Once = Once::new(); #[unsafe(no_mangle)] -#[trace_function] pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_level: u64) { if peb_address == 0 { panic!("PEB address is null"); @@ -231,9 +229,7 @@ pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_leve .expect("Invalid log level"); init_logger(max_log_level); - trace!("hyperlight_main", - hyperlight_main(); - ); + hyperlight_main(); } }); diff --git a/src/hyperlight_guest_bin/src/paging.rs b/src/hyperlight_guest_bin/src/paging.rs index a5a3d9f26..749900349 100644 --- a/src/hyperlight_guest_bin/src/paging.rs +++ b/src/hyperlight_guest_bin/src/paging.rs @@ -61,7 +61,6 @@ struct MapResponse { /// as such do not use concurrently with any other page table operations /// - TLB invalidation is not performed, /// if previously-unmapped ranges are not being mapped, TLB invalidation may need to be performed afterwards. -#[hyperlight_guest_tracing::trace_function] pub unsafe fn map_region(phys_base: u64, virt_base: *mut u8, len: u64) { let mut pml4_base: u64; unsafe { diff --git a/src/hyperlight_guest_tracing/Cargo.toml b/src/hyperlight_guest_tracing/Cargo.toml index 4e9bf9758..9c67daeaf 100644 --- a/src/hyperlight_guest_tracing/Cargo.toml +++ b/src/hyperlight_guest_tracing/Cargo.toml @@ -10,13 +10,15 @@ readme.workspace = true description = """Provides the tracing functionality for the hyperlight guest.""" [dependencies] +heapless = { version = "0.8.0", features = ["serde"] } hyperlight-common = { workspace = true, default-features = false } -hyperlight-guest-tracing-macro = { workspace = true } spin = "0.10.0" +tracing = { version = "0.1.41", default-features = false, features = ["attributes"] } +tracing-core = { version = "0.1.34", default-features = false } [lints] workspace = true [features] default = [] -trace = [ "hyperlight-guest-tracing-macro/trace", "hyperlight-common/trace_guest" ] +trace = [ "hyperlight-common/trace_guest" ] diff --git a/src/hyperlight_guest_tracing/src/lib.rs b/src/hyperlight_guest_tracing/src/lib.rs index 631890161..b92444aea 100644 --- a/src/hyperlight_guest_tracing/src/lib.rs +++ b/src/hyperlight_guest_tracing/src/lib.rs @@ -15,111 +15,6 @@ limitations under the License. */ #![no_std] -/// Re-export the tracing macros -/// This allows users to use the macros without needing to import them explicitly. -/// -/// # Tracing Macros Usage -/// -/// ## The `trace_function` macro can be used to trace function calls. -/// -/// ```rust -/// #[hyperlight_guest_tracing_macro::trace_function] -/// fn my_function() { -/// // // Function body -/// } -/// ``` -/// -/// ## The `trace!` macro can be used to create trace records with a message. -/// -/// ```rust -/// use hyperlight_guest_tracing_macro::trace; -/// trace!("message"); -/// trace!("message", { /* block of code */ }); -/// ``` -/// -/// ## Basic usage: trace with message only -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// trace!("hello"); -/// ``` -/// -/// ## Trace with a block, returning a value -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// let x = trace!("block", { 42 }); -/// assert_eq!(x, 42); -/// ``` -/// -/// ## Trace with a block using local variables -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// let y = 10; -/// let z = trace!("sum", { y + 5 }); -/// assert_eq!(z, 15); -/// ``` -/// -/// ## Trace with a block that returns a reference -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// let s = String::from("abc"); -/// let r: &str = trace!("ref", { &s }); -/// assert_eq!(r, "abc"); -/// ``` -/// -/// ## Control flow: `return` inside the block returns from the function -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// fn foo() -> i32 { -/// let _ = trace!("fail", { -/// // This return only exits the closure, not the function `foo`. -/// return 42; -/// }); -/// assert!(false, "This should not be reached"); -/// } -/// ``` -/// -/// ## Control flow: `break` inside the block exits the outer loop -/// -/// ``` -/// use hyperlight_guest_tracing_macro::trace; -/// let mut x = 0; -/// for i in 1..3 { -/// x = i; -/// let _ = trace!("msg", { -/// // This break should exit the loop. -/// break; -/// }); -/// } -/// assert_eq!(x, 1, "Loop should break after the first iteration"); -/// ``` -/// -/// ## Flush the trace buffer -/// ```rust -/// hyperlight_guest_tracing_macro::flush!(); -/// ``` -pub use hyperlight_guest_tracing_macro::*; -#[cfg(feature = "trace")] -pub use trace::{create_trace_record, flush_trace_buffer}; - -/// Maximum length of a trace message in bytes. -pub const MAX_TRACE_MSG_LEN: usize = 64; - -#[derive(Debug, Copy, Clone)] -/// Represents a trace record of a guest with a number of cycles and a message. -pub struct TraceRecord { - /// The number of CPU cycles returned by the invariant TSC. - pub cycles: u64, - /// The length of the message in bytes. - pub msg_len: usize, - /// The message associated with the trace record. - pub msg: [u8; MAX_TRACE_MSG_LEN], -} - /// Module for checking invariant TSC support and reading the timestamp counter pub mod invariant_tsc { use core::arch::x86_64::{__cpuid, _rdtsc}; @@ -153,224 +48,3 @@ pub mod invariant_tsc { unsafe { _rdtsc() } } } - -#[cfg(feature = "trace")] -mod trace { - // === Dependencies === - extern crate alloc; - - use core::mem::MaybeUninit; - - use hyperlight_common::outb::OutBAction; - use spin::Mutex; - - use super::{MAX_TRACE_MSG_LEN, TraceRecord, invariant_tsc}; - - /// Type alias for the function that sends trace records to the host. - type SendToHostFn = fn(u64, &[TraceRecord]); - - /// Global trace buffer for storing trace records. - static TRACE_BUFFER: Mutex> = - Mutex::new(TraceBuffer::new(send_to_host)); - - /// Maximum number of entries in the trace buffer. - /// From local testing, 32 entries seems to be a good balance between performance and memory usage. - const MAX_NO_OF_ENTRIES: usize = 32; - - impl From<&str> for TraceRecord { - fn from(mut msg: &str) -> Self { - if msg.len() > MAX_TRACE_MSG_LEN { - // If the message is too long, truncate it to fit the maximum length - msg = &msg[..MAX_TRACE_MSG_LEN]; - } - - let cycles = invariant_tsc::read_tsc(); - - TraceRecord { - cycles, - msg: { - let mut arr = [0u8; MAX_TRACE_MSG_LEN]; - arr[..msg.len()].copy_from_slice(msg.as_bytes()); - arr - }, - msg_len: msg.len(), - } - } - } - - /// A buffer for storing trace records. - struct TraceBuffer { - /// The entries in the trace buffer. - entries: [TraceRecord; MAX_NO_OF_ENTRIES], - /// The index where the next entry will be written. - write_index: usize, - /// Function to send the trace records to the host. - send_to_host: F, - } - - impl TraceBuffer { - /// Creates a new `TraceBuffer` with uninitialized entries. - const fn new(f: F) -> Self { - Self { - entries: unsafe { [MaybeUninit::zeroed().assume_init(); MAX_NO_OF_ENTRIES] }, - write_index: 0, - send_to_host: f, - } - } - - /// Push a new trace record into the buffer. - /// If the buffer is full, it sends the records to the host. - fn push(&mut self, entry: TraceRecord) { - let mut write_index = self.write_index; - - self.entries[write_index] = entry; - write_index = (write_index + 1) % MAX_NO_OF_ENTRIES; - - self.write_index = write_index; - - if write_index == 0 { - // If buffer is full send to host - (self.send_to_host)(MAX_NO_OF_ENTRIES as u64, &self.entries); - } - } - - /// Flush the trace buffer, sending any remaining records to the host. - fn flush(&mut self) { - if self.write_index > 0 { - (self.send_to_host)(self.write_index as u64, &self.entries); - self.write_index = 0; // Reset write index after flushing - } - } - } - - /// Send the trace records to the host. - fn send_to_host(len: u64, records: &[TraceRecord]) { - unsafe { - core::arch::asm!("out dx, al", - in("dx") OutBAction::TraceRecord as u16, - in("rax") len, - in("rcx") records.as_ptr() as u64); - } - } - - /// Create a trace record from the message and push it to the trace buffer. - /// - /// **NOTE**: If the message is too long it will be truncated to fit within `MAX_TRACE_MSG_LEN`. - /// This is useful for ensuring that the trace buffer does not overflow. - #[inline(always)] - pub fn create_trace_record(msg: &str) { - let entry = TraceRecord::from(msg); - let mut buffer = TRACE_BUFFER.lock(); - - buffer.push(entry); - } - - /// Flush the trace buffer to send any remaining trace records to the host. - #[inline(always)] - pub fn flush_trace_buffer() { - let mut buffer = TRACE_BUFFER.lock(); - buffer.flush(); - } - - #[cfg(test)] - mod tests { - use alloc::format; - - use super::*; - - /// This is a mock function for testing purposes. - /// In a real scenario, this would send the trace records to the host. - fn mock_send_to_host(_len: u64, _records: &[TraceRecord]) {} - - fn create_test_entry(msg: &str) -> TraceRecord { - let cycles = invariant_tsc::read_tsc(); - - TraceRecord { - cycles, - msg: { - let mut arr = [0u8; MAX_TRACE_MSG_LEN]; - arr[..msg.len()].copy_from_slice(msg.as_bytes()); - arr - }, - msg_len: msg.len(), - } - } - - #[test] - fn test_push_trace_record() { - let mut buffer = TraceBuffer::new(mock_send_to_host); - - let msg = "Test message"; - let entry = create_test_entry(msg); - - buffer.push(entry); - assert_eq!(buffer.write_index, 1); - assert_eq!(buffer.entries[0].msg_len, msg.len()); - assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); - assert!(buffer.entries[0].cycles > 0); // Ensure cycles is set - } - - #[test] - fn test_flush_trace_buffer() { - let mut buffer = TraceBuffer::new(mock_send_to_host); - - let msg = "Test message"; - let entry = create_test_entry(msg); - - buffer.push(entry); - assert_eq!(buffer.write_index, 1); - assert_eq!(buffer.entries[0].msg_len, msg.len()); - assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); - assert!(buffer.entries[0].cycles > 0); - - // Flush the buffer - buffer.flush(); - - // After flushing, the entries should still be intact, we don't clear them - assert_eq!(buffer.write_index, 0); - assert_eq!(buffer.entries[0].msg_len, msg.len()); - assert_eq!(&buffer.entries[0].msg[..msg.len()], msg.as_bytes()); - assert!(buffer.entries[0].cycles > 0); - } - - #[test] - fn test_auto_flush_on_full() { - let mut buffer = TraceBuffer::new(mock_send_to_host); - - // Fill the buffer to trigger auto-flush - for i in 0..MAX_NO_OF_ENTRIES { - let msg = format!("Message {}", i); - let entry = create_test_entry(&msg); - buffer.push(entry); - } - - // After filling, the write index should be 0 (buffer is full) - assert_eq!(buffer.write_index, 0); - - // The first entry should still be intact - assert_eq!(buffer.entries[0].msg_len, "Message 0".len()); - } - - /// Test TraceRecord creation with a valid message - #[test] - fn test_trace_record_creation_valid() { - let msg = "Valid message"; - let entry = TraceRecord::from(msg); - assert_eq!(entry.msg_len, msg.len()); - assert_eq!(&entry.msg[..msg.len()], msg.as_bytes()); - assert!(entry.cycles > 0); // Ensure cycles is set - } - - /// Test TraceRecord creation with a message that exceeds the maximum length - #[test] - fn test_trace_record_creation_too_long() { - let long_msg = "A".repeat(MAX_TRACE_MSG_LEN + 1); - let result = TraceRecord::from(long_msg.as_str()); - assert_eq!(result.msg_len, MAX_TRACE_MSG_LEN); - assert_eq!( - &result.msg[..MAX_TRACE_MSG_LEN], - &long_msg.as_bytes()[..MAX_TRACE_MSG_LEN], - ); - } - } -} diff --git a/src/hyperlight_guest_tracing_macro/Cargo.toml b/src/hyperlight_guest_tracing_macro/Cargo.toml deleted file mode 100644 index 88d06022d..000000000 --- a/src/hyperlight_guest_tracing_macro/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "hyperlight-guest-tracing-macro" -version.workspace = true -edition.workspace = true -rust-version.workspace = true -license.workspace = true -homepage.workspace = true -repository.workspace = true -readme.workspace = true -description = """Provides the tracing macros for the hyperlight guest, enabling structured logging and tracing capabilities.""" - -[dependencies] -proc-macro2 = "1.0" -quote = "1.0.41" -syn = { version = "2.0.107", features = ["full"] } - -[features] -default = [] -trace = [] - -[lib] -proc-macro = true - -[lints] -workspace = true diff --git a/src/hyperlight_guest_tracing_macro/src/lib.rs b/src/hyperlight_guest_tracing_macro/src/lib.rs deleted file mode 100644 index cba0bcff3..000000000 --- a/src/hyperlight_guest_tracing_macro/src/lib.rs +++ /dev/null @@ -1,209 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -use proc_macro::TokenStream; -use quote::quote; -use syn::{ItemFn, parse_macro_input}; - -/// A procedural macro attribute for tracing function calls. -/// This macro will create a trace record when the function is called -/// -/// The trace record will contain the function name as a string. -/// Note: This macro is intended to be used with the `hyperlight_guest_tracing` crate. -#[proc_macro_attribute] -pub fn trace_function(_attr: TokenStream, item: TokenStream) -> TokenStream { - let input_fn = parse_macro_input!(item as ItemFn); - - let fn_name = &input_fn.sig.ident; - let fn_name_str = fn_name.to_string(); - let fn_vis = &input_fn.vis; - let fn_sig = &input_fn.sig; - let fn_block = &input_fn.block; - let fn_attrs = &input_fn.attrs; - let fn_output = &input_fn.sig.output; - - // Compose entry/exit messages - let entry_msg = format!("> {}", fn_name_str); - let _exit_msg = format!("< {}", fn_name_str); - - let expanded = match fn_output { - syn::ReturnType::Default => { - // No return value (unit) - #[cfg(feature = "trace")] - quote! { - #(#fn_attrs)* - #fn_vis #fn_sig { - const _: () = assert!( - #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, - "Trace message exceeds the maximum bytes length", - ); - ::hyperlight_guest_tracing::create_trace_record(#entry_msg); - // Call the original function body - #fn_block - ::hyperlight_guest_tracing::create_trace_record(#_exit_msg); - } - } - #[cfg(not(feature = "trace"))] - quote! { - #(#fn_attrs)* - #fn_vis #fn_sig { - const _: () = assert!( - #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, - "Trace message exceeds the maximum bytes length", - ); - #fn_block - } - } - } - syn::ReturnType::Type(_, _) => { - // Has a return value - #[cfg(feature = "trace")] - quote! { - #(#fn_attrs)* - #fn_vis #fn_sig { - const _: () = assert!( - #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, - "Trace message exceeds the maximum bytes length", - ); - ::hyperlight_guest_tracing::create_trace_record(#entry_msg); - let __trace_result = (|| #fn_block )(); - ::hyperlight_guest_tracing::create_trace_record(#_exit_msg); - __trace_result - } - } - #[cfg(not(feature = "trace"))] - quote! { - #(#fn_attrs)* - #fn_vis #fn_sig { - const _: () = assert!( - #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, - "Trace message exceeds the maximum bytes length", - ); - #fn_block - } - } - } - }; - - TokenStream::from(expanded) -} - -// Input structure for the trace macro -struct TraceMacroInput { - message: syn::Lit, - statement: Option, -} - -impl syn::parse::Parse for TraceMacroInput { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let message: syn::Lit = input.parse()?; - if !matches!(message, syn::Lit::Str(_)) { - return Err(input.error("first argument to trace! must be a string literal")); - } - if let syn::Lit::Str(ref lit_str) = message - && lit_str.value().is_empty() - { - return Err(input.error("trace message must not be empty")); - } - - let statement = if input.peek(syn::Token![,]) { - let _: syn::Token![,] = input.parse()?; - Some(input.parse()?) - } else { - None - }; - Ok(TraceMacroInput { message, statement }) - } -} - -/// This macro creates a trace record with a message, or traces a block with entry/exit records. -/// -/// When called with an expression or statement as the second argument, it is wrapped in a block, -/// entry and exit trace records are created at the start and end of block, and the result of the block is returned. -#[proc_macro] -pub fn trace(input: TokenStream) -> TokenStream { - let parsed = syn::parse_macro_input!(input as TraceMacroInput); - let trace_message = match parsed.message { - syn::Lit::Str(ref lit_str) => lit_str.value(), - _ => unreachable!(), - }; - if let Some(statement) = parsed.statement { - let entry_msg = format!("+ {}", trace_message); - let _exit_msg = format!("- {}", trace_message); - #[cfg(feature = "trace")] - let expanded = quote! { - { - const _: () = assert!( - #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, - "Trace message exceeds the maximum bytes length", - ); - ::hyperlight_guest_tracing::create_trace_record(#entry_msg); - let __trace_result = #statement; - ::hyperlight_guest_tracing::create_trace_record(#_exit_msg); - __trace_result - } - }; - #[cfg(not(feature = "trace"))] - let expanded = quote! { - { - const _: () = assert!( - #entry_msg.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, - "Trace message exceeds the maximum bytes length", - ); - #statement - } - }; - - TokenStream::from(expanded) - } else { - #[cfg(feature = "trace")] - let expanded = quote! { - { - const _: () = assert!( - #trace_message.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, - "Trace message exceeds the maximum bytes length", - ); - ::hyperlight_guest_tracing::create_trace_record(#trace_message); - } - }; - #[cfg(not(feature = "trace"))] - let expanded = quote! { - { - const _: () = assert!( - #trace_message.len() <= hyperlight_guest_tracing::MAX_TRACE_MSG_LEN, - "Trace message exceeds the maximum bytes length", - ); - } - }; - - TokenStream::from(expanded) - } -} - -/// This macro flushes the trace buffer, sending any remaining trace records to the host. -#[proc_macro] -pub fn flush(_input: TokenStream) -> TokenStream { - #[cfg(feature = "trace")] - let expanded = quote! { - { - ::hyperlight_guest_tracing::flush_trace_buffer(); - } - }; - #[cfg(not(feature = "trace"))] - let expanded = quote! {}; - - TokenStream::from(expanded) -} diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 35ddc634b..cd8afc223 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -297,7 +297,6 @@ pub(crate) struct HypervLinuxDriver { #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, #[cfg(feature = "trace_guest")] - #[allow(dead_code)] trace_info: TraceInfo, } diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index 3e53c6f3e..0e81c4be4 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -192,11 +192,6 @@ pub(crate) fn handle_outb( let regs = _hv.regs()?; crate::sandbox::trace::handle_trace_memory_free(®s, mem_mgr, _hv.trace_info_mut()) } - #[cfg(feature = "trace_guest")] - OutBAction::TraceRecord => { - let regs = _hv.regs()?; - crate::sandbox::trace::handle_trace_record(®s, mem_mgr, _hv.trace_info_mut()) - } } } #[cfg(test)] diff --git a/src/hyperlight_host/src/sandbox/trace/mod.rs b/src/hyperlight_host/src/sandbox/trace/mod.rs index e16749c52..15f8a8d8c 100644 --- a/src/hyperlight_host/src/sandbox/trace/mod.rs +++ b/src/hyperlight_host/src/sandbox/trace/mod.rs @@ -14,18 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ -use std::io::Write; use std::sync::{Arc, Mutex}; -use hyperlight_guest_tracing::TraceRecord; #[cfg(feature = "mem_profile")] -use {fallible_iterator::FallibleIterator, framehop::Unwinder}; - -use crate::hypervisor::regs::CommonRegisters; -use crate::mem::layout::SandboxMemoryLayout; -use crate::mem::mgr::SandboxMemoryManager; -use crate::mem::shared_mem::HostSharedMemory; -use crate::{Result, new_error}; +use { + crate::hypervisor::regs::CommonRegisters, + crate::mem::layout::SandboxMemoryLayout, + crate::mem::mgr::SandboxMemoryManager, + crate::mem::shared_mem::HostSharedMemory, + crate::{Result, new_error}, + fallible_iterator::FallibleIterator, + framehop::Unwinder, + std::io::Write, +}; /// The information that trace collection requires in order to write /// an accurate trace. @@ -214,57 +215,6 @@ fn record_trace_frame( Ok(()) } -fn record_guest_trace_frame( - trace_info: &TraceInfo, - frame_id: u64, - cycles: u64, - write_frame: F, -) -> Result<()> { - let Ok(mut out) = trace_info.file.lock() else { - return Ok(()); - }; - // frame structure: - // 16 bytes timestamp - - // The number of cycles spent in the guest relative to the first received trace record - let cycles_spent = cycles - - trace_info - .guest_start_tsc - .as_ref() - .map_or_else(|| 0, |c| *c); - - // Convert cycles to microseconds based on the TSC frequency - let tsc_freq = trace_info - .tsc_freq - .as_ref() - .ok_or_else(|| new_error!("TSC frequency not set in TraceInfo"))?; - let micros = cycles_spent as f64 / *tsc_freq as f64 * 1_000_000f64; - - // Convert to a Duration - let guest_duration = std::time::Duration::from_micros(micros as u64); - - // Calculate the time when the guest started execution relative to the host epoch - // Note: This is relative to the time saved when the `TraceInfo` was created (before the - // Hypervisor is created). - let guest_start_time = trace_info - .guest_start_epoch - .as_ref() - .unwrap_or(&trace_info.epoch) - .saturating_duration_since(trace_info.epoch); - - // Calculate the timestamp when the actual frame was recorded relative to the host epoch - let timestamp = guest_start_time - .checked_add(guest_duration) - .unwrap_or(guest_duration); - - let _ = out.write_all(×tamp.as_micros().to_ne_bytes()); - // 8 bytes frame type id - let _ = out.write_all(&frame_id.to_ne_bytes()); - // frame data - write_frame(&mut out); - Ok(()) -} - #[cfg(feature = "mem_profile")] pub(crate) fn handle_trace_memory_alloc( regs: &CommonRegisters, @@ -300,58 +250,3 @@ pub(crate) fn handle_trace_memory_free( write_stack(f, &stack); }) } - -pub(crate) fn handle_trace_record( - regs: &CommonRegisters, - mem_mgr: &SandboxMemoryManager, - trace_info: &mut TraceInfo, -) -> Result<()> { - let len = regs.rax; - let ptr = regs.rcx; - let mut buffer = vec![0u8; len as usize * std::mem::size_of::()]; - let buffer = &mut buffer[..]; - - // Read the trace records from the guest memory - mem_mgr - .shared_mem - .copy_to_slice(buffer, ptr as usize - SandboxMemoryLayout::BASE_ADDRESS) - .map_err(|e| { - new_error!( - "Failed to copy trace records from guest memory to host: {:?}", - e - ) - })?; - - let traces = - unsafe { std::slice::from_raw_parts(buffer.as_ptr() as *const TraceRecord, len as usize) }; - - { - // Calculate the TSC frequency based on the current TSC reading - // This is done only once, when the first trace record is received - // Ideally, we should use a timer or a clock to measure the time elapsed, - // but that adds delays. - // To avoid that we store the TSC value and a timestamp right - // before starting the guest execution and then calculate the TSC frequency when - // the first trace record is received, based on the current TSC value and clock. - if trace_info.tsc_freq.is_none() { - trace_info.calculate_tsc_freq()?; - - // After the TSC frequency is calculated, we no longer need the value of TSC - // recorded on the host when the guest started, so we can set the guest_start_tsc field - // to store the TSC value recorded on the guest when the guest started executing. - // This is used to calculate the records timestamps relative to the first trace record. - if !traces.is_empty() { - trace_info.guest_start_tsc = Some(traces[0].cycles); - } - } - } - - for record in traces { - record_guest_trace_frame(trace_info, 4u64, record.cycles, |f| { - let _ = f.write_all(&record.msg_len.to_ne_bytes()); - let _ = f.write_all(&record.msg[..record.msg_len]); - })? - } - - Ok(()) -} diff --git a/src/tests/rust_guests/dummyguest/Cargo.lock b/src/tests/rust_guests/dummyguest/Cargo.lock index 1d9d3b354..c95757748 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.lock +++ b/src/tests/rust_guests/dummyguest/Cargo.lock @@ -29,6 +29,12 @@ dependencies = [ "spin 0.9.8", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cc" version = "1.2.34" @@ -68,6 +74,26 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "serde", + "stable_deref_trait", +] + [[package]] name = "hyperlight-common" version = "0.10.0" @@ -109,18 +135,11 @@ dependencies = [ name = "hyperlight-guest-tracing" version = "0.10.0" dependencies = [ + "heapless", "hyperlight-common", - "hyperlight-guest-tracing-macro", "spin 0.10.0", -] - -[[package]] -name = "hyperlight-guest-tracing-macro" -version = "0.10.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "tracing", + "tracing-core", ] [[package]] @@ -151,6 +170,12 @@ version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + [[package]] name = "proc-macro2" version = "1.0.101" @@ -252,6 +277,12 @@ dependencies = [ "lock_api", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "syn" version = "2.0.107" @@ -263,6 +294,34 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" + [[package]] name = "unicode-ident" version = "1.0.18" diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index 26e526c37..4008b7025 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -29,6 +29,12 @@ dependencies = [ "spin 0.9.8", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cc" version = "1.2.34" @@ -60,6 +66,26 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "serde", + "stable_deref_trait", +] + [[package]] name = "hyperlight-common" version = "0.10.0" @@ -101,18 +127,11 @@ dependencies = [ name = "hyperlight-guest-tracing" version = "0.10.0" dependencies = [ + "heapless", "hyperlight-common", - "hyperlight-guest-tracing-macro", "spin 0.10.0", -] - -[[package]] -name = "hyperlight-guest-tracing-macro" -version = "0.10.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "tracing", + "tracing-core", ] [[package]] @@ -143,6 +162,12 @@ version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + [[package]] name = "proc-macro2" version = "1.0.101" @@ -255,6 +280,12 @@ dependencies = [ "lock_api", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "syn" version = "2.0.107" @@ -266,6 +297,34 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" + [[package]] name = "unicode-ident" version = "1.0.18" diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index bdf8d5f62..b8219ea69 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -58,7 +58,6 @@ extern crate hyperlight_guest; static mut BIGARRAY: [i32; 1024 * 1024] = [0; 1024 * 1024]; -#[hyperlight_guest_tracing::trace_function] fn set_static(_: &FunctionCall) -> Result> { unsafe { #[allow(static_mut_refs)] @@ -70,7 +69,6 @@ fn set_static(_: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn echo_double(function_call: &FunctionCall) -> Result> { if let ParameterValue::Double(value) = function_call.parameters.clone().unwrap()[0].clone() { Ok(get_flatbuffer_result(value)) @@ -82,7 +80,6 @@ fn echo_double(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn echo_float(function_call: &FunctionCall) -> Result> { if let ParameterValue::Float(value) = function_call.parameters.clone().unwrap()[0].clone() { Ok(get_flatbuffer_result(value)) @@ -94,7 +91,6 @@ fn echo_float(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn print_output(message: &str) -> Result> { let res = call_host_function::( "HostPrint", @@ -105,7 +101,6 @@ fn print_output(message: &str) -> Result> { Ok(get_flatbuffer_result(res)) } -#[hyperlight_guest_tracing::trace_function] fn simple_print_output(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = function_call.parameters.clone().unwrap()[0].clone() { print_output(&message) @@ -117,7 +112,6 @@ fn simple_print_output(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn set_byte_array_to_zero(function_call: &FunctionCall) -> Result> { if let ParameterValue::VecBytes(mut vec) = function_call.parameters.clone().unwrap()[0].clone() { @@ -131,7 +125,6 @@ fn set_byte_array_to_zero(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn print_two_args(function_call: &FunctionCall) -> Result> { if let (ParameterValue::String(arg1), ParameterValue::Int(arg2)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -147,7 +140,6 @@ fn print_two_args(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn print_three_args(function_call: &FunctionCall) -> Result> { if let (ParameterValue::String(arg1), ParameterValue::Int(arg2), ParameterValue::Long(arg3)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -164,7 +156,6 @@ fn print_three_args(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn print_four_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -190,7 +181,6 @@ fn print_four_args(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn print_five_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -218,7 +208,6 @@ fn print_five_args(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn print_six_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -248,7 +237,6 @@ fn print_six_args(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn print_seven_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -280,7 +268,6 @@ fn print_seven_args(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn print_eight_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -314,7 +301,6 @@ fn print_eight_args(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn print_nine_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -350,7 +336,6 @@ fn print_nine_args(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn print_ten_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -388,7 +373,6 @@ fn print_ten_args(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn print_eleven_args(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(arg1), @@ -428,7 +412,6 @@ fn print_eleven_args(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn buffer_overrun(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(value) = function_call.parameters.clone().unwrap()[0].clone() { let c_str = value.as_str(); @@ -451,7 +434,6 @@ fn buffer_overrun(function_call: &FunctionCall) -> Result> { } #[allow(unconditional_recursion)] -#[hyperlight_guest_tracing::trace_function] fn infinite_recursion(_a: &FunctionCall) -> Result> { // blackbox is needed so something //is written to the stack in release mode, @@ -461,7 +443,6 @@ fn infinite_recursion(_a: &FunctionCall) -> Result> { infinite_recursion(_a) } -#[hyperlight_guest_tracing::trace_function] fn stack_overflow(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(i) = function_call.parameters.clone().unwrap()[0].clone() { loop_stack_overflow(i); @@ -474,7 +455,6 @@ fn stack_overflow(function_call: &FunctionCall) -> Result> { } } // This function will allocate i * (8KiB + 1B) on the stack -#[hyperlight_guest_tracing::trace_function] fn loop_stack_overflow(i: i32) { if i > 0 { let _nums = black_box([0u8; 0x2000 + 1]); // chkstk guaranteed to be called for > 8KiB @@ -482,19 +462,16 @@ fn loop_stack_overflow(i: i32) { } } -#[hyperlight_guest_tracing::trace_function] fn large_var(_: &FunctionCall) -> Result> { let _buffer = black_box([0u8; (DEFAULT_GUEST_STACK_SIZE + 1) as usize]); Ok(get_flatbuffer_result(DEFAULT_GUEST_STACK_SIZE + 1)) } -#[hyperlight_guest_tracing::trace_function] fn small_var(_: &FunctionCall) -> Result> { let _buffer = black_box([0u8; 1024]); Ok(get_flatbuffer_result(1024)) } -#[hyperlight_guest_tracing::trace_function] fn call_malloc(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(size) = function_call.parameters.clone().unwrap()[0].clone() { // will panic if OOM, and we need blackbox to avoid optimizing away this test @@ -509,7 +486,6 @@ fn call_malloc(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] unsafe fn exhaust_heap(_: &FunctionCall) -> ! { let layout: Layout = Layout::new::(); let mut ptr = alloc::alloc::alloc_zeroed(layout); @@ -526,7 +502,6 @@ unsafe fn exhaust_heap(_: &FunctionCall) -> ! { panic!("function should have panicked before due to OOM") } -#[hyperlight_guest_tracing::trace_function] fn malloc_and_free(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(size) = function_call.parameters.clone().unwrap()[0].clone() { let alloc_length = if size < DEFAULT_GUEST_STACK_SIZE { @@ -546,7 +521,6 @@ fn malloc_and_free(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn echo(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(value) = function_call.parameters.clone().unwrap()[0].clone() { Ok(get_flatbuffer_result(&*value)) @@ -558,7 +532,6 @@ fn echo(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn get_size_prefixed_buffer(function_call: &FunctionCall) -> Result> { if let ParameterValue::VecBytes(data) = function_call.parameters.clone().unwrap()[0].clone() { Ok(get_flatbuffer_result(&*data)) @@ -583,7 +556,6 @@ fn spin(_: &FunctionCall) -> Result> { Ok(get_flatbuffer_result(())) } -#[hyperlight_guest_tracing::trace_function] fn test_abort(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(code) = function_call.parameters.clone().unwrap()[0].clone() { abort_with_code(&[code as u8]); @@ -591,7 +563,6 @@ fn test_abort(function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result(())) } -#[hyperlight_guest_tracing::trace_function] fn test_abort_with_code_and_message(function_call: &FunctionCall) -> Result> { if let (ParameterValue::Int(code), ParameterValue::String(message)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -604,7 +575,6 @@ fn test_abort_with_code_and_message(function_call: &FunctionCall) -> Result Result> { if let ParameterValue::String(message) = function_call.parameters.clone().unwrap()[0].clone() { panic!("{}", message); @@ -612,7 +582,6 @@ fn test_guest_panic(function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result(())) } -#[hyperlight_guest_tracing::trace_function] fn test_write_raw_ptr(function_call: &FunctionCall) -> Result> { if let ParameterValue::Long(offset) = function_call.parameters.clone().unwrap()[0].clone() { let min_stack_addr = unsafe { MIN_STACK_ADDRESS }; @@ -636,7 +605,6 @@ fn test_write_raw_ptr(function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result("fail")) } -#[hyperlight_guest_tracing::trace_function] fn execute_on_stack(_function_call: &FunctionCall) -> Result> { unsafe { let mut noop: u8 = 0x90; @@ -646,7 +614,6 @@ fn execute_on_stack(_function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result("fail")) } -#[hyperlight_guest_tracing::trace_function] fn execute_on_heap(_function_call: &FunctionCall) -> Result> { unsafe { // NO-OP followed by RET @@ -659,7 +626,6 @@ fn execute_on_heap(_function_call: &FunctionCall) -> Result> { Ok(get_flatbuffer_result("fail")) } -#[hyperlight_guest_tracing::trace_function] fn test_rust_malloc(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(code) = function_call.parameters.clone().unwrap()[0].clone() { let ptr = unsafe { malloc(code as usize) }; @@ -672,7 +638,6 @@ fn test_rust_malloc(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn log_message(function_call: &FunctionCall) -> Result> { if let (ParameterValue::String(message), ParameterValue::Int(level)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -695,7 +660,6 @@ fn log_message(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn trigger_exception(_: &FunctionCall) -> Result> { unsafe { core::arch::asm!("ud2"); @@ -705,7 +669,6 @@ fn trigger_exception(_: &FunctionCall) -> Result> { static mut COUNTER: i32 = 0; -#[hyperlight_guest_tracing::trace_function] fn add_to_static(function_call: &FunctionCall) -> Result> { if let ParameterValue::Int(i) = function_call.parameters.clone().unwrap()[0].clone() { let res = unsafe { @@ -721,7 +684,6 @@ fn add_to_static(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn get_static(function_call: &FunctionCall) -> Result> { if function_call.parameters.is_none() { Ok(get_flatbuffer_result(unsafe { COUNTER })) @@ -733,7 +695,6 @@ fn get_static(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn add_to_static_and_fail(_: &FunctionCall) -> Result> { unsafe { COUNTER += 10; @@ -744,7 +705,6 @@ fn add_to_static_and_fail(_: &FunctionCall) -> Result> { )) } -#[hyperlight_guest_tracing::trace_function] fn twenty_four_k_in_eight_k_out(function_call: &FunctionCall) -> Result> { if let ParameterValue::VecBytes(input) = &function_call.parameters.as_ref().unwrap()[0] { assert!(input.len() == 24 * 1024, "Input must be 24K bytes"); @@ -757,7 +717,6 @@ fn twenty_four_k_in_eight_k_out(function_call: &FunctionCall) -> Result> } } -#[hyperlight_guest_tracing::trace_function] fn violate_seccomp_filters(function_call: &FunctionCall) -> Result> { if function_call.parameters.is_none() { let res = call_host_function::("MakeGetpidSyscall", None, ReturnType::ULong)?; @@ -771,7 +730,6 @@ fn violate_seccomp_filters(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn call_given_paramless_hostfunc_that_returns_i64(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(hostfuncname) = function_call.parameters.clone().unwrap()[0].clone() @@ -787,7 +745,6 @@ fn call_given_paramless_hostfunc_that_returns_i64(function_call: &FunctionCall) } } -#[hyperlight_guest_tracing::trace_function] fn use_sse2_registers(_: &FunctionCall) -> Result> { unsafe { let val: f32 = 1.2f32; @@ -796,7 +753,6 @@ fn use_sse2_registers(_: &FunctionCall) -> Result> { Ok(get_flatbuffer_result(())) } -#[hyperlight_guest_tracing::trace_function] fn add(function_call: &FunctionCall) -> Result> { if let (ParameterValue::Int(a), ParameterValue::Int(b)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -817,7 +773,6 @@ fn add(function_call: &FunctionCall) -> Result> { } // Does nothing, but used for testing large parameters -#[hyperlight_guest_tracing::trace_function] fn large_parameters(function_call: &FunctionCall) -> Result> { if let (ParameterValue::VecBytes(v), ParameterValue::String(s)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -833,7 +788,6 @@ fn large_parameters(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn read_from_user_memory(function_call: &FunctionCall) -> Result> { if let (ParameterValue::ULong(num), ParameterValue::VecBytes(expected)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -859,7 +813,6 @@ fn read_from_user_memory(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn read_mapped_buffer(function_call: &FunctionCall) -> Result> { if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -883,7 +836,6 @@ fn read_mapped_buffer(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn write_mapped_buffer(function_call: &FunctionCall) -> Result> { if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -911,7 +863,6 @@ fn write_mapped_buffer(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn exec_mapped_buffer(function_call: &FunctionCall) -> Result> { if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( function_call.parameters.clone().unwrap()[0].clone(), @@ -968,7 +919,6 @@ fn call_host_expect_error(function_call: &FunctionCall) -> Result> { } #[no_mangle] -#[hyperlight_guest_tracing::trace_function] pub extern "C" fn hyperlight_main() { let expect_error_def = GuestFunctionDefinition::new( "CallHostExpectError".to_string(), @@ -1527,7 +1477,6 @@ pub extern "C" fn hyperlight_main() { register_function(use_sse2_registers); } -#[hyperlight_guest_tracing::trace_function] fn send_message_to_host_method( method_name: &str, guest_message: &str, @@ -1543,7 +1492,6 @@ fn send_message_to_host_method( Ok(get_flatbuffer_result(res)) } -#[hyperlight_guest_tracing::trace_function] fn guest_function(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("HostMethod", "Hello from GuestFunction, ", message) @@ -1555,7 +1503,6 @@ fn guest_function(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn guest_function1(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("HostMethod1", "Hello from GuestFunction1, ", message) @@ -1567,7 +1514,6 @@ fn guest_function1(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn guest_function2(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("HostMethod1", "Hello from GuestFunction2, ", message) @@ -1579,7 +1525,6 @@ fn guest_function2(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn guest_function3(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("HostMethod1", "Hello from GuestFunction3, ", message) @@ -1591,7 +1536,6 @@ fn guest_function3(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn guest_function4(_: &FunctionCall) -> Result> { call_host_function::<()>( "HostMethod4", @@ -1604,7 +1548,6 @@ fn guest_function4(_: &FunctionCall) -> Result> { Ok(get_flatbuffer_result(())) } -#[hyperlight_guest_tracing::trace_function] fn guest_log_message(function_call: &FunctionCall) -> Result> { if let ( ParameterValue::String(message), @@ -1638,7 +1581,6 @@ fn guest_log_message(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn call_error_method(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { send_message_to_host_method("ErrorMethod", "Error From Host: ", message) @@ -1650,13 +1592,11 @@ fn call_error_method(function_call: &FunctionCall) -> Result> { } } -#[hyperlight_guest_tracing::trace_function] fn call_host_spin(_: &FunctionCall) -> Result> { call_host_function::<()>("Spin", None, ReturnType::Void)?; Ok(get_flatbuffer_result(())) } -#[hyperlight_guest_tracing::trace_function] fn host_call_loop(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = &function_call.parameters.as_ref().unwrap()[0] { loop { @@ -1671,7 +1611,6 @@ fn host_call_loop(function_call: &FunctionCall) -> Result> { } // Interprets the given guest function call as a host function call and dispatches it to the host. -#[hyperlight_guest_tracing::trace_function] fn fuzz_host_function(func: FunctionCall) -> Result> { let mut params = func.parameters.unwrap(); // first parameter must be string (the name of the host function to call) @@ -1701,7 +1640,6 @@ fn fuzz_host_function(func: FunctionCall) -> Result> { } #[no_mangle] -#[hyperlight_guest_tracing::trace_function] pub fn guest_dispatch_function(function_call: FunctionCall) -> Result> { // This test checks the stack behavior of the input/output buffer // by calling the host before serializing the function call. diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index 3a0f074ae..f2c6b0dae 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -88,6 +88,12 @@ dependencies = [ "spin 0.9.8", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cc" version = "1.2.34" @@ -166,6 +172,15 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -176,6 +191,17 @@ dependencies = [ "serde", ] +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "serde", + "stable_deref_trait", +] + [[package]] name = "hyperlight-common" version = "0.10.0" @@ -244,18 +270,11 @@ dependencies = [ name = "hyperlight-guest-tracing" version = "0.10.0" dependencies = [ + "heapless", "hyperlight-common", - "hyperlight-guest-tracing-macro", "spin 0.10.0", -] - -[[package]] -name = "hyperlight-guest-tracing-macro" -version = "0.10.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "tracing", + "tracing-core", ] [[package]] @@ -342,6 +361,12 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + [[package]] name = "portable-atomic" version = "1.11.1" @@ -497,6 +522,12 @@ dependencies = [ "lock_api", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "syn" version = "2.0.107" @@ -508,6 +539,34 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" + [[package]] name = "unicode-ident" version = "1.0.18" diff --git a/src/trace_dump/main.rs b/src/trace_dump/main.rs index e6d205eb9..84f552735 100644 --- a/src/trace_dump/main.rs +++ b/src/trace_dump/main.rs @@ -25,19 +25,6 @@ use std::time::Duration; use piet_common::{Color, RenderContext, Text, TextLayout, TextLayoutBuilder, kurbo}; -fn read_u8_vec(inf: &mut File) -> Option> { - let len = read_u64(inf)?; - let mut vec = Vec::with_capacity(len as usize); - for _ in 0..len { - vec.push(read_u8(inf)?); - } - Some(vec) -} -fn read_u8(inf: &mut File) -> Option { - let mut bytes: [u8; 1] = [0; 1]; - inf.read_exact(&mut bytes).ok()?; - Some(u8::from_ne_bytes(bytes)) -} fn read_u128(inf: &mut File) -> Result { let mut bytes: [u8; 16] = [0; 16]; inf.read_exact(&mut bytes)?; @@ -105,51 +92,6 @@ fn dump_free( Some(()) } -fn dump_trace_record( - _state: &mut State, - _rs: &mut (), - indent: &mut u64, - now: Duration, - msg: Rc<[u8]>, -) -> Option<()> { - let msg = String::from_utf8_lossy(&msg); - - // Pretty-printing of trace records to show indentation based on the trace depth. - // Indentation is increased for messages starting with `>`, and decreased for messages starting - // with `<`. - // With the exception of `> halt`, which decreases the indent (because `> entrypoint` does not - // have a corresponding `< entrypoint`) - let msg = if msg.starts_with('>') { - if msg == "> halt" && *indent > 0 { - *indent -= 1; - } - let indent_str = " ".repeat(*indent as usize); - let msg = format!("{}{}", indent_str, &msg); - if msg != "> halt" { - // If the message is not `> halt`, increment the indent. - // This is to ensure that the next message is indented correctly. - *indent += 1; - } - - msg - } else if msg.starts_with('<') { - if *indent > 0 { - *indent -= 1; - } - let indent_str = " ".repeat(*indent as usize); - let msg = format!("{}{}", indent_str, msg); - - msg - } else { - let indent_str = " ".repeat(*indent as usize); - format!("{}{}", indent_str, msg) - }; - - println!("\n[{:9?}] {}", now, msg); - - Some(()) -} - // todo: this should use something more reasonable than a hash table // for each node. let's measure the out-degree and see if a small // array is better, to start. @@ -600,33 +542,20 @@ fn render_free( Some(()) } -fn render_trace_record( - _state: &mut State, - _rs: &mut RenderState, - _indent: &mut u64, - _now: Duration, - _msg: Rc<[u8]>, -) -> Option<()> { - Some(()) -} - -fn read_file( +fn read_file( state: &mut State, mut handle_state: S, handle_ident: I, handle_unwind: U, handle_alloc: A, handle_free: F, - handle_trace_record: T, ) -> Option<()> where I: Fn(&mut State, &mut S, Duration, blake3::Hash) -> Option<()>, U: Fn(&mut State, &mut S, Duration, Rc<[u64]>) -> Option<()>, A: Fn(&mut State, &mut S, Duration, u64, u64, Rc<[u64]>) -> Option<()>, F: Fn(&mut State, &mut S, Duration, u64, u64, Rc<[u64]>) -> Option<()>, - T: Fn(&mut State, &mut S, &mut u64, Duration, Rc<[u8]>) -> Option<()>, { - let mut indent = 0; loop { let time = match read_u128(&mut state.inf) { Ok(t) => t, @@ -671,9 +600,6 @@ where let trace = amt_trace.1.clone(); state.total -= amt; handle_free(state, &mut handle_state, now, ptr, amt, trace)?; - } else if frame_id == 4 { - let msg = read_u8_vec(&mut state.inf)?.into(); - handle_trace_record(state, &mut handle_state, &mut indent, now, msg)?; } else { return None; } @@ -773,7 +699,6 @@ fn spawn_render_thread( render_unwind, render_alloc, render_free, - render_trace_record, )?; bar_ffmpeg.wait().ok()?; flame_ffmpeg.wait().ok()?; @@ -830,7 +755,6 @@ fn dump_trace(mut state: State) { dump_unwind, dump_alloc, dump_free, - dump_trace_record, ); } @@ -847,7 +771,6 @@ fn plot_mem(args: Vec, mut state: State) { |_, _, _, _| Some(()), |_, _, _, _, _, _| Some(()), |_, _, _, _, _, _| Some(()), - |_, _, _, _, _| Some(()), ) { Some(()) => (), None => { @@ -886,7 +809,6 @@ fn plot_mem(args: Vec, mut state: State) { |_, _, _, _| Some(()), count_frame, count_frame, - |_, _, _, _, _| Some(()), ); if state.num_durations > 0 { (*jobs.lock().unwrap()).push((*start_duration.lock().unwrap(), state.max_duration)); From 1837342a4221313ad1602bc4f9b692ef37ec6e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Sat, 30 Aug 2025 16:14:50 +0300 Subject: [PATCH 254/271] [trace-host] refactor `mem_profile` logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Define a separate struct that holds the functionality related to memory profiling of the guest Signed-off-by: Doru Blânzeanu --- .../src/hypervisor/hyperv_linux.rs | 11 +- .../src/hypervisor/hyperv_windows.rs | 10 +- src/hyperlight_host/src/hypervisor/kvm.rs | 11 +- src/hyperlight_host/src/hypervisor/mod.rs | 4 +- src/hyperlight_host/src/sandbox/outb.rs | 6 +- src/hyperlight_host/src/sandbox/trace/mod.rs | 314 +++++++++--------- 6 files changed, 159 insertions(+), 197 deletions(-) diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index cd8afc223..5acf12fdd 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -296,6 +296,7 @@ pub(crate) struct HypervLinuxDriver { gdb_conn: Option>, #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, + #[allow(dead_code)] #[cfg(feature = "trace_guest")] trace_info: TraceInfo, } @@ -684,14 +685,6 @@ impl Hypervisor for HypervLinuxDriver { { Err(mshv_ioctls::MshvError::from(libc::EINTR)) } else { - #[cfg(feature = "trace_guest")] - if self.trace_info.guest_start_epoch.is_none() { - // Store the guest start epoch and cycles to trace the guest execution time - crate::debug!("MSHV - Guest Start Epoch set"); - self.trace_info.guest_start_tsc = - Some(hyperlight_guest_tracing::invariant_tsc::read_tsc()); - self.trace_info.guest_start_epoch = Some(std::time::Instant::now()); - } // Note: if a `InterruptHandle::kill()` called while this thread is **here** // Then the vcpu will run, but we will keep sending signals to this thread // to interrupt it until `running` is set to false. The `vcpu_fd::run()` call will @@ -1093,7 +1086,7 @@ impl Hypervisor for HypervLinuxDriver { } } - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] fn trace_info_mut(&mut self) -> &mut TraceInfo { &mut self.trace_info } diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index e506f7dea..19b5ba0ae 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -569,14 +569,6 @@ impl Hypervisor for HypervWindowsDriver { Reserved: Default::default(), } } else { - #[cfg(feature = "trace_guest")] - if self.trace_info.guest_start_epoch.is_none() { - // Store the guest start epoch and cycles to trace the guest execution time - crate::debug!("HyperV - Guest Start Epoch set"); - self.trace_info.guest_start_tsc = - Some(hyperlight_guest_tracing::invariant_tsc::read_tsc()); - self.trace_info.guest_start_epoch = Some(std::time::Instant::now()); - } self.processor.run()? }; self.interrupt_handle @@ -940,7 +932,7 @@ impl Hypervisor for HypervWindowsDriver { } } - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] fn trace_info_mut(&mut self) -> &mut TraceInfo { &mut self.trace_info } diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index cfaf442f8..a4e32322e 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -646,15 +646,6 @@ impl Hypervisor for KVMDriver { { Err(kvm_ioctls::Error::new(libc::EINTR)) } else { - #[cfg(feature = "trace_guest")] - if self.trace_info.guest_start_epoch.is_none() { - // Store the guest start epoch and cycles to trace the guest execution time - crate::debug!("KVM - Guest Start Epoch set"); - self.trace_info.guest_start_epoch = Some(std::time::Instant::now()); - self.trace_info.guest_start_tsc = - Some(hyperlight_guest_tracing::invariant_tsc::read_tsc()); - } - // Note: if a `InterruptHandle::kill()` called while this thread is **here** // Then the vcpu will run, but we will keep sending signals to this thread // to interrupt it until `running` is set to false. The `vcpu_fd::run()` call will @@ -1030,7 +1021,7 @@ impl Hypervisor for KVMDriver { } } - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] fn trace_info_mut(&mut self) -> &mut TraceInfo { &mut self.trace_info } diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index 7e8b8220b..320aa9418 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -24,7 +24,7 @@ use crate::hypervisor::regs::{ }; use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::metrics::METRIC_GUEST_CANCELLATION; -#[cfg(feature = "trace_guest")] +#[cfg(feature = "mem_profile")] use crate::sandbox::trace::TraceInfo; use crate::{HyperlightError, Result, log_then_return}; @@ -314,7 +314,7 @@ pub(crate) trait Hypervisor: Debug + Send { fn check_stack_guard(&self) -> Result; /// Get a mutable reference of the trace info for the guest - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] fn trace_info_mut(&mut self) -> &mut TraceInfo; } diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index 0e81c4be4..5d25a31d6 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -185,12 +185,14 @@ pub(crate) fn handle_outb( #[cfg(feature = "mem_profile")] OutBAction::TraceMemoryAlloc => { let regs = _hv.regs()?; - crate::sandbox::trace::handle_trace_memory_alloc(®s, mem_mgr, _hv.trace_info_mut()) + let trace_info = _hv.trace_info_mut(); + trace_info.handle_trace_mem_alloc(®s, mem_mgr) } #[cfg(feature = "mem_profile")] OutBAction::TraceMemoryFree => { let regs = _hv.regs()?; - crate::sandbox::trace::handle_trace_memory_free(®s, mem_mgr, _hv.trace_info_mut()) + let trace_info = _hv.trace_info_mut(); + trace_info.handle_trace_mem_free(®s, mem_mgr) } } } diff --git a/src/hyperlight_host/src/sandbox/trace/mod.rs b/src/hyperlight_host/src/sandbox/trace/mod.rs index 15f8a8d8c..8458b84f1 100644 --- a/src/hyperlight_host/src/sandbox/trace/mod.rs +++ b/src/hyperlight_host/src/sandbox/trace/mod.rs @@ -14,8 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -use std::sync::{Arc, Mutex}; - #[cfg(feature = "mem_profile")] use { crate::hypervisor::regs::CommonRegisters, @@ -26,53 +24,38 @@ use { fallible_iterator::FallibleIterator, framehop::Unwinder, std::io::Write, + std::sync::{Arc, Mutex}, }; -/// The information that trace collection requires in order to write -/// an accurate trace. -#[derive(Clone)] -pub(crate) struct TraceInfo { - /// The epoch against which trace events are timed; at least as - /// early as the creation of the sandbox being traced. - pub epoch: std::time::Instant, - /// The frequency of the timestamp counter. - pub tsc_freq: Option, - /// The epoch at which the guest started, if it has started. - /// This is used to calculate the time spent in the guest relative to the - /// time when the host started. - pub guest_start_epoch: Option, - /// The start guest time, in TSC cycles, for the current guest has a double purpose. - /// This field is used in two ways: - /// 1. It contains the TSC value recorded on the host when the guest started. - /// This is used to calculate the TSC frequency which is the same on the host and guest. - /// The TSC frequency is used to convert TSC values to timestamps in the trace. - /// **NOTE**: This is only used until the TSC frequency is calculated, when the first - /// records are received. - /// 2. To store the TSC value at recorded on the guest when the guest started (first record - /// received) - /// This is used to calculate the records timestamps relative to when guest started. - pub guest_start_tsc: Option, +/// The type of trace frame being recorded. +/// This is used to identify the type of frame being recorded in the trace file. +#[cfg(feature = "mem_profile")] +enum TraceFrameType { + /// A frame that records a memory allocation. + MemAlloc = 2, + /// A frame that records a memory free. + MemFree = 3, +} +/// This structure handles the memory profiling trace information. +#[cfg(feature = "mem_profile")] +struct GuestMemProfileProcessor { /// The file to which the trace is being written - #[allow(dead_code)] pub file: Arc>, /// The unwind information for the current guest #[allow(dead_code)] - #[cfg(feature = "mem_profile")] pub unwind_module: Arc, /// The framehop unwinder for the current guest - #[cfg(feature = "mem_profile")] pub unwinder: framehop::x86_64::UnwinderX86_64>, /// The framehop cache - #[cfg(feature = "mem_profile")] pub unwind_cache: Arc>, } -impl TraceInfo { - /// Create a new TraceInfo by saving the current time as the epoch - /// and generating a random filename. - pub fn new( - #[cfg(feature = "mem_profile")] unwind_module: Arc, - ) -> crate::Result { +#[cfg(feature = "mem_profile")] +impl GuestMemProfileProcessor { + fn new( + unwind_module: Arc, + start_instant: std::time::Instant, + ) -> Result { let mut path = std::env::current_dir()?; path.push("trace"); @@ -86,167 +69,168 @@ impl TraceInfo { log::info!("Creating trace file at: {}", path.display()); println!("Creating trace file at: {}", path.display()); - #[cfg(feature = "mem_profile")] let hash = unwind_module.hash(); - #[cfg(feature = "mem_profile")] let (unwinder, unwind_cache) = { let mut unwinder = framehop::x86_64::UnwinderX86_64::new(); unwinder.add_module(unwind_module.clone().as_module()); let cache = framehop::x86_64::CacheX86_64::new(); (unwinder, Arc::new(Mutex::new(cache))) }; - if !hyperlight_guest_tracing::invariant_tsc::has_invariant_tsc() { - // If the platform does not support invariant TSC, warn the user. - // On Azure nested virtualization, the TSC invariant bit is not correctly reported, this is a known issue. - log::warn!( - "Invariant TSC is not supported on this platform, trace timestamps may be inaccurate" - ); - } let ret = Self { - epoch: std::time::Instant::now(), - tsc_freq: None, - guest_start_epoch: None, - guest_start_tsc: None, file: Arc::new(Mutex::new(std::fs::File::create_new(path)?)), - #[cfg(feature = "mem_profile")] unwind_module, - #[cfg(feature = "mem_profile")] unwinder, - #[cfg(feature = "mem_profile")] unwind_cache, }; + /* write a frame identifying the binary */ - #[cfg(feature = "mem_profile")] - record_trace_frame(&ret, 0, |f| { + ret.record_trace_frame(start_instant, 0, |f| { let _ = f.write_all(hash.as_bytes()); })?; + Ok(ret) } - /// Calculate the TSC frequency based on the RDTSC instruction on the host. - pub(crate) fn calculate_tsc_freq(&mut self) -> crate::Result<()> { - let (start, start_time) = match ( - self.guest_start_tsc.as_ref(), - self.guest_start_epoch.as_ref(), - ) { - (Some(start), Some(start_time)) => (*start, *start_time), - _ => { - // If the guest start TSC and time are not set, we use the current time and TSC. - // This is not ideal, but it allows us to calculate the TSC frequency without - // failing. - // This is a fallback mechanism to ensure that we can still calculate, however it - // should be noted that this may lead to inaccuracies in the TSC frequency. - // The start time should be already set before running the guest for each sandbox. - log::error!( - "Guest start TSC and time are not set. Calculating TSC frequency will use current time and TSC." - ); - ( - hyperlight_guest_tracing::invariant_tsc::read_tsc(), - std::time::Instant::now(), - ) - } + fn unwind( + &self, + regs: &CommonRegisters, + mem_mgr: &SandboxMemoryManager, + ) -> Result> { + let mut read_stack = |addr| { + mem_mgr + .shared_mem + .read::((addr - SandboxMemoryLayout::BASE_ADDRESS as u64) as usize) + .map_err(|_| ()) }; + let mut cache = self + .unwind_cache + .try_lock() + .map_err(|e| new_error!("could not lock unwinder cache {}\n", e))?; + let iter = self.unwinder.iter_frames( + regs.rip, + framehop::x86_64::UnwindRegsX86_64::new(regs.rip, regs.rsp, regs.rbp), + &mut *cache, + &mut read_stack, + ); + iter.map(|f| Ok(f.address() - mem_mgr.layout.get_guest_code_address() as u64)) + .collect() + .map_err(|e| new_error!("couldn't unwind: {}", e)) + } - let end_time = std::time::Instant::now(); - let end = hyperlight_guest_tracing::invariant_tsc::read_tsc(); + fn write_stack(&self, out: &mut std::fs::File, stack: &[u64]) { + let _ = out.write_all(&stack.len().to_ne_bytes()); + for frame in stack { + let _ = out.write_all(&frame.to_ne_bytes()); + } + } - let elapsed = end_time.duration_since(start_time).as_secs_f64(); - let tsc_freq = ((end - start) as f64 / elapsed) as u64; + fn record_trace_frame( + &self, + start_instant: std::time::Instant, + frame_id: u64, + write_frame: F, + ) -> Result<()> { + let Ok(mut out) = self.file.lock() else { + return Ok(()); + }; + // frame structure: + // 16 bytes timestamp + let now = std::time::Instant::now().saturating_duration_since(start_instant); + let _ = out.write_all(&now.as_micros().to_ne_bytes()); + // 8 bytes frame type id + let _ = out.write_all(&frame_id.to_ne_bytes()); + // frame data + write_frame(&mut out); + Ok(()) + } - log::info!("Calculated TSC frequency: {} Hz", tsc_freq); - self.tsc_freq = Some(tsc_freq); + fn handle_trace( + &self, + start_instant: std::time::Instant, + regs: &CommonRegisters, + mem_mgr: &SandboxMemoryManager, + trace_identifier: TraceFrameType, + ) -> Result<()> { + let Ok(stack) = self.unwind(regs, mem_mgr) else { + return Ok(()); + }; - Ok(()) + let amt = regs.rax; + let ptr = regs.rcx; + + self.record_trace_frame(start_instant, trace_identifier as u64, |f| { + let _ = f.write_all(&ptr.to_ne_bytes()); + let _ = f.write_all(&amt.to_ne_bytes()); + self.write_stack(f, &stack); + }) } -} -#[cfg(feature = "mem_profile")] -fn unwind( - regs: &CommonRegisters, - mem: &SandboxMemoryManager, - trace_info: &TraceInfo, -) -> Result> { - let mut read_stack = |addr| { - mem.shared_mem - .read::((addr - SandboxMemoryLayout::BASE_ADDRESS as u64) as usize) - .map_err(|_| ()) - }; - let mut cache = trace_info - .unwind_cache - .try_lock() - .map_err(|e| new_error!("could not lock unwinder cache {}\n", e))?; - let iter = trace_info.unwinder.iter_frames( - regs.rip, - framehop::x86_64::UnwindRegsX86_64::new(regs.rip, regs.rsp, regs.rbp), - &mut *cache, - &mut read_stack, - ); - iter.map(|f| Ok(f.address() - mem.layout.get_guest_code_address() as u64)) - .collect() - .map_err(|e| new_error!("couldn't unwind: {}", e)) -} + fn handle_trace_mem_alloc( + &self, + start_instant: std::time::Instant, + regs: &CommonRegisters, + mem_mgr: &SandboxMemoryManager, + ) -> Result<()> { + self.handle_trace(start_instant, regs, mem_mgr, TraceFrameType::MemAlloc) + } -#[cfg(feature = "mem_profile")] -fn write_stack(out: &mut std::fs::File, stack: &[u64]) { - let _ = out.write_all(&stack.len().to_ne_bytes()); - for frame in stack { - let _ = out.write_all(&frame.to_ne_bytes()); + fn handle_trace_mem_free( + &self, + start_instant: std::time::Instant, + regs: &CommonRegisters, + mem_mgr: &SandboxMemoryManager, + ) -> Result<()> { + self.handle_trace(start_instant, regs, mem_mgr, TraceFrameType::MemFree) } } -#[cfg(feature = "mem_profile")] -fn record_trace_frame( - trace_info: &TraceInfo, - frame_id: u64, - write_frame: F, -) -> Result<()> { - let Ok(mut out) = trace_info.file.lock() else { - return Ok(()); - }; - // frame structure: - // 16 bytes timestamp - let now = std::time::Instant::now().saturating_duration_since(trace_info.epoch); - let _ = out.write_all(&now.as_micros().to_ne_bytes()); - // 8 bytes frame type id - let _ = out.write_all(&frame_id.to_ne_bytes()); - // frame data - write_frame(&mut out); - Ok(()) +/// The information that trace collection requires in order to write +/// an accurate trace. +pub(crate) struct TraceInfo { + /// The epoch against which trace events are timed; at least as + /// early as the creation of the sandbox being traced. + #[cfg(feature = "mem_profile")] + epoch: std::time::Instant, + #[cfg(feature = "mem_profile")] + mem_profile: GuestMemProfileProcessor, } -#[cfg(feature = "mem_profile")] -pub(crate) fn handle_trace_memory_alloc( - regs: &CommonRegisters, - mem_mgr: &SandboxMemoryManager, - trace_info: &TraceInfo, -) -> Result<()> { - let Ok(stack) = unwind(regs, mem_mgr, trace_info) else { - return Ok(()); - }; - let amt = regs.rax; - let ptr = regs.rcx; - - record_trace_frame(trace_info, 2u64, |f| { - let _ = f.write_all(&ptr.to_ne_bytes()); - let _ = f.write_all(&amt.to_ne_bytes()); - write_stack(f, &stack); - }) -} +impl TraceInfo { + /// Create a new TraceInfo by saving the current time as the epoch + /// and generating a random filename. + pub(crate) fn new( + #[cfg(feature = "mem_profile")] unwind_module: Arc, + ) -> crate::Result { + #[cfg(feature = "mem_profile")] + let epoch = std::time::Instant::now(); + Ok(Self { + #[cfg(feature = "mem_profile")] + epoch, + #[cfg(feature = "mem_profile")] + mem_profile: GuestMemProfileProcessor::new(unwind_module, epoch)?, + }) + } -#[cfg(feature = "mem_profile")] -pub(crate) fn handle_trace_memory_free( - regs: &CommonRegisters, - mem_mgr: &SandboxMemoryManager, - trace_info: &TraceInfo, -) -> Result<()> { - let Ok(stack) = unwind(regs, mem_mgr, trace_info) else { - return Ok(()); - }; - let ptr = regs.rcx; - - record_trace_frame(trace_info, 3u64, |f| { - let _ = f.write_all(&ptr.to_ne_bytes()); - write_stack(f, &stack); - }) + #[inline(always)] + #[cfg(feature = "mem_profile")] + pub(crate) fn handle_trace_mem_alloc( + &self, + regs: &CommonRegisters, + mem_mgr: &SandboxMemoryManager, + ) -> Result<()> { + self.mem_profile + .handle_trace_mem_alloc(self.epoch, regs, mem_mgr) + } + + #[inline(always)] + #[cfg(feature = "mem_profile")] + pub(crate) fn handle_trace_mem_free( + &self, + regs: &CommonRegisters, + mem_mgr: &SandboxMemoryManager, + ) -> Result<()> { + self.mem_profile + .handle_trace_mem_free(self.epoch, regs, mem_mgr) + } } From e734010def0191f35aa0d6ecad729a5fee5ad4ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Wed, 10 Sep 2025 21:37:49 +0300 Subject: [PATCH 255/271] [trace-host] move mem_profile logic to different file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename TraceInfo to reflect only being used by mem_profile Signed-off-by: Doru Blânzeanu --- .../src/hypervisor/hyperv_linux.rs | 26 +-- .../src/hypervisor/hyperv_windows.rs | 18 +- src/hyperlight_host/src/hypervisor/kvm.rs | 18 +- src/hyperlight_host/src/hypervisor/mod.rs | 4 +- src/hyperlight_host/src/sandbox/outb.rs | 4 +- .../src/sandbox/trace/mem_profile.rs | 182 +++++++++++++++ src/hyperlight_host/src/sandbox/trace/mod.rs | 221 +----------------- .../src/sandbox/uninitialized_evolve.rs | 17 +- 8 files changed, 225 insertions(+), 265 deletions(-) create mode 100644 src/hyperlight_host/src/sandbox/trace/mem_profile.rs diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 5acf12fdd..8b72e3d0b 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -70,8 +70,8 @@ use crate::mem::shared_mem::HostSharedMemory; use crate::sandbox::SandboxConfiguration; use crate::sandbox::host_funcs::FunctionRegistry; use crate::sandbox::outb::handle_outb; -#[cfg(feature = "trace_guest")] -use crate::sandbox::trace::TraceInfo; +#[cfg(feature = "mem_profile")] +use crate::sandbox::trace::MemTraceInfo; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; use crate::{Result, log_then_return, new_error}; @@ -297,8 +297,8 @@ pub(crate) struct HypervLinuxDriver { #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, #[allow(dead_code)] - #[cfg(feature = "trace_guest")] - trace_info: TraceInfo, + #[cfg(feature = "mem_profile")] + trace_info: MemTraceInfo, } impl HypervLinuxDriver { @@ -321,7 +321,7 @@ impl HypervLinuxDriver { config: &SandboxConfiguration, #[cfg(gdb)] gdb_conn: Option>, #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, - #[cfg(feature = "trace_guest")] trace_info: TraceInfo, + #[cfg(feature = "mem_profile")] trace_info: MemTraceInfo, ) -> Result { let mshv = Mshv::new()?; let pr = Default::default(); @@ -429,7 +429,7 @@ impl HypervLinuxDriver { gdb_conn, #[cfg(crashdump)] rt_cfg, - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] trace_info, }; @@ -595,7 +595,7 @@ impl Hypervisor for HypervLinuxDriver { padded[..copy_len].copy_from_slice(&data[..copy_len]); let val = u32::from_le_bytes(padded); - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] { // We need to handle the borrow checker issue where we need both: // - &mut SandboxMemoryManager (from self.mem_mgr) @@ -616,7 +616,7 @@ impl Hypervisor for HypervLinuxDriver { self.mem_mgr = Some(mem_mgr); } - #[cfg(not(feature = "trace_guest"))] + #[cfg(not(feature = "mem_profile"))] { let mem_mgr = self .mem_mgr @@ -1087,7 +1087,7 @@ impl Hypervisor for HypervLinuxDriver { } #[cfg(feature = "mem_profile")] - fn trace_info_mut(&mut self) -> &mut TraceInfo { + fn trace_info_mut(&mut self) -> &mut MemTraceInfo { &mut self.trace_info } } @@ -1178,12 +1178,8 @@ mod tests { #[cfg(crashdump)] guest_core_dump: true, }, - #[cfg(feature = "trace_guest")] - TraceInfo::new( - #[cfg(feature = "mem_profile")] - Arc::new(DummyUnwindInfo {}), - ) - .unwrap(), + #[cfg(feature = "mem_profile")] + MemTraceInfo::new(Arc::new(DummyUnwindInfo {})).unwrap(), ) .unwrap(); } diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index 19b5ba0ae..4603a3f93 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -49,10 +49,10 @@ use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::ptr::{GuestPtr, RawPtr}; use crate::mem::shared_mem::HostSharedMemory; -#[cfg(feature = "trace_guest")] -use crate::sandbox::TraceInfo; use crate::sandbox::host_funcs::FunctionRegistry; use crate::sandbox::outb::handle_outb; +#[cfg(feature = "mem_profile")] +use crate::sandbox::trace::MemTraceInfo; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; use crate::{Result, debug, log_then_return, new_error}; @@ -274,9 +274,9 @@ pub(crate) struct HypervWindowsDriver { gdb_conn: Option>, #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] #[allow(dead_code)] - trace_info: TraceInfo, + trace_info: MemTraceInfo, } /* This does not automatically impl Send because the host * address of the shared memory region is a raw pointer, which are @@ -298,7 +298,7 @@ impl HypervWindowsDriver { mmap_file_handle: HandleWrapper, #[cfg(gdb)] gdb_conn: Option>, #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, - #[cfg(feature = "trace_guest")] trace_info: TraceInfo, + #[cfg(feature = "mem_profile")] trace_info: MemTraceInfo, ) -> Result { // create and setup hypervisor partition let mut partition = VMPartition::new(1)?; @@ -350,7 +350,7 @@ impl HypervWindowsDriver { gdb_conn, #[cfg(crashdump)] rt_cfg, - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] trace_info, }; @@ -502,7 +502,7 @@ impl Hypervisor for HypervWindowsDriver { padded[..copy_len].copy_from_slice(&data[..copy_len]); let val = u32::from_le_bytes(padded); - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] { // We need to handle the borrow checker issue where we need both: // - &mut SandboxMemoryManager (from self.mem_mgr.as_mut()) @@ -523,7 +523,7 @@ impl Hypervisor for HypervWindowsDriver { self.mem_mgr = Some(mem_mgr); } - #[cfg(not(feature = "trace_guest"))] + #[cfg(not(feature = "mem_profile"))] { let mem_mgr = self .mem_mgr @@ -933,7 +933,7 @@ impl Hypervisor for HypervWindowsDriver { } #[cfg(feature = "mem_profile")] - fn trace_info_mut(&mut self) -> &mut TraceInfo { + fn trace_info_mut(&mut self) -> &mut MemTraceInfo { &mut self.trace_info } } diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index a4e32322e..da7e4e4d1 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -43,8 +43,8 @@ use crate::mem::shared_mem::HostSharedMemory; use crate::sandbox::SandboxConfiguration; use crate::sandbox::host_funcs::FunctionRegistry; use crate::sandbox::outb::handle_outb; -#[cfg(feature = "trace_guest")] -use crate::sandbox::trace::TraceInfo; +#[cfg(feature = "mem_profile")] +use crate::sandbox::trace::MemTraceInfo; #[cfg(crashdump)] use crate::sandbox::uninitialized::SandboxRuntimeConfig; use crate::{Result, log_then_return, new_error}; @@ -284,9 +284,9 @@ pub(crate) struct KVMDriver { gdb_conn: Option>, #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] #[allow(dead_code)] - trace_info: TraceInfo, + trace_info: MemTraceInfo, } impl KVMDriver { @@ -304,7 +304,7 @@ impl KVMDriver { config: &SandboxConfiguration, #[cfg(gdb)] gdb_conn: Option>, #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, - #[cfg(feature = "trace_guest")] trace_info: TraceInfo, + #[cfg(feature = "mem_profile")] trace_info: MemTraceInfo, ) -> Result { let kvm = Kvm::new()?; @@ -375,7 +375,7 @@ impl KVMDriver { gdb_conn, #[cfg(crashdump)] rt_cfg, - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] trace_info, }; @@ -572,7 +572,7 @@ impl Hypervisor for KVMDriver { padded[..copy_len].copy_from_slice(&data[..copy_len]); let value = u32::from_le_bytes(padded); - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] { // We need to handle the borrow checker issue where we need both: // - &mut SandboxMemoryManager (from self.mem_mgr.as_mut()) @@ -593,7 +593,7 @@ impl Hypervisor for KVMDriver { self.mem_mgr = Some(mem_mgr); } - #[cfg(not(feature = "trace_guest"))] + #[cfg(not(feature = "mem_profile"))] { let mem_mgr = self .mem_mgr @@ -1022,7 +1022,7 @@ impl Hypervisor for KVMDriver { } #[cfg(feature = "mem_profile")] - fn trace_info_mut(&mut self) -> &mut TraceInfo { + fn trace_info_mut(&mut self) -> &mut MemTraceInfo { &mut self.trace_info } } diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index 320aa9418..cf8899d96 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -25,7 +25,7 @@ use crate::hypervisor::regs::{ use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::metrics::METRIC_GUEST_CANCELLATION; #[cfg(feature = "mem_profile")] -use crate::sandbox::trace::TraceInfo; +use crate::sandbox::trace::MemTraceInfo; use crate::{HyperlightError, Result, log_then_return}; /// HyperV-on-linux functionality @@ -315,7 +315,7 @@ pub(crate) trait Hypervisor: Debug + Send { /// Get a mutable reference of the trace info for the guest #[cfg(feature = "mem_profile")] - fn trace_info_mut(&mut self) -> &mut TraceInfo; + fn trace_info_mut(&mut self) -> &mut MemTraceInfo; } /// Returns a Some(HyperlightExit::AccessViolation(..)) if the given gpa doesn't have diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index 5d25a31d6..e3bacedb7 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -25,7 +25,7 @@ use tracing::{Span, instrument}; use tracing_log::format_trace; use super::host_funcs::FunctionRegistry; -#[cfg(feature = "trace_guest")] +#[cfg(feature = "mem_profile")] use crate::hypervisor::Hypervisor; use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::HostSharedMemory; @@ -148,7 +148,7 @@ fn outb_abort(mem_mgr: &mut SandboxMemoryManager, data: u32) - pub(crate) fn handle_outb( mem_mgr: &mut SandboxMemoryManager, host_funcs: Arc>, - #[cfg(feature = "trace_guest")] _hv: &mut dyn Hypervisor, + #[cfg(feature = "mem_profile")] _hv: &mut dyn Hypervisor, port: u16, data: u32, ) -> Result<()> { diff --git a/src/hyperlight_host/src/sandbox/trace/mem_profile.rs b/src/hyperlight_host/src/sandbox/trace/mem_profile.rs new file mode 100644 index 000000000..89ff7b24b --- /dev/null +++ b/src/hyperlight_host/src/sandbox/trace/mem_profile.rs @@ -0,0 +1,182 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +use std::io::Write; +use std::sync::{Arc, Mutex}; + +use fallible_iterator::FallibleIterator; +use framehop::Unwinder; + +use crate::hypervisor::regs::CommonRegisters; +use crate::mem::layout::SandboxMemoryLayout; +use crate::mem::mgr::SandboxMemoryManager; +use crate::mem::shared_mem::HostSharedMemory; +use crate::{Result, new_error}; + +/// The type of trace frame being recorded. +/// This is used to identify the type of frame being recorded in the trace file. +enum TraceFrameType { + /// A frame that records a memory allocation. + MemAlloc = 2, + /// A frame that records a memory free. + MemFree = 3, +} + +/// This structure handles the memory profiling trace information. +pub(crate) struct MemTraceInfo { + /// The epoch against which trace events are timed; at least as + /// early as the creation of the sandbox being traced. + epoch: std::time::Instant, + /// The file to which the trace is being written + pub file: Arc>, + /// The unwind information for the current guest + #[allow(dead_code)] + pub unwind_module: Arc, + /// The framehop unwinder for the current guest + pub unwinder: framehop::x86_64::UnwinderX86_64>, + /// The framehop cache + pub unwind_cache: Arc>, +} + +impl MemTraceInfo { + pub fn new(unwind_module: Arc) -> Result { + let mut path = std::env::current_dir()?; + path.push("trace"); + + // create directory if it does not exist + if !path.exists() { + std::fs::create_dir(&path)?; + } + path.push(uuid::Uuid::new_v4().to_string()); + path.set_extension("trace"); + + log::info!("Creating trace file at: {}", path.display()); + println!("Creating trace file at: {}", path.display()); + + let hash = unwind_module.hash(); + let (unwinder, unwind_cache) = { + let mut unwinder = framehop::x86_64::UnwinderX86_64::new(); + unwinder.add_module(unwind_module.clone().as_module()); + let cache = framehop::x86_64::CacheX86_64::new(); + (unwinder, Arc::new(Mutex::new(cache))) + }; + + let ret = Self { + epoch: std::time::Instant::now(), + file: Arc::new(Mutex::new(std::fs::File::create_new(path)?)), + unwind_module, + unwinder, + unwind_cache, + }; + + /* write a frame identifying the binary */ + ret.record_trace_frame(ret.epoch, 0, |f| { + let _ = f.write_all(hash.as_bytes()); + })?; + + Ok(ret) + } + + fn unwind( + &self, + regs: &CommonRegisters, + mem_mgr: &SandboxMemoryManager, + ) -> Result> { + let mut read_stack = |addr| { + mem_mgr + .shared_mem + .read::((addr - SandboxMemoryLayout::BASE_ADDRESS as u64) as usize) + .map_err(|_| ()) + }; + let mut cache = self + .unwind_cache + .try_lock() + .map_err(|e| new_error!("could not lock unwinder cache {}\n", e))?; + let iter = self.unwinder.iter_frames( + regs.rip, + framehop::x86_64::UnwindRegsX86_64::new(regs.rip, regs.rsp, regs.rbp), + &mut *cache, + &mut read_stack, + ); + iter.map(|f| Ok(f.address() - mem_mgr.layout.get_guest_code_address() as u64)) + .collect() + .map_err(|e| new_error!("couldn't unwind: {}", e)) + } + + fn write_stack(&self, out: &mut std::fs::File, stack: &[u64]) { + let _ = out.write_all(&stack.len().to_ne_bytes()); + for frame in stack { + let _ = out.write_all(&frame.to_ne_bytes()); + } + } + + fn record_trace_frame( + &self, + start_instant: std::time::Instant, + frame_id: u64, + write_frame: F, + ) -> Result<()> { + let Ok(mut out) = self.file.lock() else { + return Ok(()); + }; + // frame structure: + // 16 bytes timestamp + let now = std::time::Instant::now().saturating_duration_since(start_instant); + let _ = out.write_all(&now.as_micros().to_ne_bytes()); + // 8 bytes frame type id + let _ = out.write_all(&frame_id.to_ne_bytes()); + // frame data + write_frame(&mut out); + Ok(()) + } + + fn handle_trace( + &self, + regs: &CommonRegisters, + mem_mgr: &SandboxMemoryManager, + trace_identifier: TraceFrameType, + ) -> Result<()> { + let Ok(stack) = self.unwind(regs, mem_mgr) else { + return Ok(()); + }; + + let amt = regs.rax; + let ptr = regs.rcx; + + self.record_trace_frame(self.epoch, trace_identifier as u64, |f| { + let _ = f.write_all(&ptr.to_ne_bytes()); + let _ = f.write_all(&amt.to_ne_bytes()); + self.write_stack(f, &stack); + }) + } + + #[inline(always)] + pub(crate) fn handle_trace_mem_alloc( + &self, + regs: &CommonRegisters, + mem_mgr: &SandboxMemoryManager, + ) -> Result<()> { + self.handle_trace(regs, mem_mgr, TraceFrameType::MemAlloc) + } + + #[inline(always)] + pub(crate) fn handle_trace_mem_free( + &self, + regs: &CommonRegisters, + mem_mgr: &SandboxMemoryManager, + ) -> Result<()> { + self.handle_trace(regs, mem_mgr, TraceFrameType::MemFree) + } +} diff --git a/src/hyperlight_host/src/sandbox/trace/mod.rs b/src/hyperlight_host/src/sandbox/trace/mod.rs index 8458b84f1..47ffd9125 100644 --- a/src/hyperlight_host/src/sandbox/trace/mod.rs +++ b/src/hyperlight_host/src/sandbox/trace/mod.rs @@ -14,223 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ +/// Tracing and profiling support for sandboxes. #[cfg(feature = "mem_profile")] -use { - crate::hypervisor::regs::CommonRegisters, - crate::mem::layout::SandboxMemoryLayout, - crate::mem::mgr::SandboxMemoryManager, - crate::mem::shared_mem::HostSharedMemory, - crate::{Result, new_error}, - fallible_iterator::FallibleIterator, - framehop::Unwinder, - std::io::Write, - std::sync::{Arc, Mutex}, -}; - -/// The type of trace frame being recorded. -/// This is used to identify the type of frame being recorded in the trace file. -#[cfg(feature = "mem_profile")] -enum TraceFrameType { - /// A frame that records a memory allocation. - MemAlloc = 2, - /// A frame that records a memory free. - MemFree = 3, -} -/// This structure handles the memory profiling trace information. -#[cfg(feature = "mem_profile")] -struct GuestMemProfileProcessor { - /// The file to which the trace is being written - pub file: Arc>, - /// The unwind information for the current guest - #[allow(dead_code)] - pub unwind_module: Arc, - /// The framehop unwinder for the current guest - pub unwinder: framehop::x86_64::UnwinderX86_64>, - /// The framehop cache - pub unwind_cache: Arc>, -} - +mod mem_profile; #[cfg(feature = "mem_profile")] -impl GuestMemProfileProcessor { - fn new( - unwind_module: Arc, - start_instant: std::time::Instant, - ) -> Result { - let mut path = std::env::current_dir()?; - path.push("trace"); - - // create directory if it does not exist - if !path.exists() { - std::fs::create_dir(&path)?; - } - path.push(uuid::Uuid::new_v4().to_string()); - path.set_extension("trace"); - - log::info!("Creating trace file at: {}", path.display()); - println!("Creating trace file at: {}", path.display()); - - let hash = unwind_module.hash(); - let (unwinder, unwind_cache) = { - let mut unwinder = framehop::x86_64::UnwinderX86_64::new(); - unwinder.add_module(unwind_module.clone().as_module()); - let cache = framehop::x86_64::CacheX86_64::new(); - (unwinder, Arc::new(Mutex::new(cache))) - }; - - let ret = Self { - file: Arc::new(Mutex::new(std::fs::File::create_new(path)?)), - unwind_module, - unwinder, - unwind_cache, - }; - - /* write a frame identifying the binary */ - ret.record_trace_frame(start_instant, 0, |f| { - let _ = f.write_all(hash.as_bytes()); - })?; - - Ok(ret) - } - - fn unwind( - &self, - regs: &CommonRegisters, - mem_mgr: &SandboxMemoryManager, - ) -> Result> { - let mut read_stack = |addr| { - mem_mgr - .shared_mem - .read::((addr - SandboxMemoryLayout::BASE_ADDRESS as u64) as usize) - .map_err(|_| ()) - }; - let mut cache = self - .unwind_cache - .try_lock() - .map_err(|e| new_error!("could not lock unwinder cache {}\n", e))?; - let iter = self.unwinder.iter_frames( - regs.rip, - framehop::x86_64::UnwindRegsX86_64::new(regs.rip, regs.rsp, regs.rbp), - &mut *cache, - &mut read_stack, - ); - iter.map(|f| Ok(f.address() - mem_mgr.layout.get_guest_code_address() as u64)) - .collect() - .map_err(|e| new_error!("couldn't unwind: {}", e)) - } - - fn write_stack(&self, out: &mut std::fs::File, stack: &[u64]) { - let _ = out.write_all(&stack.len().to_ne_bytes()); - for frame in stack { - let _ = out.write_all(&frame.to_ne_bytes()); - } - } - - fn record_trace_frame( - &self, - start_instant: std::time::Instant, - frame_id: u64, - write_frame: F, - ) -> Result<()> { - let Ok(mut out) = self.file.lock() else { - return Ok(()); - }; - // frame structure: - // 16 bytes timestamp - let now = std::time::Instant::now().saturating_duration_since(start_instant); - let _ = out.write_all(&now.as_micros().to_ne_bytes()); - // 8 bytes frame type id - let _ = out.write_all(&frame_id.to_ne_bytes()); - // frame data - write_frame(&mut out); - Ok(()) - } - - fn handle_trace( - &self, - start_instant: std::time::Instant, - regs: &CommonRegisters, - mem_mgr: &SandboxMemoryManager, - trace_identifier: TraceFrameType, - ) -> Result<()> { - let Ok(stack) = self.unwind(regs, mem_mgr) else { - return Ok(()); - }; - - let amt = regs.rax; - let ptr = regs.rcx; - - self.record_trace_frame(start_instant, trace_identifier as u64, |f| { - let _ = f.write_all(&ptr.to_ne_bytes()); - let _ = f.write_all(&amt.to_ne_bytes()); - self.write_stack(f, &stack); - }) - } - - fn handle_trace_mem_alloc( - &self, - start_instant: std::time::Instant, - regs: &CommonRegisters, - mem_mgr: &SandboxMemoryManager, - ) -> Result<()> { - self.handle_trace(start_instant, regs, mem_mgr, TraceFrameType::MemAlloc) - } - - fn handle_trace_mem_free( - &self, - start_instant: std::time::Instant, - regs: &CommonRegisters, - mem_mgr: &SandboxMemoryManager, - ) -> Result<()> { - self.handle_trace(start_instant, regs, mem_mgr, TraceFrameType::MemFree) - } -} - -/// The information that trace collection requires in order to write -/// an accurate trace. -pub(crate) struct TraceInfo { - /// The epoch against which trace events are timed; at least as - /// early as the creation of the sandbox being traced. - #[cfg(feature = "mem_profile")] - epoch: std::time::Instant, - #[cfg(feature = "mem_profile")] - mem_profile: GuestMemProfileProcessor, -} - -impl TraceInfo { - /// Create a new TraceInfo by saving the current time as the epoch - /// and generating a random filename. - pub(crate) fn new( - #[cfg(feature = "mem_profile")] unwind_module: Arc, - ) -> crate::Result { - #[cfg(feature = "mem_profile")] - let epoch = std::time::Instant::now(); - Ok(Self { - #[cfg(feature = "mem_profile")] - epoch, - #[cfg(feature = "mem_profile")] - mem_profile: GuestMemProfileProcessor::new(unwind_module, epoch)?, - }) - } - - #[inline(always)] - #[cfg(feature = "mem_profile")] - pub(crate) fn handle_trace_mem_alloc( - &self, - regs: &CommonRegisters, - mem_mgr: &SandboxMemoryManager, - ) -> Result<()> { - self.mem_profile - .handle_trace_mem_alloc(self.epoch, regs, mem_mgr) - } - - #[inline(always)] - #[cfg(feature = "mem_profile")] - pub(crate) fn handle_trace_mem_free( - &self, - regs: &CommonRegisters, - mem_mgr: &SandboxMemoryManager, - ) -> Result<()> { - self.mem_profile - .handle_trace_mem_free(self.epoch, regs, mem_mgr) - } -} +pub(crate) use mem_profile::MemTraceInfo; diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index 92030138a..d1ba71ef9 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -36,8 +36,8 @@ use crate::mem::shared_mem::GuestSharedMemory; use crate::mem::shared_mem::SharedMemory; #[cfg(gdb)] use crate::sandbox::config::DebugInfo; -#[cfg(feature = "trace_guest")] -use crate::sandbox::trace::TraceInfo; +#[cfg(feature = "mem_profile")] +use crate::sandbox::trace::MemTraceInfo; #[cfg(target_os = "linux")] use crate::signal_handlers::setup_signal_handlers; use crate::{MultiUseSandbox, Result, UninitializedSandbox, log_then_return, new_error}; @@ -164,11 +164,8 @@ pub(crate) fn set_up_hypervisor_partition( None }; - #[cfg(feature = "trace_guest")] - let trace_info = TraceInfo::new( - #[cfg(feature = "mem_profile")] - _load_info, - )?; + #[cfg(feature = "mem_profile")] + let trace_info = MemTraceInfo::new(_load_info)?; match *get_available_hypervisor() { #[cfg(mshv)] @@ -183,7 +180,7 @@ pub(crate) fn set_up_hypervisor_partition( gdb_conn, #[cfg(crashdump)] rt_cfg.clone(), - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] trace_info, )?; Ok(Box::new(hv)) @@ -201,7 +198,7 @@ pub(crate) fn set_up_hypervisor_partition( gdb_conn, #[cfg(crashdump)] rt_cfg.clone(), - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] trace_info, )?; Ok(Box::new(hv)) @@ -225,7 +222,7 @@ pub(crate) fn set_up_hypervisor_partition( gdb_conn, #[cfg(crashdump)] rt_cfg.clone(), - #[cfg(feature = "trace_guest")] + #[cfg(feature = "mem_profile")] trace_info, )?; Ok(Box::new(hv)) From e4a0785f352c72b94cba2cce0cd9ac25af4ff2c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Wed, 10 Sep 2025 23:21:54 +0300 Subject: [PATCH 256/271] [trace-guest] move invariant_tsc logic to separate module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- .../src/invariant_tsc.rs | 47 +++++++++++++++++++ src/hyperlight_guest_tracing/src/lib.rs | 37 ++------------- 2 files changed, 51 insertions(+), 33 deletions(-) create mode 100644 src/hyperlight_guest_tracing/src/invariant_tsc.rs diff --git a/src/hyperlight_guest_tracing/src/invariant_tsc.rs b/src/hyperlight_guest_tracing/src/invariant_tsc.rs new file mode 100644 index 000000000..13521f906 --- /dev/null +++ b/src/hyperlight_guest_tracing/src/invariant_tsc.rs @@ -0,0 +1,47 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/// Module for checking invariant TSC support and reading the timestamp counter +use core::arch::x86_64::{__cpuid, _rdtsc}; + +/// Check if the processor supports invariant TSC +/// +/// Returns true if CPUID.80000007H:EDX[8] is set, indicating invariant TSC support +pub fn has_invariant_tsc() -> bool { + // Check if extended CPUID functions are available + let max_extended = unsafe { __cpuid(0x80000000) }; + if max_extended.eax < 0x80000007 { + return false; + } + + // Query CPUID.80000007H for invariant TSC support + let cpuid_result = unsafe { __cpuid(0x80000007) }; + + // Check bit 8 of EDX register for invariant TSC support + (cpuid_result.edx & (1 << 8)) != 0 +} + +/// Read the timestamp counter +/// +/// This function provides a high-performance timestamp by reading the TSC. +/// Should only be used when invariant TSC is supported for reliable timing. +/// +/// # Safety +/// This function uses unsafe assembly instructions but is safe to call. +/// However, the resulting timestamp is only meaningful if invariant TSC is supported. +pub fn read_tsc() -> u64 { + unsafe { _rdtsc() } +} diff --git a/src/hyperlight_guest_tracing/src/lib.rs b/src/hyperlight_guest_tracing/src/lib.rs index b92444aea..d062fccd2 100644 --- a/src/hyperlight_guest_tracing/src/lib.rs +++ b/src/hyperlight_guest_tracing/src/lib.rs @@ -13,38 +13,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -#![no_std] - -/// Module for checking invariant TSC support and reading the timestamp counter -pub mod invariant_tsc { - use core::arch::x86_64::{__cpuid, _rdtsc}; - - /// Check if the processor supports invariant TSC - /// - /// Returns true if CPUID.80000007H:EDX[8] is set, indicating invariant TSC support - pub fn has_invariant_tsc() -> bool { - // Check if extended CPUID functions are available - let max_extended = unsafe { __cpuid(0x80000000) }; - if max_extended.eax < 0x80000007 { - return false; - } - // Query CPUID.80000007H for invariant TSC support - let cpuid_result = unsafe { __cpuid(0x80000007) }; - - // Check bit 8 of EDX register for invariant TSC support - (cpuid_result.edx & (1 << 8)) != 0 - } +#![no_std] +use heapless as hl; - /// Read the timestamp counter - /// - /// This function provides a high-performance timestamp by reading the TSC. - /// Should only be used when invariant TSC is supported for reliable timing. - /// - /// # Safety - /// This function uses unsafe assembly instructions but is safe to call. - /// However, the resulting timestamp is only meaningful if invariant TSC is supported. - pub fn read_tsc() -> u64 { - unsafe { _rdtsc() } - } -} +/// Expose invariant TSC module +pub mod invariant_tsc; From 9e63e545a29be0df1243a706c55fedbd8f2b1ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Wed, 10 Sep 2025 23:40:33 +0300 Subject: [PATCH 257/271] [trace-guest] add Subscriber to capture traces/events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Adds a type that implements the Subscriber trait of the tracing_core crate that allows the type to be set as the global Subscriber of the crate - This way we can handle the adding of new spans and events and store them where/how we want Signed-off-by: Doru Blânzeanu --- .../src/guest_function/call.rs | 9 +++ src/hyperlight_guest_bin/src/lib.rs | 10 +++ src/hyperlight_guest_tracing/src/lib.rs | 52 +++++++++++++ src/hyperlight_guest_tracing/src/state.rs | 71 +++++++++++++++++ .../src/subscriber.rs | 78 +++++++++++++++++++ 5 files changed, 220 insertions(+) create mode 100644 src/hyperlight_guest_tracing/src/state.rs create mode 100644 src/hyperlight_guest_tracing/src/subscriber.rs diff --git a/src/hyperlight_guest_bin/src/guest_function/call.rs b/src/hyperlight_guest_bin/src/guest_function/call.rs index 50cdffa50..6d49aced8 100644 --- a/src/hyperlight_guest_bin/src/guest_function/call.rs +++ b/src/hyperlight_guest_bin/src/guest_function/call.rs @@ -128,6 +128,15 @@ pub(crate) extern "C" fn dispatch_function() { // part of the big identity-mapped region at the base of the // guest. crate::paging::flush_tlb(); + + // Read the current TSC to report it to the host with the spans/events + // This helps calculating the timestamps relative to the guest call + #[cfg(feature = "trace_guest")] + { + let guest_start_tsc = hyperlight_guest_tracing::invariant_tsc::read_tsc(); + hyperlight_guest_tracing::set_start_tsc(guest_start_tsc); + } + internal_dispatch_function(); halt(); } diff --git a/src/hyperlight_guest_bin/src/lib.rs b/src/hyperlight_guest_bin/src/lib.rs index b7cd9d43d..240e29ac9 100644 --- a/src/hyperlight_guest_bin/src/lib.rs +++ b/src/hyperlight_guest_bin/src/lib.rs @@ -181,6 +181,10 @@ static INIT: Once = Once::new(); #[unsafe(no_mangle)] pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_level: u64) { + // Save the guest start TSC for tracing + #[cfg(feature = "trace_guest")] + let guest_start_tsc = hyperlight_guest_tracing::invariant_tsc::read_tsc(); + if peb_address == 0 { panic!("PEB address is null"); } @@ -229,6 +233,12 @@ pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_leve .expect("Invalid log level"); init_logger(max_log_level); + // It is important that all the tracing events are produced after the tracing is initialized. + #[cfg(feature = "trace_guest")] + if max_log_level != LevelFilter::Off { + hyperlight_guest_tracing::init_guest_tracing(guest_start_tsc); + } + hyperlight_main(); } }); diff --git a/src/hyperlight_guest_tracing/src/lib.rs b/src/hyperlight_guest_tracing/src/lib.rs index d062fccd2..375ff7d3a 100644 --- a/src/hyperlight_guest_tracing/src/lib.rs +++ b/src/hyperlight_guest_tracing/src/lib.rs @@ -19,3 +19,55 @@ use heapless as hl; /// Expose invariant TSC module pub mod invariant_tsc; + +/// Defines internal guest state +#[cfg(feature = "trace")] +mod state; + +/// Defines guest tracing Subscriber +#[cfg(feature = "trace")] +mod subscriber; + +#[cfg(feature = "trace")] +pub use trace::{init_guest_tracing, set_start_tsc}; + +/// This module is gated because some of these types are also used on the host, but we want +/// only the guest to allocate and allow the functionality intended for the guest. +#[cfg(feature = "trace")] +mod trace { + extern crate alloc; + use alloc::sync::{Arc, Weak}; + + use spin::Mutex; + + use super::*; + use crate::state::GuestState; + use crate::subscriber::GuestSubscriber; + + /// Weak reference to the guest state so we can manually trigger flush to host + static GUEST_STATE: spin::Once>> = spin::Once::new(); + + /// Initialize the guest tracing subscriber as global default. + pub fn init_guest_tracing(guest_start_tsc: u64) { + // Set as global default if not already set. + if tracing_core::dispatcher::has_been_set() { + return; + } + let sub = GuestSubscriber::new(guest_start_tsc); + let state = sub.state(); + // Store state Weak to use later at runtime + GUEST_STATE.call_once(|| Arc::downgrade(state)); + + // Set global dispatcher + let _ = tracing_core::dispatcher::set_global_default(tracing_core::Dispatch::new(sub)); + } + + /// Sets the guset starting timestamp reported to the host on a VMExit + pub fn set_start_tsc(guest_start_tsc: u64) { + if let Some(w) = GUEST_STATE.get() { + if let Some(state) = w.upgrade() { + state.lock().set_start_tsc(guest_start_tsc); + } + } + } +} diff --git a/src/hyperlight_guest_tracing/src/state.rs b/src/hyperlight_guest_tracing/src/state.rs new file mode 100644 index 000000000..e3105f8fb --- /dev/null +++ b/src/hyperlight_guest_tracing/src/state.rs @@ -0,0 +1,71 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +extern crate alloc; + +use core::sync::atomic::{AtomicU64, Ordering}; + +use heapless as hl; +use hyperlight_common::outb::OutBAction; +use tracing_core::Event; +use tracing_core::span::{Attributes, Id, Record}; + +/// Internal state of the tracing subscriber +pub(crate) struct GuestState { + /// The timestamp counter at the start of the guest execution. + guest_start_tsc: u64, +} + +impl GuestState { + pub(crate) fn new(guest_start_tsc: u64) -> Self { + Self { guest_start_tsc } + } + + /// Set a new guest start tsc + pub(crate) fn set_start_tsc(&mut self, guest_start_tsc: u64) { + self.guest_start_tsc = guest_start_tsc; + } + + /// Create a new span and push it on the stack + pub(crate) fn new_span(&mut self, attrs: &Attributes) -> Id { + unimplemented!() + } + + /// Record an event in the current span (top of the stack) + pub(crate) fn event(&mut self, event: &Event<'_>) { + unimplemented!() + } + + /// Record new values for an existing span + pub(crate) fn record(&mut self, id: &Id, values: &Record<'_>) { + unimplemented!() + } + + /// Enter a span (push it on the stack) + pub(crate) fn enter(&mut self, id: &Id) { + unimplemented!() + } + + /// Exit a span (pop it from the stack) + pub(crate) fn exit(&mut self, _id: &Id) { + unimplemented!() + } + + /// Try to close a span by ID, returning true if successful + /// Records the end timestamp for the span. + pub(crate) fn try_close(&mut self, id: Id) -> bool { + unimplemented!() + } +} diff --git a/src/hyperlight_guest_tracing/src/subscriber.rs b/src/hyperlight_guest_tracing/src/subscriber.rs new file mode 100644 index 000000000..fca202bb0 --- /dev/null +++ b/src/hyperlight_guest_tracing/src/subscriber.rs @@ -0,0 +1,78 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +extern crate alloc; + +use alloc::sync::Arc; + +use spin::Mutex; +use tracing_core::span::{Attributes, Id, Record}; +use tracing_core::subscriber::Subscriber; +use tracing_core::{Event, Metadata}; + +use crate::state::GuestState; + +/// The subscriber is used to collect spans and events in the guest. +pub(crate) struct GuestSubscriber { + /// Internal state that holds the spans and events + /// Protected by a Mutex for inner mutability + /// A reference to this state is stored in a static variable + state: Arc>, +} + +impl GuestSubscriber { + pub(crate) fn new(guest_start_tsc: u64) -> Self { + Self { + state: Arc::new(Mutex::new(GuestState::new(guest_start_tsc))), + } + } + pub(crate) fn state(&self) -> &Arc> { + &self.state + } +} + +impl Subscriber for GuestSubscriber { + fn enabled(&self, _md: &Metadata<'_>) -> bool { + true + } + + fn new_span(&self, attrs: &Attributes<'_>) -> Id { + self.state.lock().new_span(attrs) + } + + fn record(&self, id: &Id, values: &Record<'_>) { + self.state.lock().record(id, values) + } + + fn event(&self, event: &Event<'_>) { + self.state.lock().event(event) + } + + fn enter(&self, id: &Id) { + self.state.lock().enter(id) + } + + fn exit(&self, id: &Id) { + self.state.lock().exit(id) + } + + fn try_close(&self, id: Id) -> bool { + self.state.lock().try_close(id) + } + + fn record_follows_from(&self, _span: &Id, _follows: &Id) { + // no-op: we don't track follows-from relationships + } +} From 4a9105405d48ffc2846deef845ca1c4d086129d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Wed, 10 Sep 2025 23:58:33 +0300 Subject: [PATCH 258/271] [trace-guest] add span and event storage logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - implement add_span and event methods that store the info and report it to the host when the buffer gets full Signed-off-by: Doru Blânzeanu --- src/hyperlight_guest_tracing/src/lib.rs | 104 +++++++++ src/hyperlight_guest_tracing/src/state.rs | 230 +++++++++++++++++++- src/hyperlight_guest_tracing/src/visitor.rs | 73 +++++++ 3 files changed, 398 insertions(+), 9 deletions(-) create mode 100644 src/hyperlight_guest_tracing/src/visitor.rs diff --git a/src/hyperlight_guest_tracing/src/lib.rs b/src/hyperlight_guest_tracing/src/lib.rs index 375ff7d3a..3e92eb368 100644 --- a/src/hyperlight_guest_tracing/src/lib.rs +++ b/src/hyperlight_guest_tracing/src/lib.rs @@ -28,9 +28,113 @@ mod state; #[cfg(feature = "trace")] mod subscriber; +/// Defines a type to iterate over spans/events fields +#[cfg(feature = "trace")] +mod visitor; + +/// Type to get the relevant information from the internal state +/// and expose it to the host +#[cfg(feature = "trace")] +pub use state::TraceBatchInfo; #[cfg(feature = "trace")] pub use trace::{init_guest_tracing, set_start_tsc}; +/// Maximum number of spans that the guest can store +const MAX_NO_OF_SPANS: usize = 10; +/// Maximum number of events that the guest can store +const MAX_NO_OF_EVENTS: usize = 10; +/// Maximum length a name can have in a span/event +const MAX_NAME_LENGTH: usize = 64; +/// Maximum length the target can have in a span/event +const MAX_TARGET_LENGTH: usize = 64; +/// Maximum length key of a Field can have +const MAX_FIELD_KEY_LENGTH: usize = 32; +/// Maximum length value of a Field can have +const MAX_FIELD_VALUE_LENGTH: usize = 96; +/// Maximum number of fields a span/event can have +const MAX_NO_OF_FIELDS: usize = 8; + +/// Alias for the complicated heapless::Vec type for Spans +pub type Spans = hl::Vec< + GuestSpan< + MAX_NAME_LENGTH, + MAX_TARGET_LENGTH, + MAX_FIELD_KEY_LENGTH, + MAX_FIELD_VALUE_LENGTH, + MAX_NO_OF_FIELDS, + >, + MAX_NO_OF_SPANS, +>; + +/// Alias for the complicated heapless::Vec type for Events +pub type Events = hl::Vec< + GuestEvent, + MAX_NO_OF_EVENTS, +>; + +/// The trace level assigned to a span/event +#[derive(Debug, Copy, Clone)] +pub enum TraceLevel { + Error, + Warn, + Info, + Debug, + Trace, +} + +impl From for TraceLevel { + fn from(value: tracing::Level) -> Self { + match value { + tracing::Level::ERROR => Self::Error, + tracing::Level::WARN => Self::Warn, + tracing::Level::INFO => Self::Info, + tracing::Level::DEBUG => Self::Debug, + tracing::Level::TRACE => Self::Trace, + } + } +} +impl From for tracing::Level { + fn from(value: TraceLevel) -> Self { + match value { + TraceLevel::Error => Self::ERROR, + TraceLevel::Warn => Self::WARN, + TraceLevel::Info => Self::INFO, + TraceLevel::Debug => Self::DEBUG, + TraceLevel::Trace => Self::TRACE, + } + } +} + +/// The structure in which a guest stores Span information +pub struct GuestSpan< + const N: usize, + const T: usize, + const FK: usize, + const FV: usize, + const F: usize, +> { + pub id: u64, + pub parent_id: Option, + pub level: TraceLevel, + /// Span name + pub name: hl::String, + /// Filename + pub target: hl::String, + pub start_tsc: u64, + pub end_tsc: Option, + pub fields: hl::Vec<(hl::String, hl::String), F>, +} + +/// The structure in which a guest stores Event information +pub struct GuestEvent { + pub parent_id: u64, + pub level: TraceLevel, + pub name: hl::String, + /// Event name + pub tsc: u64, + pub fields: hl::Vec<(hl::String, hl::String), F>, +} + /// This module is gated because some of these types are also used on the host, but we want /// only the guest to allocate and allow the functionality intended for the guest. #[cfg(feature = "trace")] diff --git a/src/hyperlight_guest_tracing/src/state.rs b/src/hyperlight_guest_tracing/src/state.rs index e3105f8fb..f7196a350 100644 --- a/src/hyperlight_guest_tracing/src/state.rs +++ b/src/hyperlight_guest_tracing/src/state.rs @@ -22,15 +22,123 @@ use hyperlight_common::outb::OutBAction; use tracing_core::Event; use tracing_core::span::{Attributes, Id, Record}; +use crate::visitor::FieldsVisitor; +use crate::{ + GuestEvent, GuestSpan, MAX_FIELD_KEY_LENGTH, MAX_FIELD_VALUE_LENGTH, MAX_NAME_LENGTH, + MAX_NO_OF_EVENTS, MAX_NO_OF_FIELDS, MAX_NO_OF_SPANS, MAX_TARGET_LENGTH, invariant_tsc, +}; + +pub struct TraceBatchInfo { + /// The timestamp counter at the start of the guest execution. + pub guest_start_tsc: u64, + /// Pointer to the spans in the guest memory. + pub spans_ptr: u64, + /// Pointer to the events in the guest memory. + pub events_ptr: u64, +} + +/// Helper type to define the guest state with the configured constants +pub type GuestState = TraceState< + MAX_NO_OF_SPANS, + MAX_NO_OF_EVENTS, + MAX_NAME_LENGTH, + MAX_TARGET_LENGTH, + MAX_FIELD_KEY_LENGTH, + MAX_FIELD_VALUE_LENGTH, + MAX_NO_OF_FIELDS, +>; + /// Internal state of the tracing subscriber -pub(crate) struct GuestState { +pub(crate) struct TraceState< + const SP: usize, + const EV: usize, + const N: usize, + const T: usize, + const FK: usize, + const FV: usize, + const F: usize, +> { + /// Whether we need to cleanup the state on next access + cleanup_needed: bool, /// The timestamp counter at the start of the guest execution. guest_start_tsc: u64, + /// Next span ID to allocate + next_id: AtomicU64, + /// All spans collected + spans: hl::Vec, SP>, + /// All events collected + events: hl::Vec, EV>, + /// Stack of active spans + stack: hl::Vec, } -impl GuestState { +impl< + const SP: usize, + const EV: usize, + const N: usize, + const T: usize, + const FK: usize, + const FV: usize, + const F: usize, +> TraceState +{ pub(crate) fn new(guest_start_tsc: u64) -> Self { - Self { guest_start_tsc } + Self { + cleanup_needed: false, + guest_start_tsc, + next_id: AtomicU64::new(1), + spans: hl::Vec::new(), + stack: hl::Vec::new(), + events: hl::Vec::new(), + } + } + + pub(crate) fn alloc_id(&self) -> (u64, Id) { + let n = self.next_id.load(Ordering::Relaxed); + self.next_id.store(n + 1, Ordering::Relaxed); + + (n, Id::from_u64(n)) + } + + /// Cleanup internal state by removing closed spans and events + /// This ensures that after a VM exit, we keep the spans that + /// are still active (in the stack) and remove all other spans and events. + pub fn clean(&mut self) { + // Remove all spans that have an end timestamp (closed spans) + self.spans.retain(|s| s.end_tsc.is_none()); + + // Remove all events + self.events.clear(); + } + + #[inline(always)] + fn verify_and_clean(&mut self) { + if self.cleanup_needed { + self.clean(); + self.cleanup_needed = false; + } + } + + /// Triggers a VM exit to flush the current spans to the host. + /// This also clears the internal state to start fresh. + fn send_to_host(&mut self) { + let guest_start_tsc = self.guest_start_tsc; + let spans_ptr = &self.spans as *const _ as u64; + let events_ptr = &self.events as *const _ as u64; + + unsafe { + core::arch::asm!("out dx, al", + // Port value for tracing + in("dx") OutBAction::TraceBatch as u16, + // Additional magic number to identify the action + in("r8") OutBAction::TraceBatch as u64, + in("r9") guest_start_tsc, + in("r10") spans_ptr, + in("r11") events_ptr, + ); + } + + self.clean(); } /// Set a new guest start tsc @@ -38,34 +146,138 @@ impl GuestState { self.guest_start_tsc = guest_start_tsc; } + /// Closes the trace by ending all spans + /// NOTE: This expects an outb call to send the spans to the host. + pub(crate) fn end_trace(&mut self) { + for span in self.spans.iter_mut() { + if span.end_tsc.is_none() { + span.end_tsc = Some(invariant_tsc::read_tsc()); + } + } + + // Empty the stack + while self.stack.pop().is_some() { + // Pop all remaining spans from the stack + } + + // Mark for clearing when re-entering the VM because we might + // not enter on the same place as we exited (e.g. halt) + self.cleanup_needed = true; + } + + /// Returns information about the information needed by the host to read the spans. + pub(crate) fn guest_trace_info(&mut self) -> TraceBatchInfo { + TraceBatchInfo { + guest_start_tsc: self.guest_start_tsc, + spans_ptr: &self.spans as *const _ as u64, + events_ptr: &self.events as *const _ as u64, + } + } + /// Create a new span and push it on the stack pub(crate) fn new_span(&mut self, attrs: &Attributes) -> Id { - unimplemented!() + self.verify_and_clean(); + let (idn, id) = self.alloc_id(); + + let md = attrs.metadata(); + let mut name = hl::String::::new(); + let mut target = hl::String::::new(); + // Shorten name and target if they are bigger than the space allocated + let _ = name.push_str(&md.name()[..usize::min(md.name().len(), name.capacity())]); + let _ = target.push_str(&md.target()[..usize::min(md.target().len(), target.capacity())]); + + // Visit fields to collect them + let mut fields = hl::Vec::new(); + attrs.record(&mut FieldsVisitor:: { out: &mut fields }); + + // Find parent from current stack top (if any) + let parent_id = self.stack.last().copied(); + + let span = GuestSpan:: { + id: idn, + parent_id, + level: (*md.level()).into(), + name, + target, + start_tsc: invariant_tsc::read_tsc(), + end_tsc: None, + fields, + }; + + let spans = &mut self.spans; + // Should never fail because we flush when full + let _ = spans.push(span); + + // In case the spans Vec is full, we need to report them to the host + if spans.len() == spans.capacity() { + self.send_to_host(); + } + + id } /// Record an event in the current span (top of the stack) pub(crate) fn event(&mut self, event: &Event<'_>) { - unimplemented!() + self.verify_and_clean(); + let stack = &mut self.stack; + let parent_id = stack.last().copied().unwrap_or(0); + + let md = event.metadata(); + let mut name = hl::String::::new(); + // Shorten name and target if they are bigger than the space allocated + let _ = name.push_str(&md.name()[..usize::min(md.name().len(), name.capacity())]); + + let mut fields = hl::Vec::new(); + event.record(&mut FieldsVisitor:: { out: &mut fields }); + + let ev = GuestEvent { + parent_id, + level: (*md.level()).into(), + name, + tsc: invariant_tsc::read_tsc(), + fields, + }; + + // Should never fail because we flush when full + let _ = self.events.push(ev); + + // Flush buffer to host if full + if self.events.len() >= self.events.capacity() { + self.send_to_host(); + } } /// Record new values for an existing span pub(crate) fn record(&mut self, id: &Id, values: &Record<'_>) { - unimplemented!() + let spans = &mut self.spans; + if let Some(s) = spans.iter_mut().find(|s| s.id == id.into_u64()) { + let mut v = hl::Vec::new(); + values.record(&mut FieldsVisitor:: { out: &mut v }); + s.fields.extend(v); + } } /// Enter a span (push it on the stack) pub(crate) fn enter(&mut self, id: &Id) { - unimplemented!() + let st = &mut self.stack; + let _ = st.push(id.into_u64()); } /// Exit a span (pop it from the stack) pub(crate) fn exit(&mut self, _id: &Id) { - unimplemented!() + let st = &mut self.stack; + let _ = st.pop(); } /// Try to close a span by ID, returning true if successful /// Records the end timestamp for the span. pub(crate) fn try_close(&mut self, id: Id) -> bool { - unimplemented!() + let spans = &mut self.spans; + if let Some(s) = spans.iter_mut().find(|s| s.id == id.into_u64()) { + s.end_tsc = Some(invariant_tsc::read_tsc()); + true + } else { + false + } } } diff --git a/src/hyperlight_guest_tracing/src/visitor.rs b/src/hyperlight_guest_tracing/src/visitor.rs new file mode 100644 index 000000000..7955ca77e --- /dev/null +++ b/src/hyperlight_guest_tracing/src/visitor.rs @@ -0,0 +1,73 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +extern crate alloc; + +use core::fmt::Debug; + +use heapless as hl; +use tracing_core::field::{Field, Visit}; + +/// Visitor implementation to collect fields into a vector of key-value pairs +pub(crate) struct FieldsVisitor<'a, const FK: usize, const FV: usize, const F: usize> { + pub out: &'a mut hl::Vec<(hl::String, hl::String), F>, +} + +impl Visit for FieldsVisitor<'_, FK, FV, F> { + /// Record a byte slice field + /// # Arguments + /// * `field` - The field metadata + /// * `value` - The byte slice value + /// NOTE: This implementation truncates the key and value if they exceed the allocated capacity + fn record_bytes(&mut self, field: &Field, value: &[u8]) { + let mut k = hl::String::::new(); + let mut val = hl::String::::new(); + // Shorten key and value if they are bigger than the space allocated + let _ = k.push_str(&field.name()[..usize::min(field.name().len(), k.capacity())]); + let _ = + val.push_str(&alloc::format!("{value:?}")[..usize::min(value.len(), val.capacity())]); + let _ = self.out.push((k, val)); + } + + /// Record a string field + /// # Arguments + /// * `f` - The field metadata + /// * `v` - The string value + /// NOTE: This implementation truncates the key and value if they exceed the allocated capacity + fn record_str(&mut self, f: &Field, v: &str) { + let mut k = heapless::String::::new(); + let mut val = heapless::String::::new(); + // Shorten key and value if they are bigger than the space allocated + let _ = k.push_str(&f.name()[..usize::min(f.name().len(), k.capacity())]); + let _ = val.push_str(&v[..usize::min(v.len(), val.capacity())]); + let _ = self.out.push((k, val)); + } + + /// Record a debug field + /// # Arguments + /// * `f` - The field metadata + /// * `v` - The debug value + /// NOTE: This implementation truncates the key and value if they exceed the allocated capacity + fn record_debug(&mut self, f: &Field, v: &dyn Debug) { + use heapless::String; + let mut k = String::::new(); + let mut val = String::::new(); + // Shorten key and value if they are bigger than the space allocated + let _ = k.push_str(&f.name()[..usize::min(f.name().len(), k.capacity())]); + let v = alloc::format!("{v:?}"); + let _ = val.push_str(&v[..usize::min(v.len(), val.capacity())]); + let _ = self.out.push((k, val)); + } +} From 1e3807c485f031410377d21d29b4e15e12f7986b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Sun, 31 Aug 2025 13:26:52 +0300 Subject: [PATCH 259/271] [trace-guest] update outb instructions to include trace info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- src/hyperlight_common/src/outb.rs | 5 +++ src/hyperlight_guest/src/exit.rs | 60 ++++++++++++++++++++++++- src/hyperlight_guest_tracing/src/lib.rs | 40 ++++++++++++++++- src/hyperlight_host/src/sandbox/outb.rs | 2 + 4 files changed, 105 insertions(+), 2 deletions(-) diff --git a/src/hyperlight_common/src/outb.rs b/src/hyperlight_common/src/outb.rs index 9066b4eb6..b060ae5cf 100644 --- a/src/hyperlight_common/src/outb.rs +++ b/src/hyperlight_common/src/outb.rs @@ -90,6 +90,7 @@ impl TryFrom for Exception { /// - CallFunction: makes a call to a host function, /// - Abort: aborts the execution of the guest, /// - DebugPrint: prints a message to the host +/// - TraceBatch: reports a batch of spans and events from the guest /// - TraceMemoryAlloc: records memory allocation events /// - TraceMemoryFree: records memory deallocation events pub enum OutBAction { @@ -97,6 +98,8 @@ pub enum OutBAction { CallFunction = 101, Abort = 102, DebugPrint = 103, + #[cfg(feature = "trace_guest")] + TraceBatch = 104, #[cfg(feature = "mem_profile")] TraceMemoryAlloc = 105, #[cfg(feature = "mem_profile")] @@ -111,6 +114,8 @@ impl TryFrom for OutBAction { 101 => Ok(OutBAction::CallFunction), 102 => Ok(OutBAction::Abort), 103 => Ok(OutBAction::DebugPrint), + #[cfg(feature = "trace_guest")] + 104 => Ok(OutBAction::TraceBatch), #[cfg(feature = "mem_profile")] 105 => Ok(OutBAction::TraceMemoryAlloc), #[cfg(feature = "mem_profile")] diff --git a/src/hyperlight_guest/src/exit.rs b/src/hyperlight_guest/src/exit.rs index e3429d288..4ac359e04 100644 --- a/src/hyperlight_guest/src/exit.rs +++ b/src/hyperlight_guest/src/exit.rs @@ -22,7 +22,34 @@ use hyperlight_common::outb::OutBAction; /// Halt the execution of the guest and returns control to the host. #[inline(never)] pub fn halt() { - unsafe { asm!("hlt", options(nostack)) } + #[cfg(feature = "trace_guest")] + { + // End any ongoing trace before halting + hyperlight_guest_tracing::end_trace(); + // If tracing is enabled, we need to pass the trace batch info + // along with the halt instruction so the host can retrieve it + if let Some(tbi) = hyperlight_guest_tracing::guest_trace_info() { + unsafe { + asm!("hlt", + in("r8") OutBAction::TraceBatch as u64, + in("r9") tbi.guest_start_tsc, + in("r10") tbi.spans_ptr, + in("r11") tbi.events_ptr, + options(nostack) + ) + }; + hyperlight_guest_tracing::clean_trace_state(); + } else { + // If tracing is not enabled, we can directly halt + unsafe { asm!("hlt", options(nostack)) }; + } + } + + #[cfg(not(feature = "trace_guest"))] + { + // If tracing is not enabled, we can directly halt + unsafe { asm!("hlt", options(nostack)) }; + } } /// Exits the VM with an Abort OUT action and code 0. @@ -33,6 +60,9 @@ pub extern "C" fn abort() -> ! { /// Exits the VM with an Abort OUT action and a specific code. pub fn abort_with_code(code: &[u8]) -> ! { + // End any ongoing trace before aborting + #[cfg(feature = "trace_guest")] + hyperlight_guest_tracing::end_trace(); outb(OutBAction::Abort as u16, code); outb(OutBAction::Abort as u16, &[0xFF]); // send abort terminator (if not included in code) unreachable!() @@ -43,6 +73,9 @@ pub fn abort_with_code(code: &[u8]) -> ! { /// # Safety /// This function is unsafe because it dereferences a raw pointer. pub unsafe fn abort_with_code_and_message(code: &[u8], message_ptr: *const c_char) -> ! { + // End any ongoing trace before aborting + #[cfg(feature = "trace_guest")] + hyperlight_guest_tracing::end_trace(); unsafe { // Step 1: Send abort code (typically 1 byte, but `code` allows flexibility) outb(OutBAction::Abort as u16, code); @@ -89,6 +122,31 @@ pub(crate) fn outb(port: u16, data: &[u8]) { /// OUT function for sending a 32-bit value to the host. pub(crate) unsafe fn out32(port: u16, val: u32) { + #[cfg(feature = "trace_guest")] + { + if let Some(tbi) = hyperlight_guest_tracing::guest_trace_info() { + // If tracing is enabled, send the trace batch info along with the OUT action + unsafe { + asm!("out dx, eax", + in("dx") port, + in("eax") val, + in("r8") OutBAction::TraceBatch as u64, + in("r9") tbi.guest_start_tsc, + in("r10") tbi.spans_ptr, + in("r11") tbi.events_ptr, + options(preserves_flags, nomem, nostack) + ) + }; + + hyperlight_guest_tracing::clean_trace_state(); + } else { + // If tracing is not enabled, just send the value + unsafe { + asm!("out dx, eax", in("dx") port, in("eax") val, options(preserves_flags, nomem, nostack)) + }; + } + } + #[cfg(not(feature = "trace_guest"))] unsafe { asm!("out dx, eax", in("dx") port, in("eax") val, options(preserves_flags, nomem, nostack)); } diff --git a/src/hyperlight_guest_tracing/src/lib.rs b/src/hyperlight_guest_tracing/src/lib.rs index 3e92eb368..74f2772d3 100644 --- a/src/hyperlight_guest_tracing/src/lib.rs +++ b/src/hyperlight_guest_tracing/src/lib.rs @@ -37,7 +37,9 @@ mod visitor; #[cfg(feature = "trace")] pub use state::TraceBatchInfo; #[cfg(feature = "trace")] -pub use trace::{init_guest_tracing, set_start_tsc}; +pub use trace::{ + clean_trace_state, end_trace, guest_trace_info, init_guest_tracing, set_start_tsc, +}; /// Maximum number of spans that the guest can store const MAX_NO_OF_SPANS: usize = 10; @@ -174,4 +176,40 @@ mod trace { } } } + + /// Ends the current trace by ending all active spans in the + /// internal state and storing the end timestamps. + /// + /// This expects an outb call to send the spans to the host. + /// After calling this function, the internal state is marked + /// for cleaning on the next access. + pub fn end_trace() { + if let Some(w) = GUEST_STATE.get() { + if let Some(state) = w.upgrade() { + state.lock().end_trace(); + } + } + } + + /// Cleans the internal trace state by removing closed spans and events. + /// This ensures that after a VM exit, we keep the spans that + /// are still active (in the stack) and remove all other spans and events. + pub fn clean_trace_state() { + if let Some(w) = GUEST_STATE.get() { + if let Some(state) = w.upgrade() { + state.lock().clean(); + } + } + } + + /// Returns information about the current trace state needed by the host to read the spans. + pub fn guest_trace_info() -> Option { + let mut res = None; + if let Some(w) = GUEST_STATE.get() { + if let Some(state) = w.upgrade() { + res = Some(state.lock().guest_trace_info()); + } + } + res + } } diff --git a/src/hyperlight_host/src/sandbox/outb.rs b/src/hyperlight_host/src/sandbox/outb.rs index e3bacedb7..e5e938ae3 100644 --- a/src/hyperlight_host/src/sandbox/outb.rs +++ b/src/hyperlight_host/src/sandbox/outb.rs @@ -182,6 +182,8 @@ pub(crate) fn handle_outb( eprint!("{}", ch); Ok(()) } + #[cfg(feature = "trace_guest")] + OutBAction::TraceBatch => Ok(()), #[cfg(feature = "mem_profile")] OutBAction::TraceMemoryAlloc => { let regs = _hv.regs()?; From e7e26dbb6fd8d3c1a422a2893ce68b92c3214ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Sun, 31 Aug 2025 14:27:19 +0300 Subject: [PATCH 260/271] [trace-host] handle a TraceBatch from the guest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Parse the spans and events coming from the guest and create corresponding spans and events from the host that mimics a single call from host - Create a `TraceContext` that handles a call into a guest Signed-off-by: Doru Blânzeanu --- Cargo.lock | 57 +++ src/hyperlight_guest_tracing/src/lib.rs | 32 +- src/hyperlight_host/Cargo.toml | 6 +- .../src/hypervisor/hyperv_linux.rs | 22 +- .../src/hypervisor/hyperv_windows.rs | 22 +- src/hyperlight_host/src/hypervisor/kvm.rs | 22 +- src/hyperlight_host/src/hypervisor/mod.rs | 33 +- .../src/sandbox/trace/context.rs | 353 ++++++++++++++++++ src/hyperlight_host/src/sandbox/trace/mod.rs | 4 + 9 files changed, 525 insertions(+), 26 deletions(-) create mode 100644 src/hyperlight_host/src/sandbox/trace/context.rs diff --git a/Cargo.lock b/Cargo.lock index 0b9e7e7c5..34a3a4506 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1195,6 +1195,25 @@ dependencies = [ "scroll", ] +[[package]] +name = "h2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "2.6.0" @@ -1303,6 +1322,7 @@ dependencies = [ "bytes", "futures-channel", "futures-core", + "h2", "http", "http-body", "httparse", @@ -1314,6 +1334,19 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.16" @@ -2224,6 +2257,8 @@ dependencies = [ "prost", "reqwest", "thiserror 2.0.17", + "tokio", + "tonic", ] [[package]] @@ -3453,6 +3488,19 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-util" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.8.23" @@ -3538,10 +3586,15 @@ dependencies = [ "http", "http-body", "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", "percent-encoding", "pin-project", "sync_wrapper", + "tokio", "tokio-stream", + "tower", "tower-layer", "tower-service", "tracing", @@ -3566,11 +3619,15 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", + "indexmap", "pin-project-lite", + "slab", "sync_wrapper", "tokio", + "tokio-util", "tower-layer", "tower-service", + "tracing", ] [[package]] diff --git a/src/hyperlight_guest_tracing/src/lib.rs b/src/hyperlight_guest_tracing/src/lib.rs index 74f2772d3..771e2d820 100644 --- a/src/hyperlight_guest_tracing/src/lib.rs +++ b/src/hyperlight_guest_tracing/src/lib.rs @@ -170,10 +170,10 @@ mod trace { /// Sets the guset starting timestamp reported to the host on a VMExit pub fn set_start_tsc(guest_start_tsc: u64) { - if let Some(w) = GUEST_STATE.get() { - if let Some(state) = w.upgrade() { - state.lock().set_start_tsc(guest_start_tsc); - } + if let Some(w) = GUEST_STATE.get() + && let Some(state) = w.upgrade() + { + state.lock().set_start_tsc(guest_start_tsc); } } @@ -184,10 +184,10 @@ mod trace { /// After calling this function, the internal state is marked /// for cleaning on the next access. pub fn end_trace() { - if let Some(w) = GUEST_STATE.get() { - if let Some(state) = w.upgrade() { - state.lock().end_trace(); - } + if let Some(w) = GUEST_STATE.get() + && let Some(state) = w.upgrade() + { + state.lock().end_trace(); } } @@ -195,20 +195,20 @@ mod trace { /// This ensures that after a VM exit, we keep the spans that /// are still active (in the stack) and remove all other spans and events. pub fn clean_trace_state() { - if let Some(w) = GUEST_STATE.get() { - if let Some(state) = w.upgrade() { - state.lock().clean(); - } + if let Some(w) = GUEST_STATE.get() + && let Some(state) = w.upgrade() + { + state.lock().clean(); } } /// Returns information about the current trace state needed by the host to read the spans. pub fn guest_trace_info() -> Option { let mut res = None; - if let Some(w) = GUEST_STATE.get() { - if let Some(state) = w.upgrade() { - res = Some(state.lock().guest_trace_info()); - } + if let Some(w) = GUEST_STATE.get() + && let Some(state) = w.upgrade() + { + res = Some(state.lock().guest_trace_info()); } res } diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 5b3167185..76935b5b2 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -35,9 +35,11 @@ page_size = "0.6.0" termcolor = "1.2.0" bitflags = "2.10.0" log = "0.4.28" +opentelemetry = { version = "0.31.0", optional = true } tracing = { version = "0.1.41", features = ["log"] } tracing-log = "0.2.0" tracing-core = "0.1.34" +tracing-opentelemetry = { version = "0.32.0", optional = true } hyperlight-common = { workspace = true, default-features = true, features = [ "std" ] } hyperlight-guest-tracing = { workspace = true, default-features = true, optional = true } vmm-sys-util = "0.15.0" @@ -98,7 +100,7 @@ tracing = "0.1.41" tracing-subscriber = {version = "0.3.20", features = ["std", "env-filter"]} tracing-opentelemetry = "0.32.0" opentelemetry = "0.31.0" -opentelemetry-otlp = { version = "0.31.0", default-features = false, features = ["http-proto", "reqwest-blocking-client"] } +opentelemetry-otlp = { version = "0.31.0", default-features = false, features = ["http-proto", "reqwest-blocking-client", "grpc-tonic"] } opentelemetry-semantic-conventions = "0.31" opentelemetry_sdk = { version = "0.31.0", features = ["rt-tokio"] } tokio = { version = "1.48.0", features = ["full"] } @@ -132,7 +134,7 @@ executable_heap = [] print_debug = [] # Dumps the VM state to a file on unexpected errors or crashes. The path of the file will be printed on stdout and logged. crashdump = ["dep:chrono"] -trace_guest = ["hyperlight-common/trace_guest", "hyperlight-guest-tracing/trace"] +trace_guest = ["dep:opentelemetry", "dep:tracing-opentelemetry", "dep:hyperlight-guest-tracing", "hyperlight-common/trace_guest"] mem_profile = [ "trace_guest", "dep:framehop", "dep:fallible-iterator", "hyperlight-common/mem_profile" ] kvm = ["dep:kvm-bindings", "dep:kvm-ioctls"] # This feature is deprecated in favor of mshv3 diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 8b72e3d0b..801f361a7 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -50,6 +50,8 @@ use mshv_bindings::{ }; use mshv_ioctls::{Mshv, VcpuFd, VmFd}; use tracing::{Span, instrument}; +#[cfg(feature = "trace_guest")] +use tracing_opentelemetry::OpenTelemetrySpanExt; #[cfg(crashdump)] use {super::crashdump, std::path::Path}; @@ -296,7 +298,6 @@ pub(crate) struct HypervLinuxDriver { gdb_conn: Option>, #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, - #[allow(dead_code)] #[cfg(feature = "mem_profile")] trace_info: MemTraceInfo, } @@ -643,7 +644,10 @@ impl Hypervisor for HypervLinuxDriver { } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - fn run(&mut self) -> Result { + fn run( + &mut self, + #[cfg(feature = "trace_guest")] tc: &mut crate::sandbox::trace::TraceContext, + ) -> Result { const HALT_MESSAGE: hv_message_type = hv_message_type_HVMSG_X64_HALT; const IO_PORT_INTERCEPT_MESSAGE: hv_message_type = hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT; @@ -685,6 +689,9 @@ impl Hypervisor for HypervLinuxDriver { { Err(mshv_ioctls::MshvError::from(libc::EINTR)) } else { + #[cfg(feature = "trace_guest")] + tc.setup_guest_trace(Span::current().context()); + // Note: if a `InterruptHandle::kill()` called while this thread is **here** // Then the vcpu will run, but we will keep sending signals to this thread // to interrupt it until `running` is set to false. The `vcpu_fd::run()` call will @@ -1086,6 +1093,17 @@ impl Hypervisor for HypervLinuxDriver { } } + #[cfg(feature = "trace_guest")] + fn handle_trace(&mut self, tc: &mut crate::sandbox::trace::TraceContext) -> Result<()> { + let regs = self.regs()?; + tc.handle_trace( + ®s, + self.mem_mgr.as_ref().ok_or_else(|| { + new_error!("Memory manager is not initialized before handling trace") + })?, + ) + } + #[cfg(feature = "mem_profile")] fn trace_info_mut(&mut self) -> &mut MemTraceInfo { &mut self.trace_info diff --git a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs index 4603a3f93..5c6c9db9c 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_windows.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_windows.rs @@ -22,6 +22,8 @@ use std::sync::{Arc, Mutex}; use log::LevelFilter; use tracing::{Span, instrument}; +#[cfg(feature = "trace_guest")] +use tracing_opentelemetry::OpenTelemetrySpanExt; use windows::Win32::System::Hypervisor::{ WHV_MEMORY_ACCESS_TYPE, WHV_PARTITION_HANDLE, WHV_RUN_VP_EXIT_CONTEXT, WHV_RUN_VP_EXIT_REASON, WHvCancelRunVirtualProcessor, @@ -275,7 +277,6 @@ pub(crate) struct HypervWindowsDriver { #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, #[cfg(feature = "mem_profile")] - #[allow(dead_code)] trace_info: MemTraceInfo, } /* This does not automatically impl Send because the host @@ -544,7 +545,10 @@ impl Hypervisor for HypervWindowsDriver { } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - fn run(&mut self) -> Result { + fn run( + &mut self, + #[cfg(feature = "trace_guest")] tc: &mut crate::sandbox::trace::TraceContext, + ) -> Result { self.interrupt_handle.running.store(true, Ordering::Relaxed); #[cfg(not(gdb))] @@ -569,6 +573,9 @@ impl Hypervisor for HypervWindowsDriver { Reserved: Default::default(), } } else { + #[cfg(feature = "trace_guest")] + tc.setup_guest_trace(Span::current().context()); + self.processor.run()? }; self.interrupt_handle @@ -932,6 +939,17 @@ impl Hypervisor for HypervWindowsDriver { } } + #[cfg(feature = "trace_guest")] + fn handle_trace(&mut self, tc: &mut crate::sandbox::trace::TraceContext) -> Result<()> { + let regs = self.regs()?; + tc.handle_trace( + ®s, + self.mem_mgr.as_ref().ok_or_else(|| { + new_error!("Memory manager is not initialized before handling trace") + })?, + ) + } + #[cfg(feature = "mem_profile")] fn trace_info_mut(&mut self) -> &mut MemTraceInfo { &mut self.trace_info diff --git a/src/hyperlight_host/src/hypervisor/kvm.rs b/src/hyperlight_host/src/hypervisor/kvm.rs index da7e4e4d1..330a5f5b5 100644 --- a/src/hyperlight_host/src/hypervisor/kvm.rs +++ b/src/hyperlight_host/src/hypervisor/kvm.rs @@ -23,6 +23,8 @@ use kvm_ioctls::Cap::UserMemory; use kvm_ioctls::{Kvm, VcpuExit, VcpuFd, VmFd}; use log::LevelFilter; use tracing::{Span, instrument}; +#[cfg(feature = "trace_guest")] +use tracing_opentelemetry::OpenTelemetrySpanExt; #[cfg(crashdump)] use {super::crashdump, std::path::Path}; @@ -285,7 +287,6 @@ pub(crate) struct KVMDriver { #[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig, #[cfg(feature = "mem_profile")] - #[allow(dead_code)] trace_info: MemTraceInfo, } @@ -613,7 +614,10 @@ impl Hypervisor for KVMDriver { } #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - fn run(&mut self) -> Result { + fn run( + &mut self, + #[cfg(feature = "trace_guest")] tc: &mut crate::sandbox::trace::TraceContext, + ) -> Result { self.interrupt_handle .tid .store(unsafe { libc::pthread_self() as u64 }, Ordering::Relaxed); @@ -646,6 +650,9 @@ impl Hypervisor for KVMDriver { { Err(kvm_ioctls::Error::new(libc::EINTR)) } else { + #[cfg(feature = "trace_guest")] + tc.setup_guest_trace(Span::current().context()); + // Note: if a `InterruptHandle::kill()` called while this thread is **here** // Then the vcpu will run, but we will keep sending signals to this thread // to interrupt it until `running` is set to false. The `vcpu_fd::run()` call will @@ -1021,6 +1028,17 @@ impl Hypervisor for KVMDriver { } } + #[cfg(feature = "trace_guest")] + fn handle_trace(&mut self, tc: &mut crate::sandbox::trace::TraceContext) -> Result<()> { + let regs = self.regs()?; + tc.handle_trace( + ®s, + self.mem_mgr.as_ref().ok_or_else(|| { + new_error!("Memory manager is not initialized before handling trace") + })?, + ) + } + #[cfg(feature = "mem_profile")] fn trace_info_mut(&mut self) -> &mut MemTraceInfo { &mut self.trace_info diff --git a/src/hyperlight_host/src/hypervisor/mod.rs b/src/hyperlight_host/src/hypervisor/mod.rs index cf8899d96..e5592509a 100644 --- a/src/hyperlight_host/src/hypervisor/mod.rs +++ b/src/hyperlight_host/src/hypervisor/mod.rs @@ -171,7 +171,10 @@ pub(crate) trait Hypervisor: Debug + Send { ) -> Result<()>; /// Run the vCPU - fn run(&mut self) -> Result; + fn run( + &mut self, + #[cfg(feature = "trace_guest")] tc: &mut crate::sandbox::trace::TraceContext, + ) -> Result; /// Get InterruptHandle to underlying VM fn interrupt_handle(&self) -> Arc; @@ -313,6 +316,9 @@ pub(crate) trait Hypervisor: Debug + Send { /// Check stack guard to see if the stack is still valid fn check_stack_guard(&self) -> Result; + #[cfg(feature = "trace_guest")] + fn handle_trace(&mut self, tc: &mut crate::sandbox::trace::TraceContext) -> Result<()>; + /// Get a mutable reference of the trace info for the guest #[cfg(feature = "mem_profile")] fn trace_info_mut(&mut self) -> &mut MemTraceInfo; @@ -351,8 +357,31 @@ impl VirtualCPU { hv: &mut dyn Hypervisor, #[cfg(gdb)] dbg_mem_access_fn: Arc>>, ) -> Result<()> { + // Keeps the trace context and open spans + #[cfg(feature = "trace_guest")] + let mut tc = crate::sandbox::trace::TraceContext::new(); + loop { - match hv.run() { + #[cfg(feature = "trace_guest")] + let result = { + let result = hv.run(&mut tc); + // End current host trace by closing the current span that captures traces + // happening when a guest exits and re-enters. + tc.end_host_trace(); + + // Handle the guest trace data if any + if let Err(e) = hv.handle_trace(&mut tc) { + // If no trace data is available, we just log a message and continue + // Is this the right thing to do? + log::debug!("Error handling guest trace: {:?}", e); + } + + result + }; + #[cfg(not(feature = "trace_guest"))] + let result = hv.run(); + + match result { #[cfg(gdb)] Ok(HyperlightExit::Debug(stop_reason)) => { if let Err(e) = hv.handle_debug(dbg_mem_access_fn.clone(), stop_reason) { diff --git a/src/hyperlight_host/src/sandbox/trace/context.rs b/src/hyperlight_host/src/sandbox/trace/context.rs new file mode 100644 index 000000000..f17a466ef --- /dev/null +++ b/src/hyperlight_host/src/sandbox/trace/context.rs @@ -0,0 +1,353 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +use std::collections::HashMap; +use std::time::{Duration, Instant, SystemTime}; + +use hyperlight_common::outb::OutBAction; +use hyperlight_guest_tracing::{Events, Spans}; +use opentelemetry::global::BoxedSpan; +use opentelemetry::trace::{Span as _, TraceContextExt, Tracer as _}; +use opentelemetry::{Context, KeyValue, global}; +use tracing::span::{EnteredSpan, Span}; +use tracing_opentelemetry::OpenTelemetrySpanExt; + +use crate::hypervisor::regs::CommonRegisters; +use crate::mem::layout::SandboxMemoryLayout; +use crate::mem::mgr::SandboxMemoryManager; +use crate::mem::shared_mem::HostSharedMemory; +use crate::{HyperlightError, Result, new_error}; + +/// Type that helps get the data from the guest provided the registers and memory access +struct TraceBatch { + pub guest_start_tsc: u64, + pub spans: Spans, + pub events: Events, +} + +impl TryFrom<(&CommonRegisters, &SandboxMemoryManager)> for TraceBatch { + type Error = HyperlightError; + fn try_from( + (regs, mem_mgr): (&CommonRegisters, &SandboxMemoryManager), + ) -> Result { + let magic_no = regs.r8; + let guest_start_tsc = regs.r9; + let spans_ptr = regs.r10 as usize; + let events_ptr = regs.r11 as usize; + + if magic_no != OutBAction::TraceBatch as u64 { + return Err(new_error!("A TraceBatch is not present")); + } + + // Transmute spans_ptr to Spans type + let mut spans = vec![0u8; std::mem::size_of::()]; + mem_mgr + .shared_mem + .copy_to_slice(&mut spans, spans_ptr - SandboxMemoryLayout::BASE_ADDRESS) + .map_err(|e| { + new_error!( + "Failed to copy guest trace batch from guest memory to host: {:?}", + e + ) + })?; + + let spans: Spans = unsafe { + let raw = spans.as_slice() as *const _ as *const Spans; + raw.read_unaligned() + }; + + // Transmute events_ptr to Events type + let mut events = vec![0u8; std::mem::size_of::()]; + mem_mgr + .shared_mem + .copy_to_slice(&mut events, events_ptr - SandboxMemoryLayout::BASE_ADDRESS) + .map_err(|e| { + new_error!( + "Failed to copy guest trace batch from guest memory to host: {:?}", + e + ) + })?; + + let events: Events = unsafe { + let raw = events.as_slice() as *const _ as *const Events; + raw.read_unaligned() + }; + + Ok(TraceBatch { + guest_start_tsc, + spans, + events, + }) + } +} + +/// This structure handles the guest tracing information. +pub struct TraceContext { + host_spans: Vec, + guest_spans: HashMap, + in_host_call: bool, + + // Lazily initialized members + start_wall: Option, + /// The epoch at which the call into the guest started, if it has started. + /// This is used to calculate the time spent in the guest relative to the + /// time when the call into the guest was first made. + start_instant: Option, + /// The start guest time, in TSC cycles, for the current guest measured on the host. + /// It contains the TSC value recorded on the host before a call is made into the guest. + /// This is used to calculate the TSC frequency which is the same on the host and guest. + /// The TSC frequency is used to convert TSC values to timestamps in the trace. + /// **NOTE**: This is only used until the TSC frequency is calculated, when the first + /// records are received. + start_tsc: Option, + /// The frequency of the timestamp counter. + tsc_freq: Option, + current_parent_ctx: Option, +} + +impl TraceContext { + /// Initialize with current context + pub fn new() -> Self { + if !hyperlight_guest_tracing::invariant_tsc::has_invariant_tsc() { + // If the platform does not support invariant TSC, warn the user. + // On Azure nested virtualization, the TSC invariant bit is not correctly reported, this is a known issue. + log::warn!( + "Invariant TSC is not supported on this platform, trace timestamps may be inaccurate" + ); + } + + let current_ctx = Span::current().context(); + + let span = tracing::trace_span!("call-to-guest"); + let _ = span.set_parent(current_ctx); + let entered = span.entered(); + + Self { + host_spans: vec![entered], + guest_spans: HashMap::new(), + in_host_call: false, + + start_wall: None, + start_instant: None, + start_tsc: None, + tsc_freq: None, + current_parent_ctx: None, + } + } + + /// Calculate the frequency of the TimeStamp Counter. + /// This is done by: + /// - first reading a timestamp and an `Instant` + /// - secondly reading another timestamp and `Instant` + /// - calculate the frequency based on the `Duration` between + /// the two `Instant`s read. + fn calculate_tsc_freq(&mut self) -> Result<()> { + let (start, start_time) = match (self.start_tsc.as_ref(), self.start_instant.as_ref()) { + (Some(start), Some(start_time)) => (*start, *start_time), + _ => { + // If the guest start TSC and time are not set, we use the current time and TSC. + // This is not ideal, but it allows us to calculate the TSC frequency without + // failing. + // This is a fallback mechanism to ensure that we can still calculate, however it + // should be noted that this may lead to inaccuracies in the TSC frequency. + // The start time should be already set before running the guest for each sandbox. + log::error!( + "Guest start TSC and time are not set. Calculating TSC frequency will use current time and TSC." + ); + ( + hyperlight_guest_tracing::invariant_tsc::read_tsc(), + std::time::Instant::now(), + ) + } + }; + + let end_time = std::time::Instant::now(); + let end = hyperlight_guest_tracing::invariant_tsc::read_tsc(); + + let elapsed = end_time.duration_since(start_time).as_secs_f64(); + let tsc_freq = ((end - start) as f64 / elapsed) as u64; + + log::info!("Calculated TSC frequency: {} Hz", tsc_freq); + self.tsc_freq = Some(tsc_freq); + + Ok(()) + } + + /// Calculate timestamp relative to wall time stored on host + fn calculate_guest_time_relative_to_host( + &self, + guest_start_tsc: u64, + tsc: u64, + ) -> Result { + // Should never fail as it is extracted after it is set + let tsc_freq = self.tsc_freq.ok_or(new_error!("TSC frequency not set"))?; + + // Number of cycles relative to guest start + let rel_cycles = tsc.saturating_sub(guest_start_tsc); + + // Number of micro seconds from guest start to `tsc` argument + let rel_start_us = rel_cycles as f64 / tsc_freq as f64 * 1_000_000f64; + + // Final timestamp is calculated by: + // - starting from the wall time when the sandbox was created + // - adding the Duration to the guest start + // - adding the Duration from the guest start to the provided `tsc` + Ok(self.start_wall.ok_or(new_error!("start_wall not set"))? + + Duration::from_micros(rel_start_us as u64)) + } + + pub fn handle_trace( + &mut self, + regs: &CommonRegisters, + mem_mgr: &SandboxMemoryManager, + ) -> Result<()> { + if self.tsc_freq.is_none() { + self.calculate_tsc_freq()?; + } + + // Get the guest sent info + let trace_batch = TraceBatch::try_from((regs, mem_mgr))?; + + let tracer = global::tracer("guest-tracer"); + let mut spans_to_remove = vec![]; + + let mut current_active_span = None; + + // Update the spans map + for s in trace_batch.spans.iter() { + let start_ts = self + .calculate_guest_time_relative_to_host(trace_batch.guest_start_tsc, s.start_tsc)?; + let end_ts = s.end_tsc.map(|tsc| { + self.calculate_guest_time_relative_to_host(trace_batch.guest_start_tsc, tsc) + }); + let parent_id = s.parent_id; + let parent_ctx = if let Some(parent_id) = parent_id { + if let Some(span) = self.guest_spans.get(&parent_id) { + Context::new().with_remote_span_context(span.span_context().clone()) + } else if let Some(parent_ctx) = self.current_parent_ctx.as_ref() { + parent_ctx.clone() + } else { + Span::current().context().clone() + } + } else if let Some(parent_ctx) = self.current_parent_ctx.as_ref() { + parent_ctx.clone() + } else { + Span::current().context().clone() + }; + + // Get the saved span, modify it and set it back to avoid borrow checker + let mut span = self.guest_spans.remove(&s.id).unwrap_or_else(|| { + let mut sb = tracer + .span_builder(s.name.to_string()) + .with_start_time(start_ts); + sb.attributes = Some(vec![KeyValue::new("target", s.target.to_string())]); + let mut span = sb.start_with_context(&tracer, &parent_ctx); + + for (k, v) in s.fields.iter() { + span.set_attribute(KeyValue::new( + k.as_str().to_string(), + v.as_str().to_string(), + )); + } + + span + }); + + // If we find an end timestamp it means the span has been closed + // otherwise store it for later + if let Some(ts) = end_ts { + span.end_with_timestamp(ts?); + spans_to_remove.push(s.id); + } else { + current_active_span = + Some(Context::current().with_remote_span_context(span.span_context().clone())); + } + + self.guest_spans.insert(s.id, span); + } + + // Create the events + for ev in trace_batch.events.iter() { + let ts = + self.calculate_guest_time_relative_to_host(trace_batch.guest_start_tsc, ev.tsc)?; + let mut attributes: Vec = ev + .fields + .iter() + .map(|(k, v)| KeyValue::new(k.to_string(), v.to_string())) + .collect(); + + attributes.push(KeyValue::new( + "level", + tracing::Level::from(ev.level).to_string(), + )); + + // Add the event to the parent span + // It should always have a parent span + if let Some(span) = self.guest_spans.get_mut(&ev.parent_id) { + span.add_event_with_timestamp(ev.name.to_string(), ts, attributes); + } + } + + // Remove the spans that have been closed + for id in spans_to_remove.into_iter() { + self.guest_spans.remove(&id); + } + + if let Some(ctx) = current_active_span { + self.new_host_trace(ctx); + }; + + Ok(()) + } + + pub(crate) fn setup_guest_trace(&mut self, ctx: Context) { + if self.start_instant.is_none() { + crate::debug!("Guest Start Epoch set"); + self.start_wall = Some(SystemTime::now()); + self.start_tsc = Some(hyperlight_guest_tracing::invariant_tsc::read_tsc()); + self.start_instant = Some(std::time::Instant::now()); + } + self.current_parent_ctx = Some(ctx); + } + + pub fn new_host_trace(&mut self, ctx: Context) { + let span = tracing::trace_span!("call-to-host"); + let _ = span.set_parent(ctx); + let entered = span.entered(); + self.host_spans.push(entered); + self.in_host_call = true; + } + + pub fn end_host_trace(&mut self) { + if self.in_host_call + && let Some(entered) = self.host_spans.pop() + { + entered.exit(); + } + } +} + +impl Drop for TraceContext { + fn drop(&mut self) { + for (k, mut v) in self.guest_spans.drain() { + v.end(); + log::debug!("Dropped guest span with id {}", k); + } + while let Some(entered) = self.host_spans.pop() { + entered.exit(); + } + } +} diff --git a/src/hyperlight_host/src/sandbox/trace/mod.rs b/src/hyperlight_host/src/sandbox/trace/mod.rs index 47ffd9125..f955a6d76 100644 --- a/src/hyperlight_host/src/sandbox/trace/mod.rs +++ b/src/hyperlight_host/src/sandbox/trace/mod.rs @@ -14,6 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ +/// Tracing context support for sandboxes. +mod context; +pub(crate) use context::TraceContext; + /// Tracing and profiling support for sandboxes. #[cfg(feature = "mem_profile")] mod mem_profile; From a11b54edd5db8ec6058ce0733dc5e18f64179850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Sun, 31 Aug 2025 15:01:21 +0300 Subject: [PATCH 261/271] [trace-guest] update guest crates to add trace instrumentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - conditionally handle logs either through tracing or the dedicated VM exit based on whether tracing is initialized on the guest - modify `test_with_small_stack_and_heap` to 18kB because the `#[intrument]` attributes use more stack. Signed-off-by: Doru Blânzeanu --- Cargo.lock | 2 + src/hyperlight_guest/Cargo.toml | 1 + src/hyperlight_guest/src/exit.rs | 3 + .../src/guest_handle/host_comm.rs | 62 +++++++++++++------ src/hyperlight_guest/src/guest_handle/io.rs | 3 + src/hyperlight_guest_bin/Cargo.toml | 2 +- .../src/guest_function/call.rs | 4 ++ src/hyperlight_guest_bin/src/paging.rs | 3 + src/hyperlight_guest_tracing/src/lib.rs | 11 +++- .../src/sandbox/initialized_multi_use.rs | 2 +- src/tests/rust_guests/dummyguest/Cargo.lock | 2 + src/tests/rust_guests/simpleguest/Cargo.lock | 2 + src/tests/rust_guests/witguest/Cargo.lock | 2 + 13 files changed, 78 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34a3a4506..1ad1a78f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1429,6 +1429,7 @@ dependencies = [ "hyperlight-common", "hyperlight-guest-tracing", "serde_json", + "tracing", ] [[package]] @@ -1445,6 +1446,7 @@ dependencies = [ "hyperlight-guest-tracing", "log", "spin 0.10.0", + "tracing", ] [[package]] diff --git a/src/hyperlight_guest/Cargo.toml b/src/hyperlight_guest/Cargo.toml index e15b1e996..f031e2d6c 100644 --- a/src/hyperlight_guest/Cargo.toml +++ b/src/hyperlight_guest/Cargo.toml @@ -17,6 +17,7 @@ serde_json = { version = "1.0", default-features = false, features = ["alloc"] } hyperlight-common = { workspace = true } hyperlight-guest-tracing = { workspace = true, default-features = false } flatbuffers = { version= "25.9.23", default-features = false } +tracing = { version = "0.1.41", default-features = false, features = ["attributes"] } [features] default = [] diff --git a/src/hyperlight_guest/src/exit.rs b/src/hyperlight_guest/src/exit.rs index 4ac359e04..cc91aad9e 100644 --- a/src/hyperlight_guest/src/exit.rs +++ b/src/hyperlight_guest/src/exit.rs @@ -18,9 +18,11 @@ use core::arch::asm; use core::ffi::{CStr, c_char}; use hyperlight_common::outb::OutBAction; +use tracing::instrument; /// Halt the execution of the guest and returns control to the host. #[inline(never)] +#[instrument(skip_all, level = "Trace")] pub fn halt() { #[cfg(feature = "trace_guest")] { @@ -121,6 +123,7 @@ pub(crate) fn outb(port: u16, data: &[u8]) { } /// OUT function for sending a 32-bit value to the host. +#[instrument(skip_all, level = "Trace")] pub(crate) unsafe fn out32(port: u16, val: u32) { #[cfg(feature = "trace_guest")] { diff --git a/src/hyperlight_guest/src/guest_handle/host_comm.rs b/src/hyperlight_guest/src/guest_handle/host_comm.rs index 66429c3a5..8ae22fb49 100644 --- a/src/hyperlight_guest/src/guest_handle/host_comm.rs +++ b/src/hyperlight_guest/src/guest_handle/host_comm.rs @@ -30,6 +30,7 @@ use hyperlight_common::flatbuffer_wrappers::guest_log_level::LogLevel; use hyperlight_common::flatbuffer_wrappers::host_function_details::HostFunctionDetails; use hyperlight_common::flatbuffer_wrappers::util::estimate_flatbuffer_capacity; use hyperlight_common::outb::OutBAction; +use tracing::instrument; use super::handle::GuestHandle; use crate::error::{HyperlightGuestError, Result}; @@ -37,6 +38,7 @@ use crate::exit::out32; impl GuestHandle { /// Get user memory region as bytes. + #[instrument(skip_all, level = "Trace")] pub fn read_n_bytes_from_user_memory(&self, num: u64) -> Result> { let peb_ptr = self.peb().unwrap(); let user_memory_region_ptr = unsafe { (*peb_ptr).init_data.ptr as *mut u8 }; @@ -124,6 +126,7 @@ impl GuestHandle { /// sends it to the host, and then retrieves the return value. /// /// The return value is deserialized into the specified type `T`. + #[instrument(skip_all, level = "Trace")] pub fn call_host_function>( &self, function_name: &str, @@ -134,6 +137,7 @@ impl GuestHandle { self.get_host_return_value::() } + #[instrument(skip_all, level = "Trace")] pub fn get_host_function_details(&self) -> HostFunctionDetails { let peb_ptr = self.peb().unwrap(); let host_function_details_buffer = @@ -159,24 +163,46 @@ impl GuestHandle { source_file: &str, line: u32, ) { - let guest_log_data = GuestLogData::new( - message.to_string(), - source.to_string(), - log_level, - caller.to_string(), - source_file.to_string(), - line, - ); - - let bytes: Vec = guest_log_data - .try_into() - .expect("Failed to convert GuestLogData to bytes"); - - self.push_shared_output_data(&bytes) - .expect("Unable to push log data to shared output data"); - - unsafe { - out32(OutBAction::Log as u16, 0); + // Closure to send log message to host + let send_to_host = || { + let guest_log_data = GuestLogData::new( + message.to_string(), + source.to_string(), + log_level, + caller.to_string(), + source_file.to_string(), + line, + ); + + let bytes: Vec = guest_log_data + .try_into() + .expect("Failed to convert GuestLogData to bytes"); + + self.push_shared_output_data(&bytes) + .expect("Unable to push log data to shared output data"); + + unsafe { + out32(OutBAction::Log as u16, 0); + } + }; + + #[cfg(feature = "trace_guest")] + if hyperlight_guest_tracing::is_trace_enabled() { + // If the "trace_guest" feature is enabled and tracing is initialized, log using tracing + tracing::trace!( + event = message, + level = ?log_level, + code.filepath = source, + caller = caller, + source_file = source_file, + code.lineno = line, + ); + } else { + send_to_host(); + } + #[cfg(not(feature = "trace_guest"))] + { + send_to_host(); } } } diff --git a/src/hyperlight_guest/src/guest_handle/io.rs b/src/hyperlight_guest/src/guest_handle/io.rs index c3e39512f..a494033dd 100644 --- a/src/hyperlight_guest/src/guest_handle/io.rs +++ b/src/hyperlight_guest/src/guest_handle/io.rs @@ -20,12 +20,14 @@ use core::any::type_name; use core::slice::from_raw_parts_mut; use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; +use tracing::{Span, instrument}; use super::handle::GuestHandle; use crate::error::{HyperlightGuestError, Result}; impl GuestHandle { /// Pops the top element from the shared input data buffer and returns it as a T + #[instrument(skip_all, parent = Span::current(), level= "Trace")] pub fn try_pop_shared_input_data_into(&self) -> Result where T: for<'a> TryFrom<&'a [u8]>, @@ -87,6 +89,7 @@ impl GuestHandle { } /// Pushes the given data onto the shared output data buffer. + #[instrument(skip_all, parent = Span::current(), level= "Trace")] pub fn push_shared_output_data(&self, data: &[u8]) -> Result<()> { let peb_ptr = self.peb().unwrap(); let output_stack_size = unsafe { (*peb_ptr).output_stack.size as usize }; diff --git a/src/hyperlight_guest_bin/Cargo.toml b/src/hyperlight_guest_bin/Cargo.toml index 56c52d240..24f4c1d1b 100644 --- a/src/hyperlight_guest_bin/Cargo.toml +++ b/src/hyperlight_guest_bin/Cargo.toml @@ -28,7 +28,7 @@ buddy_system_allocator = "0.11.0" log = { version = "0.4", default-features = false } spin = "0.10.0" flatbuffers = { version = "25.2.10", default-features = false } - +tracing = { version = "0.1.41", default-features = false, features = ["attributes"] } [lints] workspace = true diff --git a/src/hyperlight_guest_bin/src/guest_function/call.rs b/src/hyperlight_guest_bin/src/guest_function/call.rs index 6d49aced8..b5bba301b 100644 --- a/src/hyperlight_guest_bin/src/guest_function/call.rs +++ b/src/hyperlight_guest_bin/src/guest_function/call.rs @@ -23,11 +23,13 @@ use hyperlight_common::flatbuffer_wrappers::function_types::{FunctionCallResult, use hyperlight_common::flatbuffer_wrappers::guest_error::{ErrorCode, GuestError}; use hyperlight_guest::error::{HyperlightGuestError, Result}; use hyperlight_guest::exit::halt; +use tracing::{Span, instrument}; use crate::{GUEST_HANDLE, REGISTERED_GUEST_FUNCTIONS}; type GuestFunc = fn(&FunctionCall) -> Result>; +#[instrument(skip_all, parent = Span::current(), level= "Trace")] pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result> { // Validate this is a Guest Function Call if function_call.function_call_type() != FunctionCallType::Guest { @@ -83,6 +85,7 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result // This function may panic, as we have no other ways of dealing with errors at this level #[unsafe(no_mangle)] #[inline(never)] +#[instrument(skip_all, parent = Span::current(), level= "Trace")] fn internal_dispatch_function() { let handle = unsafe { GUEST_HANDLE }; @@ -116,6 +119,7 @@ fn internal_dispatch_function() { // This is implemented as a separate function to make sure that epilogue in the internal_dispatch_function is called before the halt() // which if it were included in the internal_dispatch_function cause the epilogue to not be called because the halt() would not return // when running in the hypervisor. +#[instrument(skip_all, parent = Span::current(), level= "Trace")] pub(crate) extern "C" fn dispatch_function() { // The hyperlight host likes to use one partition and reset it in // various ways; if that has happened, there might stale TLB diff --git a/src/hyperlight_guest_bin/src/paging.rs b/src/hyperlight_guest_bin/src/paging.rs index 749900349..4ee3d827a 100644 --- a/src/hyperlight_guest_bin/src/paging.rs +++ b/src/hyperlight_guest_bin/src/paging.rs @@ -17,6 +17,8 @@ limitations under the License. use alloc::alloc::Layout; use core::arch::asm; +use tracing::{Span, instrument}; + use crate::OS_PAGE_SIZE; /// Convert a physical address in main memory to a virtual address @@ -61,6 +63,7 @@ struct MapResponse { /// as such do not use concurrently with any other page table operations /// - TLB invalidation is not performed, /// if previously-unmapped ranges are not being mapped, TLB invalidation may need to be performed afterwards. +#[instrument(skip_all, parent = Span::current(), level= "Trace")] pub unsafe fn map_region(phys_base: u64, virt_base: *mut u8, len: u64) { let mut pml4_base: u64; unsafe { diff --git a/src/hyperlight_guest_tracing/src/lib.rs b/src/hyperlight_guest_tracing/src/lib.rs index 771e2d820..ded4e91aa 100644 --- a/src/hyperlight_guest_tracing/src/lib.rs +++ b/src/hyperlight_guest_tracing/src/lib.rs @@ -38,7 +38,8 @@ mod visitor; pub use state::TraceBatchInfo; #[cfg(feature = "trace")] pub use trace::{ - clean_trace_state, end_trace, guest_trace_info, init_guest_tracing, set_start_tsc, + clean_trace_state, end_trace, guest_trace_info, init_guest_tracing, is_trace_enabled, + set_start_tsc, }; /// Maximum number of spans that the guest can store @@ -212,4 +213,12 @@ mod trace { } res } + + /// Returns true if tracing is enabled (the guest tracing state is initialized). + pub fn is_trace_enabled() -> bool { + GUEST_STATE + .get() + .map(|w| w.upgrade().is_some()) + .unwrap_or(false) + } } diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 6dc02d71f..bbb23638b 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -602,7 +602,7 @@ mod tests { fn test_with_small_stack_and_heap() { let mut cfg = SandboxConfiguration::default(); cfg.set_heap_size(20 * 1024); - cfg.set_stack_size(16 * 1024); + cfg.set_stack_size(18 * 1024); let mut sbox1: MultiUseSandbox = { let path = simple_guest_as_string().unwrap(); diff --git a/src/tests/rust_guests/dummyguest/Cargo.lock b/src/tests/rust_guests/dummyguest/Cargo.lock index c95757748..8844a2bb2 100644 --- a/src/tests/rust_guests/dummyguest/Cargo.lock +++ b/src/tests/rust_guests/dummyguest/Cargo.lock @@ -113,6 +113,7 @@ dependencies = [ "hyperlight-common", "hyperlight-guest-tracing", "serde_json", + "tracing", ] [[package]] @@ -129,6 +130,7 @@ dependencies = [ "hyperlight-guest-tracing", "log", "spin 0.10.0", + "tracing", ] [[package]] diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index 4008b7025..d75b3fc8b 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -105,6 +105,7 @@ dependencies = [ "hyperlight-common", "hyperlight-guest-tracing", "serde_json", + "tracing", ] [[package]] @@ -121,6 +122,7 @@ dependencies = [ "hyperlight-guest-tracing", "log", "spin 0.10.0", + "tracing", ] [[package]] diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index f2c6b0dae..1cf11ca57 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -248,6 +248,7 @@ dependencies = [ "hyperlight-common", "hyperlight-guest-tracing", "serde_json", + "tracing", ] [[package]] @@ -264,6 +265,7 @@ dependencies = [ "hyperlight-guest-tracing", "log", "spin 0.10.0", + "tracing", ] [[package]] From 4ac02782d26ca4cdb9efc2c7ae8a86f4485101b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Sun, 31 Aug 2025 15:05:55 +0300 Subject: [PATCH 262/271] [trace-guest] add spans in simpleguest sample MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- src/tests/rust_guests/simpleguest/Cargo.lock | 1 + src/tests/rust_guests/simpleguest/Cargo.toml | 1 + src/tests/rust_guests/simpleguest/src/main.rs | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index d75b3fc8b..5edd3cc30 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -262,6 +262,7 @@ dependencies = [ "hyperlight-guest-bin", "hyperlight-guest-tracing", "log", + "tracing", ] [[package]] diff --git a/src/tests/rust_guests/simpleguest/Cargo.toml b/src/tests/rust_guests/simpleguest/Cargo.toml index 1e0be5af0..183698bf3 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.toml +++ b/src/tests/rust_guests/simpleguest/Cargo.toml @@ -9,6 +9,7 @@ hyperlight-guest-bin = { path = "../../../hyperlight_guest_bin" } hyperlight-common = { path = "../../../hyperlight_common", default-features = false } hyperlight-guest-tracing = { path = "../../../hyperlight_guest_tracing" } log = {version = "0.4", default-features = false } +tracing = { version = "0.1.41", default-features = false, features = ["attributes"] } [features] default = [] diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index b8219ea69..2c23368e6 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -53,6 +53,7 @@ use hyperlight_guest_bin::host_comm::{ use hyperlight_guest_bin::memory::malloc; use hyperlight_guest_bin::{MIN_STACK_ADDRESS, guest_logger}; use log::{LevelFilter, error}; +use tracing::{Span, instrument}; extern crate hyperlight_guest; @@ -91,6 +92,7 @@ fn echo_float(function_call: &FunctionCall) -> Result> { } } +#[instrument(skip_all, parent = Span::current(), level= "Trace")] fn print_output(message: &str) -> Result> { let res = call_host_function::( "HostPrint", @@ -101,6 +103,7 @@ fn print_output(message: &str) -> Result> { Ok(get_flatbuffer_result(res)) } +#[instrument(skip_all, parent = Span::current(), level= "Trace")] fn simple_print_output(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(message) = function_call.parameters.clone().unwrap()[0].clone() { print_output(&message) @@ -919,6 +922,7 @@ fn call_host_expect_error(function_call: &FunctionCall) -> Result> { } #[no_mangle] +#[instrument(skip_all, parent = Span::current(), level= "Trace")] pub extern "C" fn hyperlight_main() { let expect_error_def = GuestFunctionDefinition::new( "CallHostExpectError".to_string(), @@ -1640,6 +1644,7 @@ fn fuzz_host_function(func: FunctionCall) -> Result> { } #[no_mangle] +#[instrument(skip_all, parent = Span::current(), level= "Trace")] pub fn guest_dispatch_function(function_call: FunctionCall) -> Result> { // This test checks the stack behavior of the input/output buffer // by calling the host before serializing the function call. From 13282188328893083f587644fc23da83188b7952 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Thu, 11 Sep 2025 01:39:27 +0300 Subject: [PATCH 263/271] update tracing docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- docs/hyperlight-metrics-logs-and-traces.md | 48 +++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/docs/hyperlight-metrics-logs-and-traces.md b/docs/hyperlight-metrics-logs-and-traces.md index 2dbf7bc25..3e04f576a 100644 --- a/docs/hyperlight-metrics-logs-and-traces.md +++ b/docs/hyperlight-metrics-logs-and-traces.md @@ -98,7 +98,7 @@ Hyperlight provides advanced observability features for guest code running insid The following features are available for guest tracing: - `trace_guest`: Enables tracing for guest code, capturing function calls and execution time. -- `mem_profile`: Enables memory profiling for guest code with stack uwinding, capturing memory allocations and usage. +- `mem_profile`: Enables memory profiling for guest code with stack unwinding, capturing memory allocations and usage. ### Building a Guest with Tracing Support @@ -109,19 +109,57 @@ just build-rust-guests debug trace_guest just move-rust-guests debug ``` -This will build the guest binaries with the `trace_guest` feature enabled and move them to the appropriate location for use by the host. +This builds the guest binaries with the `trace_guest` feature enabled and move them to the appropriate location for use by the host. + +**NOTE**: To enable the tracing in your application you need to use the `trace_guest` feature on the `hyperlight-guest-bin` and `hyperlight-guest` crates. ### Running a Hyperlight Example with Guest Tracing Once the guest is built, you can run a Hyperlight example with guest tracing enabled. For example: ```bash -cargo run --example hello-world --features trace_guest +RUST_LOG="info,hyperlight_host::sandbox=info,hyperlight_guest=trace,hyperlight_guest_bin=trace" cargo run --example tracing-otlp --features trace_guest ``` -This will execute the `hello-world` example, loading the guest with tracing enabled. During execution, trace data will be collected and written to a file in the `trace` directory. +This will execute the `tracing-otlp` example, loading the guest with tracing enabled. +During execution, trace data will be collected on the host and exported as `opentelemetry` spans/events. + +You can set up a collector to gather all the traces and inspect the traces from both host and guests. + +Due to the nature of execution inside a Sandbox, on a call basis, the guest tracing sets up a stack of spans to keep track of the correct parents for the incoming +guest spans. +We start with `call-to-guest` which contains all the spans coming from a guest. Additionally, for each exit into the host, we add another layer marking it with +a `call-to-host` span to follow the execution in the host and correctly set it as a child of the active span in the guest. +This logic simulates the propagation of `Opentelemetry` context that is usually done between two services, but cannot be done here seamlessly because the guest side +runs `no_std` which `opentelemetry` doesn't know. + +#### How it works + +##### Guest + +When the guest starts executing the `entrypoint` function, it receives a `max_log_level` parameter that tells the guest what kind of logging level is expected from it. + +The `trace_guest` logic takes advantage of this parameter and when the `max_log_level` is `trace`, it allocates a custom made `GuestSubscriber` that implements the `Subscriber` +trait from `tracing_core` that allows defining a subscriber for the `tracing` crate to handle new spans and events. + +This custom subscriber stores the spans and events in a buffer initialized only when tracing is enabled. For each new span and event, a method is called on the custom subscriber which not only stores the data, but also keeps track of the hierarchy and dependencies between the other spans/events. +**NOTE**: The spans/events attributes are truncated to fit in the allocated buffer. + +When the storage space is filled, the guest triggers a VM Exit that sends the guest pointers to the host. The host can access the guest memory, get the data and parse it to create the `spans` and `events` using the `opentelemetry` crate which allows specifying the starting and ending timestamps +which are captured in the guest using the `TSC`. + +To improve performance, for each VMExit, the guest adds metadata for the host to be able to report the tracing data and free space. + +##### Host + +When a guest exits, the host checks for metadata from the guest reporting tracing data. +If tracing data is found, the host starts parsing it and reconstructing a tree which represents the spans hierarchy. + +Additionally, the host also adds new children `span`s to the guest's reported active span, emphasizing the spans created on the host as a result of a temporary VM Exit. This helps visualize a call into the guest with context propagated across the VM boundary. + +The host creates `opentelemetry` spans and events for each guest span and event reported. -### Inspecting Guest Trace Files +### Inspecting Guest memory Trace Files (for mem_profile) To inspect the trace file generated by the guest, use the `trace_dump` crate. You will need the path to the guest symbols and the trace file. Run the following command: From 09bed268593eb0b57154d2059c7b28dae10b1ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Thu, 23 Oct 2025 15:35:56 +0300 Subject: [PATCH 264/271] Remove CI and Justfile recipies related to seccomp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- .github/workflows/dep_rust.yml | 4 ++-- Justfile | 12 +++--------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index a6acefd1c..c9a94f7ea 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -146,8 +146,8 @@ jobs: # with default features just test ${{ inputs.config }} ${{ inputs.hypervisor == 'mshv' && 'mshv2' || '""'}} - # with only one driver enabled (driver mshv/kvm feature is ignored on windows) + seccomp - just test ${{ inputs.config }} seccomp,${{ inputs.hypervisor == 'mshv' && 'mshv2' || inputs.hypervisor == 'mshv3' && 'mshv3' || 'kvm' }} + # with only one driver enabled (driver mshv/kvm feature is ignored on windows) + just test ${{ inputs.config }} ${{ inputs.hypervisor == 'mshv' && 'mshv2' || inputs.hypervisor == 'mshv3' && 'mshv3' || 'kvm' }} # make sure certain cargo features compile just check diff --git a/Justfile b/Justfile index 274c076ac..67925f662 100644 --- a/Justfile +++ b/Justfile @@ -80,8 +80,8 @@ test-like-ci config=default-target hypervisor="kvm": @# with default features just test {{config}} {{ if hypervisor == "mshv" {"mshv2"} else {""} }} - @# with only one driver enabled + seccomp + build-metadata + init-paging - just test {{config}} seccomp,build-metadata,init-paging,{{ if hypervisor == "mshv" {"mshv2"} else if hypervisor == "mshv3" {"mshv3"} else {"kvm"} }} + @# with only one driver enabled + build-metadata + init-paging + just test {{config}} build-metadata,init-paging,{{ if hypervisor == "mshv" {"mshv2"} else if hypervisor == "mshv3" {"mshv3"} else {"kvm"} }} @# make sure certain cargo features compile just check @@ -145,7 +145,7 @@ like-ci config=default-target hypervisor="kvm": {{ if config == "release" { "just bench-ci main " + if hypervisor == "mshv" { "mshv2" } else if hypervisor == "mshv3" { "mshv3" } else { "kvm" } } else { "" } }} # runs all tests -test target=default-target features="": (test-unit target features) (test-isolated target features) (test-integration "rust" target features) (test-integration "c" target features) (test-seccomp target features) (test-doc target features) +test target=default-target features="": (test-unit target features) (test-isolated target features) (test-integration "rust" target features) (test-integration "c" target features) (test-doc target features) # runs unit tests test-unit target=default-target features="": @@ -170,12 +170,6 @@ test-integration guest target=default-target features="": @# run the rest of the integration tests {{if os() == "windows" { "$env:" } else { "" } }}GUEST="{{guest}}"{{if os() == "windows" { ";" } else { "" } }} {{ cargo-cmd }} test -p hyperlight-host {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --test '*' -# runs seccomp tests -test-seccomp target=default-target features="": - @# run seccomp test with feature "seccomp" on and off - {{ cargo-cmd }} test --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host test_violate_seccomp_filters --lib {{ if features =="" {''} else { "--features " + features } }} -- --ignored - {{ cargo-cmd }} test --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host test_violate_seccomp_filters --no-default-features {{ if features =~"mshv2" {"--features init-paging,mshv2"} else {"--features mshv3,init-paging,kvm" } }} --lib -- --ignored - # tests compilation with no default features on different platforms test-compilation-no-default-features target=default-target: @# Linux should fail without a hypervisor feature (kvm, mshv, or mshv3) From 23b15117cb9452d161ce552b835f2c4a24b0b88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Thu, 23 Oct 2025 15:38:56 +0300 Subject: [PATCH 265/271] Remove seccomp related tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- .../src/sandbox/initialized_multi_use.rs | 157 ------------------ src/hyperlight_host/tests/integration_test.rs | 6 - src/tests/rust_guests/simpleguest/src/main.rs | 21 --- 3 files changed, 184 deletions(-) diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index bbb23638b..b1fd45fa1 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -655,163 +655,6 @@ mod tests { assert_eq!(res, 0); } - #[test] - // TODO: Investigate why this test fails with an incorrect error when run alongside other tests - #[ignore] - #[cfg(target_os = "linux")] - fn test_violate_seccomp_filters() -> Result<()> { - fn make_get_pid_syscall() -> Result { - let pid = unsafe { libc::syscall(libc::SYS_getpid) }; - Ok(pid as u64) - } - - // First, run to make sure it fails. - { - let mut usbox = UninitializedSandbox::new( - GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")), - None, - ) - .unwrap(); - - usbox.register("MakeGetpidSyscall", make_get_pid_syscall)?; - - let mut sbox: MultiUseSandbox = usbox.evolve()?; - - let res: Result = sbox.call("ViolateSeccompFilters", ()); - - #[cfg(seccomp)] - match res { - Ok(_) => panic!("Expected to fail due to seccomp violation"), - Err(e) => match e { - HyperlightError::GuestError(t, msg) - if t == ErrorCode::HostFunctionError - && msg.contains("Seccomp filter trapped on disallowed syscall") => {} - _ => panic!("Expected DisallowedSyscall error: {}", e), - }, - } - - #[cfg(not(seccomp))] - match res { - Ok(_) => (), - Err(e) => panic!("Expected to succeed without seccomp: {}", e), - } - } - - // Second, run with allowing `SYS_getpid` - #[cfg(seccomp)] - { - let mut usbox = UninitializedSandbox::new( - GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")), - None, - ) - .unwrap(); - - usbox.register_with_extra_allowed_syscalls( - "MakeGetpidSyscall", - make_get_pid_syscall, - vec![libc::SYS_getpid], - )?; - // ^^^ note, we are allowing SYS_getpid - - let mut sbox: MultiUseSandbox = usbox.evolve()?; - - let res: Result = sbox.call("ViolateSeccompFilters", ()); - - match res { - Ok(_) => {} - Err(e) => panic!("Expected to succeed due to seccomp violation: {}", e), - } - } - - Ok(()) - } - - // We have a secomp specifically for `openat`, but we don't want to crash on `openat`, but rather make sure `openat` returns `EACCES` - #[test] - #[cfg(target_os = "linux")] - fn violate_seccomp_filters_openat() -> Result<()> { - // Hostcall to call `openat`. - fn make_openat_syscall() -> Result { - use std::ffi::CString; - - let path = CString::new("/proc/sys/vm/overcommit_memory").unwrap(); - - let fd_or_err = unsafe { - libc::syscall( - libc::SYS_openat, - libc::AT_FDCWD, - path.as_ptr(), - libc::O_RDONLY, - ) - }; - - if fd_or_err == -1 { - Ok((-std::io::Error::last_os_error().raw_os_error().unwrap()).into()) - } else { - Ok(fd_or_err) - } - } - { - // First make sure a regular call to `openat` on /proc/sys/vm/overcommit_memory succeeds - let ret = make_openat_syscall()?; - assert!( - ret >= 0, - "Expected openat syscall to succeed, got: {:?}", - ret - ); - - let mut ubox = UninitializedSandbox::new( - GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")), - None, - ) - .unwrap(); - ubox.register("Openat_Hostfunc", make_openat_syscall)?; - - let mut sbox = ubox.evolve().unwrap(); - let host_func_result = sbox - .call::( - "CallGivenParamlessHostFuncThatReturnsI64", - "Openat_Hostfunc".to_string(), - ) - .expect("Expected to call host function that returns i64"); - - if cfg!(seccomp) { - // If seccomp is enabled, we expect the syscall to return EACCES, as setup by our seccomp filter - assert_eq!(host_func_result, -libc::EACCES as i64); - } else { - // If seccomp is not enabled, we expect the syscall to succeed - assert!(host_func_result >= 0); - } - } - - #[cfg(seccomp)] - { - // Now let's make sure if we register the `openat` syscall as an extra allowed syscall, it will succeed - let mut ubox = UninitializedSandbox::new( - GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")), - None, - ) - .unwrap(); - ubox.register_with_extra_allowed_syscalls( - "Openat_Hostfunc", - make_openat_syscall, - [libc::SYS_openat], - )?; - let mut sbox = ubox.evolve().unwrap(); - let host_func_result: i64 = sbox - .call::( - "CallGivenParamlessHostFuncThatReturnsI64", - "Openat_Hostfunc".to_string(), - ) - .expect("Expected to call host function that returns i64"); - - // should pass regardless of seccomp feature - assert!(host_func_result >= 0); - } - - Ok(()) - } - #[test] fn test_trigger_exception_on_guest() { let usbox = UninitializedSandbox::new( diff --git a/src/hyperlight_host/tests/integration_test.rs b/src/hyperlight_host/tests/integration_test.rs index 0869a9d5a..b252aa947 100644 --- a/src/hyperlight_host/tests/integration_test.rs +++ b/src/hyperlight_host/tests/integration_test.rs @@ -49,14 +49,8 @@ fn interrupt_host_call() { Ok(()) }; - #[cfg(any(target_os = "windows", not(seccomp)))] usbox.register("Spin", spin).unwrap(); - #[cfg(seccomp)] - usbox - .register_with_extra_allowed_syscalls("Spin", spin, vec![libc::SYS_clock_nanosleep]) - .unwrap(); - let mut sandbox: MultiUseSandbox = usbox.evolve().unwrap(); let interrupt_handle = sandbox.interrupt_handle(); assert!(!interrupt_handle.dropped()); // not yet dropped diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index 2c23368e6..eda988f33 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -720,19 +720,6 @@ fn twenty_four_k_in_eight_k_out(function_call: &FunctionCall) -> Result> } } -fn violate_seccomp_filters(function_call: &FunctionCall) -> Result> { - if function_call.parameters.is_none() { - let res = call_host_function::("MakeGetpidSyscall", None, ReturnType::ULong)?; - - Ok(get_flatbuffer_result(res)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to violate_seccomp_filters".to_string(), - )) - } -} - fn call_given_paramless_hostfunc_that_returns_i64(function_call: &FunctionCall) -> Result> { if let ParameterValue::String(hostfuncname) = function_call.parameters.clone().unwrap()[0].clone() @@ -1416,14 +1403,6 @@ pub extern "C" fn hyperlight_main() { ); register_function(add_to_static_and_fail_def); - let violate_seccomp_filters_def = GuestFunctionDefinition::new( - "ViolateSeccompFilters".to_string(), - Vec::new(), - ReturnType::ULong, - violate_seccomp_filters as usize, - ); - register_function(violate_seccomp_filters_def); - let echo_float_def = GuestFunctionDefinition::new( "EchoFloat".to_string(), Vec::from(&[ParameterType::Float]), From 37bdf3d187e3fac7c52c4da0aec274ad70a05a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Thu, 23 Oct 2025 15:55:54 +0300 Subject: [PATCH 266/271] Remove seccomp feature from hyperlight-host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- Cargo.lock | 10 -- src/hyperlight_host/Cargo.toml | 4 +- src/hyperlight_host/build.rs | 1 - src/hyperlight_host/src/error.rs | 15 -- .../src/func/host_functions.rs | 35 +--- src/hyperlight_host/src/lib.rs | 2 - src/hyperlight_host/src/metrics/mod.rs | 25 +-- src/hyperlight_host/src/sandbox/host_funcs.rs | 64 +------ .../src/sandbox/uninitialized.rs | 70 +------- src/hyperlight_host/src/seccomp/guest.rs | 159 ------------------ src/hyperlight_host/src/seccomp/mod.rs | 39 ----- .../src/signal_handlers/mod.rs | 31 ---- .../signal_handlers/sigsys_signal_handler.rs | 87 ---------- src/tests/rust_guests/witguest/Cargo.lock | 4 +- 14 files changed, 9 insertions(+), 537 deletions(-) delete mode 100644 src/hyperlight_host/src/seccomp/guest.rs delete mode 100644 src/hyperlight_host/src/seccomp/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 1ad1a78f9..0c823ae83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1508,7 +1508,6 @@ dependencies = [ "proptest", "rand", "rust-embed", - "seccompiler", "serde", "serde_json", "serial_test", @@ -3076,15 +3075,6 @@ version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" -[[package]] -name = "seccompiler" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ae55de56877481d112a559bbc12667635fdaf5e005712fd4e2b2fa50ffc884" -dependencies = [ - "libc", -] - [[package]] name = "semver" version = "1.0.26" diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 76935b5b2..1f4899c12 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -75,7 +75,6 @@ windows-version = "0.1" lazy_static = "1.4.0" [target.'cfg(unix)'.dependencies] -seccompiler = { version = "0.5.0", optional = true } kvm-bindings = { version = "0.14", features = ["fam-wrappers"], optional = true } kvm-ioctls = { version = "0.24", optional = true } mshv-bindings2 = { package="mshv-bindings", version = "=0.2.1", optional = true } @@ -126,8 +125,7 @@ cfg_aliases = "0.2.1" built = { version = "0.8.0", optional = true, features = ["chrono", "git2"] } [features] -default = ["kvm", "mshv3", "seccomp", "build-metadata", "init-paging"] -seccomp = ["dep:seccompiler"] +default = ["kvm", "mshv3", "build-metadata", "init-paging"] function_call_metrics = [] executable_heap = [] # This feature enables printing of debug information to stdout in debug builds diff --git a/src/hyperlight_host/build.rs b/src/hyperlight_host/build.rs index bef001b22..6c90a485f 100644 --- a/src/hyperlight_host/build.rs +++ b/src/hyperlight_host/build.rs @@ -101,7 +101,6 @@ fn main() -> Result<()> { // the other features they want. mshv2: { all(feature = "mshv2", target_os = "linux") }, mshv3: { all(feature = "mshv3", not(feature="mshv2"), target_os = "linux") }, - seccomp: { all(feature = "seccomp", target_os = "linux", not(target_env = "musl")) }, } #[cfg(feature = "build-metadata")] diff --git a/src/hyperlight_host/src/error.rs b/src/hyperlight_host/src/error.rs index 9ecce9968..99e46b7c9 100644 --- a/src/hyperlight_host/src/error.rs +++ b/src/hyperlight_host/src/error.rs @@ -69,11 +69,6 @@ pub enum HyperlightError { #[error("Error converting CString {0:?}")] CStringConversionError(#[from] std::ffi::NulError), - /// A disallowed syscall was caught - #[error("Seccomp filter trapped on disallowed syscall (check STDERR for offending syscall)")] - #[cfg(seccomp)] - DisallowedSyscall, - /// A generic error with a message #[error("{0}")] Error(String), @@ -216,16 +211,6 @@ pub enum HyperlightError { #[error("Stack overflow detected")] StackOverflow(), - /// a backend error occurred with seccomp filters - #[error("Backend Error with Seccomp Filter {0:?}")] - #[cfg(seccomp)] - SeccompFilterBackendError(#[from] seccompiler::BackendError), - - /// an error occurred with seccomp filters - #[error("Error with Seccomp Filter {0:?}")] - #[cfg(seccomp)] - SeccompFilterError(#[from] seccompiler::Error), - /// Tried to restore snapshot to a sandbox that is not the same as the one the snapshot was taken from #[error("Snapshot was taken from a different sandbox")] SnapshotSandboxMismatch, diff --git a/src/hyperlight_host/src/func/host_functions.rs b/src/hyperlight_host/src/func/host_functions.rs index a0fcbb52f..6764a07c2 100644 --- a/src/hyperlight_host/src/func/host_functions.rs +++ b/src/hyperlight_host/src/func/host_functions.rs @@ -20,8 +20,8 @@ use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, Ret use super::utils::for_each_tuple; use super::{ParameterTuple, ResultType, SupportedReturnType}; +use crate::sandbox::UninitializedSandbox; use crate::sandbox::host_funcs::FunctionEntry; -use crate::sandbox::{ExtraAllowedSyscall, UninitializedSandbox}; use crate::{Result, new_error}; /// A sandbox on which (primitive) host functions can be registered @@ -33,15 +33,6 @@ pub trait Registerable { name: &str, hf: impl Into>, ) -> Result<()>; - /// Register a primitive host function whose worker thread has - /// extra permissive seccomp filters installed - #[cfg(seccomp)] - fn register_host_function_with_syscalls( - &mut self, - name: &str, - hf: impl Into>, - eas: Vec, - ) -> Result<()>; } impl Registerable for UninitializedSandbox { fn register_host_function( @@ -56,28 +47,6 @@ impl Registerable for UninitializedSandbox { let entry = FunctionEntry { function: hf.into().into(), - extra_allowed_syscalls: None, - parameter_types: Args::TYPE, - return_type: Output::TYPE, - }; - - (*hfs).register_host_function(name.to_string(), entry, &mut self.mgr) - } - #[cfg(seccomp)] - fn register_host_function_with_syscalls( - &mut self, - name: &str, - hf: impl Into>, - eas: Vec, - ) -> Result<()> { - let mut hfs = self - .host_funcs - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?; - - let entry = FunctionEntry { - function: hf.into().into(), - extra_allowed_syscalls: Some(eas), parameter_types: Args::TYPE, return_type: Output::TYPE, }; @@ -195,13 +164,11 @@ pub(crate) fn register_host_function>, sandbox: &mut UninitializedSandbox, name: &str, - extra_allowed_syscalls: Option>, ) -> Result<()> { let func = func.into().into(); let entry = FunctionEntry { function: func, - extra_allowed_syscalls: extra_allowed_syscalls.clone(), parameter_types: Args::TYPE, return_type: Output::TYPE, }; diff --git a/src/hyperlight_host/src/lib.rs b/src/hyperlight_host/src/lib.rs index 10e8a898a..5f034dc79 100644 --- a/src/hyperlight_host/src/lib.rs +++ b/src/hyperlight_host/src/lib.rs @@ -76,8 +76,6 @@ pub mod metrics; /// outside this file. Types from this module needed for public consumption are /// re-exported below. pub mod sandbox; -#[cfg(seccomp)] -pub(crate) mod seccomp; /// Signal handling for Linux #[cfg(target_os = "linux")] pub(crate) mod signal_handlers; diff --git a/src/hyperlight_host/src/metrics/mod.rs b/src/hyperlight_host/src/metrics/mod.rs index 67a7b0eca..3a630fa44 100644 --- a/src/hyperlight_host/src/metrics/mod.rs +++ b/src/hyperlight_host/src/metrics/mod.rs @@ -133,11 +133,7 @@ mod tests { if #[cfg(feature = "function_call_metrics")] { use metrics::Label; - let expected_num_metrics = if cfg!(all(seccomp)) { - 3 // if seccomp enabled, the host call duration metric is emitted on a separate thread which this local recorder doesn't capture - } else { - 4 - }; + let expected_num_metrics = 4; // Verify that the histogram metrics are recorded correctly assert_eq!(snapshot.len(), expected_num_metrics); @@ -185,25 +181,6 @@ mod tests { ), "Histogram metric does not match expected value" ); - - if !cfg!(all(seccomp)) { - // 4. Host call duration - let histogram_key = CompositeKey::new( - metrics_util::MetricKind::Histogram, - Key::from_parts( - METRIC_HOST_FUNC_DURATION, - vec![Label::new("function_name", "HostPrint")], - ), - ); - let histogram_value = &snapshot.get(&histogram_key).unwrap().2; - assert!( - matches!( - histogram_value, - metrics_util::debugging::DebugValue::Histogram(histogram) if histogram.len() == 1 - ), - "Histogram metric does not match expected value" - ); - } } else { // Verify that the counter metrics are recorded correctly assert_eq!(snapshot.len(), 1); diff --git a/src/hyperlight_host/src/sandbox/host_funcs.rs b/src/hyperlight_host/src/sandbox/host_funcs.rs index b61a2cd77..52160539a 100644 --- a/src/hyperlight_host/src/sandbox/host_funcs.rs +++ b/src/hyperlight_host/src/sandbox/host_funcs.rs @@ -25,7 +25,6 @@ use hyperlight_common::flatbuffer_wrappers::host_function_details::HostFunctionD use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; use tracing::{Span, instrument}; -use super::ExtraAllowedSyscall; use crate::HyperlightError::HostFunctionNotFound; use crate::func::host_functions::TypeErasedHostFunction; use crate::mem::mgr::SandboxMemoryManager; @@ -58,7 +57,6 @@ impl From<&mut FunctionRegistry> for HostFunctionDetails { pub struct FunctionEntry { pub function: TypeErasedHostFunction, - pub extra_allowed_syscalls: Option>, pub parameter_types: &'static [ParameterType], pub return_type: ReturnType, } @@ -119,7 +117,6 @@ impl FunctionRegistry { fn call_host_func_impl(&self, name: &str, args: Vec) -> Result { let FunctionEntry { function, - extra_allowed_syscalls, parameter_types: _, return_type: _, } = self @@ -127,10 +124,8 @@ impl FunctionRegistry { .get(name) .ok_or_else(|| HostFunctionNotFound(name.to_string()))?; - // Create a new thread when seccomp is enabled on Linux - maybe_with_seccomp(name, extra_allowed_syscalls.as_deref(), || { - crate::metrics::maybe_time_and_emit_host_call(name, || function.call(args)) - }) + // Make the host function call + crate::metrics::maybe_time_and_emit_host_call(name, || function.call(args)) } } @@ -153,58 +148,3 @@ pub(super) fn default_writer_func(s: String) -> Result { } } } - -#[cfg(seccomp)] -fn maybe_with_seccomp( - name: &str, - syscalls: Option<&[ExtraAllowedSyscall]>, - f: impl FnOnce() -> Result + Send, -) -> Result { - use std::thread; - - use crate::seccomp::guest::get_seccomp_filter_for_host_function_worker_thread; - - // Use a scoped thread so that we can pass around references without having to clone them. - thread::scope(|s| { - thread::Builder::new() - .name(format!("Host Function Worker Thread for: {name:?}")) - .spawn_scoped(s, move || { - let seccomp_filter = get_seccomp_filter_for_host_function_worker_thread(syscalls)?; - seccomp_filter - .iter() - .try_for_each(|filter| seccompiler::apply_filter(filter))?; - - // We have a `catch_unwind` here because, if a disallowed syscall is issued, - // we handle it by panicking. This is to avoid returning execution to the - // offending host function—for two reasons: (1) if a host function is issuing - // disallowed syscalls, it could be unsafe to return to, and (2) returning - // execution after trapping the disallowed syscall can lead to UB (e.g., try - // running a host function that attempts to sleep without `SYS_clock_nanosleep`, - // you'll block the syscall but panic in the aftermath). - match std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)) { - Ok(val) => val, - Err(err) => { - if let Some(crate::HyperlightError::DisallowedSyscall) = - err.downcast_ref::() - { - return Err(crate::HyperlightError::DisallowedSyscall); - } - - crate::log_then_return!("Host function {} panicked", name); - } - } - })? - .join() - .map_err(|_| new_error!("Error joining thread executing host function"))? - }) -} - -#[cfg(not(seccomp))] -fn maybe_with_seccomp( - _name: &str, - _syscalls: Option<&[ExtraAllowedSyscall]>, - f: impl FnOnce() -> Result + Send, -) -> Result { - // No seccomp, just call the function - f() -} diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index c4b08da2f..fb09572a9 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -35,21 +35,6 @@ use crate::mem::shared_mem::ExclusiveSharedMemory; use crate::sandbox::SandboxConfiguration; use crate::{MultiUseSandbox, Result, new_error}; -#[cfg(seccomp)] -const EXTRA_ALLOWED_SYSCALLS_FOR_WRITER_FUNC: &[super::ExtraAllowedSyscall] = &[ - // Fuzzing fails without `mmap` being an allowed syscall on our seccomp filter. - // All fuzzing does is call `PrintOutput` (which calls `HostPrint` ). Thing is, `println!` - // is designed to be thread-safe in Rust and the std lib ensures this by using - // buffered I/O, which I think relies on `mmap`. This gets surfaced in fuzzing with an - // OOM error, which I think is happening because `println!` is not being able to allocate - // more memory for its buffers for the fuzzer's huge inputs. - libc::SYS_mmap, - libc::SYS_brk, - libc::SYS_mprotect, - #[cfg(mshv)] - libc::SYS_close, -]; - #[cfg(any(crashdump, gdb))] #[derive(Clone, Debug, Default)] pub(crate) struct SandboxRuntimeConfig { @@ -304,25 +289,7 @@ impl UninitializedSandbox { name: impl AsRef, host_func: impl Into>, ) -> Result<()> { - register_host_function(host_func, self, name.as_ref(), None) - } - - /// Registers a host function with additional allowed syscalls during execution. - /// - /// Unlike [`register`](Self::register), this variant allows specifying extra syscalls - /// that will be permitted when the function handler runs. - #[cfg(seccomp)] - pub fn register_with_extra_allowed_syscalls< - Args: ParameterTuple, - Output: SupportedReturnType, - >( - &mut self, - name: impl AsRef, - host_func: impl Into>, - extra_allowed_syscalls: impl IntoIterator, - ) -> Result<()> { - let extra_allowed_syscalls: Vec<_> = extra_allowed_syscalls.into_iter().collect(); - register_host_function(host_func, self, name.as_ref(), Some(extra_allowed_syscalls)) + register_host_function(host_func, self, name.as_ref()) } /// Registers the special "HostPrint" function for guest printing. @@ -334,40 +301,7 @@ impl UninitializedSandbox { &mut self, print_func: impl Into>, ) -> Result<()> { - #[cfg(not(seccomp))] - self.register("HostPrint", print_func)?; - - #[cfg(seccomp)] - self.register_with_extra_allowed_syscalls( - "HostPrint", - print_func, - EXTRA_ALLOWED_SYSCALLS_FOR_WRITER_FUNC.iter().copied(), - )?; - - Ok(()) - } - - /// Registers the "HostPrint" function with additional allowed syscalls. - /// - /// Like [`register_print`](Self::register_print), but allows specifying extra syscalls - /// that will be permitted during function execution. - #[cfg(seccomp)] - pub fn register_print_with_extra_allowed_syscalls( - &mut self, - print_func: impl Into>, - extra_allowed_syscalls: impl IntoIterator, - ) -> Result<()> { - #[cfg(seccomp)] - self.register_with_extra_allowed_syscalls( - "HostPrint", - print_func, - EXTRA_ALLOWED_SYSCALLS_FOR_WRITER_FUNC - .iter() - .copied() - .chain(extra_allowed_syscalls), - )?; - - Ok(()) + self.register("HostPrint", print_func) } } // Check to see if the current version of Windows is supported diff --git a/src/hyperlight_host/src/seccomp/guest.rs b/src/hyperlight_host/src/seccomp/guest.rs deleted file mode 100644 index c55d40686..000000000 --- a/src/hyperlight_host/src/seccomp/guest.rs +++ /dev/null @@ -1,159 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -use seccompiler::SeccompCmpOp::Eq; -use seccompiler::{ - BpfProgram, SeccompAction, SeccompCmpArgLen as ArgLen, SeccompCondition as Cond, SeccompFilter, - SeccompRule, TargetArch, -}; - -use crate::sandbox::ExtraAllowedSyscall; -use crate::{Result, and, or}; - -fn syscalls_allowlist() -> Result)>> { - Ok(vec![ - // SYS_signalstack, SYS_munmap, SYS_rt_sigprocmask, SYS_madvise, and SYS_exit - // are minimally required syscalls to be able to setup our seccomp filter. - (libc::SYS_sigaltstack, vec![]), - (libc::SYS_munmap, vec![]), - (libc::SYS_rt_sigprocmask, vec![]), - (libc::SYS_madvise, vec![]), - (libc::SYS_exit, vec![]), - // SYS_rt_sigaction, SYS_write, and SYS_rt_sigreturn are required for the - // signal handler inside the host function worker thread. - (libc::SYS_rt_sigaction, vec![]), - ( - libc::SYS_write, - or![ - and![Cond::new(0, ArgLen::Dword, Eq, 1)?], // stdout - and![Cond::new(0, ArgLen::Dword, Eq, 2)?], // stderr - ], - ), - (libc::SYS_rt_sigreturn, vec![]), - // Note: This `ioctl` is used to get information about the terminal. - // I believe it is used to get terminal information by our default writer function. - // That said, I am registering it here instead of in the function specifically - // because we don't currently support registering parameterized syscalls. - ( - libc::SYS_ioctl, - or![and![Cond::new( - 1, - ArgLen::Dword, - Eq, - #[cfg(all( - target_arch = "x86_64", - target_vendor = "unknown", - target_os = "linux", - target_env = "musl" - ))] - libc::TCGETS.try_into()?, - #[cfg(not(all( - target_arch = "x86_64", - target_vendor = "unknown", - target_os = "linux", - target_env = "musl" - )))] - libc::TCGETS, - )?]], - ), - // `futex` is needed for some tests that run in parallel (`simple_test_parallel`, - // and `callback_test_parallel`). - (libc::SYS_futex, vec![]), - // `sched_yield` is needed for many synchronization primitives that may be invoked - // on the host function worker thread - (libc::SYS_sched_yield, vec![]), - // `mprotect` is needed by malloc during memory allocation - (libc::SYS_mprotect, vec![]), - // `openat` is marked allowed here because it may be called by `libc::free()` - // since it will try to open /proc/sys/vm/overcommit_memory (https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/malloc-sysdep.h;h=778d8971d53e284397c3a5dcdd923e93be5e4731;hb=HEAD) - // We have another more restrictive filter for it below so it will return EACCES instead of trap, in which case libc will use the default value - (libc::SYS_openat, vec![]), - ]) -} - -/// Creates two `BpfProgram`s for a `SeccompFilter` over specific syscalls/`SeccompRule`s -/// intended to be applied on host function threads. -/// -/// Note: This does not provide coverage over the Hyperlight host, which is why we don't need -/// `SeccompRules` for operations we definitely perform but are outside the handler thread -/// (e.g., `KVM_SET_USER_MEMORY_REGION`, `KVM_GET_API_VERSION`, `KVM_CREATE_VM`, -/// or `KVM_CREATE_VCPU`). -pub(crate) fn get_seccomp_filter_for_host_function_worker_thread( - extra_allowed_syscalls: Option<&[ExtraAllowedSyscall]>, -) -> Result> { - let mut allowed_syscalls = syscalls_allowlist()?; - - if let Some(extra_allowed_syscalls) = extra_allowed_syscalls { - allowed_syscalls.extend( - extra_allowed_syscalls - .iter() - .copied() - .map(|syscall| (syscall, vec![])), - ); - - // Remove duplicates - allowed_syscalls.sort_by(|a, b| a.0.cmp(&b.0)); - allowed_syscalls.dedup(); - } - - let arch: TargetArch = std::env::consts::ARCH.try_into()?; - - // Allowlist filter that traps on unknown syscalls - let allowlist = SeccompFilter::new( - allowed_syscalls.into_iter().collect(), - SeccompAction::Trap, - SeccompAction::Allow, - arch, - )? - .try_into()?; - - // If `openat` is an explicitly allowed syscall, we shouldn't return the filter that forces it to return EACCES. - if let Some(extra_syscalls) = extra_allowed_syscalls - && extra_syscalls.contains(&libc::SYS_openat) - { - return Ok(vec![allowlist]); - } - - // Otherwise, we return both filters. - - // Filter that forces `openat` to return EACCES - let errno_on_openat = SeccompFilter::new( - [(libc::SYS_openat, vec![])].into_iter().collect(), - SeccompAction::Allow, - SeccompAction::Errno(libc::EACCES.try_into()?), - arch, - )? - .try_into()?; - - // Note: the order of the 2 filters are important. If we applied the strict filter first, - // we wouldn't be allowed to setup the second filter (would be trapped since the syscalls to setup seccomp are not allowed). - // However, from an seccomp filter perspective, the order of the filters is not important: - // - // If multiple filters exist, they are all executed, in reverse order - // of their addition to the filter tree—that is, the most recently - // installed filter is executed first. (Note that all filters will - // be called even if one of the earlier filters returns - // SECCOMP_RET_KILL. This is done to simplify the kernel code and to - // provide a tiny speed-up in the execution of sets of filters by - // avoiding a check for this uncommon case.) The return value for - // the evaluation of a given system call is the first-seen action - // value of highest precedence (along with its accompanying data) - // returned by execution of all of the filters. - // - // (https://man7.org/linux/man-pages/man2/seccomp.2.html). - // - Ok(vec![errno_on_openat, allowlist]) -} diff --git a/src/hyperlight_host/src/seccomp/mod.rs b/src/hyperlight_host/src/seccomp/mod.rs deleted file mode 100644 index 9edce3ed2..000000000 --- a/src/hyperlight_host/src/seccomp/mod.rs +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// For more information on seccomp and its implementation in Hyperlight, -// refer to: https://github.com/hyperlight-dev/hyperlight/blob/dev/docs/seccomp.md - -/// This module defines all seccomp filters (i.e., used for blockage of non-specified syscalls) -/// needed for execution of guest code within Hyperlight through a syscalls allow-list. -pub(crate) mod guest; - -// The credit on the creation of the macros below goes to the cloud-hypervisor team -// (https://github.com/cloud-hypervisor/cloud-hypervisor/blob/main/vmm/src/seccomp_filters.rs) - -/// Shorthand for chaining `SeccompCondition`s with the `and` operator in a `SeccompRule`. -/// The rule will take the `Allow` action if _all_ the conditions are true. -#[macro_export] -macro_rules! and { - ($($x:expr),*) => (SeccompRule::new(vec![$($x),*]).unwrap()) -} - -/// Shorthand for chaining `SeccompRule`s with the `or` operator in a `SeccompFilter`. -#[macro_export] -macro_rules! or { - ($($x:expr,)*) => (vec![$($x),*]); - ($($x:expr),*) => (vec![$($x),*]) -} diff --git a/src/hyperlight_host/src/signal_handlers/mod.rs b/src/hyperlight_host/src/signal_handlers/mod.rs index 43a58977b..71bba7326 100644 --- a/src/hyperlight_host/src/signal_handlers/mod.rs +++ b/src/hyperlight_host/src/signal_handlers/mod.rs @@ -18,43 +18,12 @@ use libc::c_int; use crate::sandbox::SandboxConfiguration; -#[cfg(seccomp)] -pub mod sigsys_signal_handler; - pub(crate) fn setup_signal_handlers(config: &SandboxConfiguration) -> crate::Result<()> { // This is unsafe because signal handlers only allow a very restrictive set of // functions (i.e., async-signal-safe functions) to be executed inside them. // Anything that performs memory allocations, locks, and others are non-async-signal-safe. // Hyperlight signal handlers are all designed to be async-signal-safe, so this function // should be safe to call. - #[cfg(seccomp)] - { - use std::sync::Once; - - vmm_sys_util::signal::register_signal_handler( - libc::SIGSYS, - sigsys_signal_handler::handle_sigsys, - ) - .map_err(crate::HyperlightError::VmmSysError)?; - - static PANIC_HOOK_INIT: Once = Once::new(); - PANIC_HOOK_INIT.call_once(|| { - let original_hook = std::panic::take_hook(); - // Set a custom panic hook that checks for "DisallowedSyscall" - std::panic::set_hook(Box::new(move |panic_info| { - // Check if the panic payload matches "DisallowedSyscall" - if let Some(crate::HyperlightError::DisallowedSyscall) = panic_info - .payload() - .downcast_ref::( - ) { - // Do nothing to avoid superfluous syscalls - return; - } - // If not "DisallowedSyscall", use the original hook - original_hook(panic_info); - })); - }); - } vmm_sys_util::signal::register_signal_handler( libc::SIGRTMIN() + config.get_interrupt_vcpu_sigrtmin_offset() as c_int, vm_kill_signal, diff --git a/src/hyperlight_host/src/signal_handlers/sigsys_signal_handler.rs b/src/hyperlight_host/src/signal_handlers/sigsys_signal_handler.rs index 0202873f5..dc0572d55 100644 --- a/src/hyperlight_host/src/signal_handlers/sigsys_signal_handler.rs +++ b/src/hyperlight_host/src/signal_handlers/sigsys_signal_handler.rs @@ -14,93 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -#[cfg(seccomp)] -pub(super) extern "C" fn handle_sigsys( - signal: i32, - info: *mut libc::siginfo_t, - context: *mut libc::c_void, -) { - #[cfg(target_arch = "x86_64")] - { - unsafe { - // si_code contains the reason for the SIGSYS signal. - // SYS_SECCOMP is 1 as per: - // https://github.com/torvalds/linux/blob/81983758430957d9a5cb3333fe324fd70cf63e7e/include/uapi/asm-generic/siginfo.h#L301C9-L301C21 - const SYS_SECCOMP: libc::c_int = 1; - // Sanity checks to make sure SIGSYS was triggered by a BPF filter. - // If something else triggered a SIGSYS (i.e., kill()), we do nothing. - // Inspired by Chromium's sandbox: - // https://chromium.googlesource.com/chromium/chromium/+/master/sandbox/linux/seccomp-bpf/sandbox_bpf.cc#572 - if signal != libc::SIGSYS - || (*info).si_code != SYS_SECCOMP - || context.is_null() - || (*info).si_errno < 0 - { - let err_msg = - b"[ERROR][HYPERLIGHT] SIGSYS triggered by something other than a BPF filter\n"; - libc::write( - libc::STDERR_FILENO, - err_msg.as_ptr() as *const _, - err_msg.len(), - ); - return; - } - - let err_msg = b"[ERROR][HYPERLIGHT] Handling disallowed syscall\n"; - libc::write( - libc::STDERR_FILENO, - err_msg.as_ptr() as *const _, - err_msg.len(), - ); - - // We get the syscall number by accessing a particular offset in the `siginfo_t` struct. - // This only works because this is handling a SIGSYS signal (i.e., the `siginfo_t` struct - // is implemented as a union in the kernel: - // https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/siginfo.h). - // Note: This is not necessarily platform-agnostic, so we might want to be more careful here - // in the future. - const SI_OFF_SYSCALL: isize = 6; - let syscall = *(info as *const i32).offset(SI_OFF_SYSCALL) as usize; - let syscall_bytes = raw_format(b"[ERROR][HYPERLIGHT] Disallowed Syscall: ", syscall); - - // `write` as per https://man7.org/linux/man-pages/man7/signal-safety.7.html - // is async-signal-safe. - libc::write( - libc::STDERR_FILENO, - syscall_bytes.as_ptr() as *const _, - syscall_bytes.len(), - ); - - // Note: This is not necessarily platform-agnostic, so we might want to be more careful here - // in the future. - let ucontext = context as *mut libc::ucontext_t; - let mcontext = &mut (*ucontext).uc_mcontext; - - if syscall == libc::SYS_ioctl as usize { - let ioctl_param = mcontext.gregs[libc::REG_EBRACE as usize] as usize; - let ioctl_param_bytes = - raw_format(b"[ERROR][HYPERLIGHT] IOCTL Param: ", ioctl_param); - libc::write( - libc::STDERR_FILENO, - ioctl_param_bytes.as_ptr() as *const _, - ioctl_param_bytes.len(), - ); - } - - // We don't want to return execution to the offending host function, so - // we alter the RIP register to point to a function that will panic out of - // the host function call. - mcontext.gregs[libc::REG_RIP as usize] = - after_syscall_violation as usize as libc::greg_t; - } - } - - #[cfg(not(target_arch = "x86_64"))] - { - compile_error!("Unsupported architecture for seccomp feature"); - } -} - extern "C-unwind" fn after_syscall_violation() { #[allow(clippy::panic)] std::panic::panic_any(crate::HyperlightError::DisallowedSyscall); diff --git a/src/tests/rust_guests/witguest/Cargo.lock b/src/tests/rust_guests/witguest/Cargo.lock index 1cf11ca57..6172a003c 100644 --- a/src/tests/rust_guests/witguest/Cargo.lock +++ b/src/tests/rust_guests/witguest/Cargo.lock @@ -396,9 +396,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "8e0f6df8eaa422d97d72edcd152e1451618fed47fabbdbd5a8864167b1d4aff7" dependencies = [ "unicode-ident", ] From 1986fedfc83474a16d193d9e429e566de9c4d38e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= Date: Thu, 23 Oct 2025 15:56:29 +0300 Subject: [PATCH 267/271] Remove documentation related to seccomp support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Doru Blânzeanu --- docs/security.md | 2 -- docs/signal-handlers-development-notes.md | 20 ++++++-------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/docs/security.md b/docs/security.md index 10f96bd46..3ee86780c 100644 --- a/docs/security.md +++ b/docs/security.md @@ -19,5 +19,3 @@ All communication between the host and the guest is done through a shared memory Hyperlight provides a mechanism for the host to register functions that may be called from the guest. This mechanism is useful to allow developers to provide guests with strictly controlled access to functionality we don't make available by default inside the VM. This mechanism likely represents the largest attack surface area of this project. To mitigate the risk, only functions that have been explicitly exposed to the guest by the host application, are allowed to be called from the guest. Any attempt to call other host functions will result in an error. - -Additionally, we provide an API for using Seccomp filters to further restrict the system calls available to the host-provided functions, to help limit the impact of the un-audited or un-managed functions. diff --git a/docs/signal-handlers-development-notes.md b/docs/signal-handlers-development-notes.md index fca9d31a9..3cde0dafc 100644 --- a/docs/signal-handlers-development-notes.md +++ b/docs/signal-handlers-development-notes.md @@ -1,17 +1,9 @@ # Signal Handling in Hyperlight -Hyperlight registers custom signal handlers to intercept and manage specific signals, primarily `SIGSYS` and `SIGRTMIN`. Here's an overview of the registration process: -- **Preserving Old Handlers**: When registering a new signal handler, Hyperlight first retrieves and stores the existing handler using `OnceCell`. This allows Hyperlight to delegate signals to the original handler if necessary. +Hyperlight registers custom signal handlers to intercept and manage specific signals, primarily `SIGRTMIN`. Here's an overview of the registration process: - **Custom Handlers**: - - **`SIGSYS` Handler**: Captures disallowed syscalls enforced by seccomp. If the signal originates from a hyperlight thread, Hyperlight logs the syscall details. Otherwise, it delegates the signal to the previously registered handler. - - **`SIGRTMIN` Handler**: Utilized for inter-thread signaling, such as execution cancellation. Similar to SIGSYS, it distinguishes between application and non-hyperlight threads to determine how to handle the signal. -- **Thread Differentiation**: Hyperlight uses thread-local storage (IS_HYPERLIGHT_THREAD) to identify whether the current thread is a hyperlight thread. This distinction ensures that signals are handled appropriately based on the thread's role. - -## Potential Issues and Considerations - -### Handler Invalidation - -**Issue**: After Hyperlight registers its custom signal handler and preserves the `old_handler`, if the host or another component modifies the signal handler for the same signal, it can lead to: - - **Invalidation of `old_handler`**: The stored old_handler reference may no longer point to a valid handler, causing undefined behavior when Hyperlight attempts to delegate signals. - - **Loss of Custom Handling**: Hyperlight's custom handler might not be invoked as expected, disrupting its ability to enforce syscall restrictions or manage inter-thread signals. - + - **`SIGRTMIN` Handler**: Utilized for inter-thread signaling, such as execution cancellation. +- **Killing a sandbox**: + - To stop a sandboxed process, a `SIGRTMIN` signal must be delivered to the thread running the sandboxed code. + - The sandbox provides an interface to obtain an interrupt handle, which includes the thread ID and a method to dispatch the signal. + - Hyperlight uses the `pthread_kill` function to send this signal directly to the targeted thread. From 97cf2c677aa62cb7d6c5848fd8246c3430e91c9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Oct 2025 19:39:33 +0300 Subject: [PATCH 268/271] Bump syn from 2.0.107 to 2.0.108 (#967) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.107 to 2.0.108. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.107...2.0.108) --- updated-dependencies: - dependency-name: syn dependency-version: 2.0.108 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c823ae83..06bf1b8af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3302,9 +3302,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.107" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index 35a452689..6082b9828 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -19,7 +19,7 @@ proc-macro = true wasmparser = { version = "0.240.0" } quote = { version = "1.0.41" } proc-macro2 = { version = "1.0.102" } -syn = { version = "2.0.107" } +syn = { version = "2.0.108" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.37" } hyperlight-component-util = { workspace = true } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index 6a2e942b5..deb4078bf 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -18,7 +18,7 @@ name = "hyperlight_component_util" wasmparser = { version = "0.240.0" } quote = { version = "1.0.41" } proc-macro2 = { version = "1.0.102" } -syn = { version = "2.0.107" } +syn = { version = "2.0.108" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.37" } log = { version = "0.4" } \ No newline at end of file From 3063e4a20a33b946767672a34e06464eb8d459d3 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 23 Oct 2025 18:23:34 +0100 Subject: [PATCH 269/271] Crashdump on demand (#972) * Adds a function to create a core dump on demand Signed-off-by: Simon Davies * Add gdb script and update docs Signed-off-by: Simon Davies --------- Signed-off-by: Simon Davies --- docs/how-to-debug-a-hyperlight-guest.md | 40 ++++++++++++++++-- .../scripts/dump_all_sandboxes.gdb | 41 +++++++++++++++++++ .../src/sandbox/initialized_multi_use.rs | 41 +++++++++++++++++++ 3 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 src/hyperlight_host/scripts/dump_all_sandboxes.gdb diff --git a/docs/how-to-debug-a-hyperlight-guest.md b/docs/how-to-debug-a-hyperlight-guest.md index 0cf2e0753..f4b45e996 100644 --- a/docs/how-to-debug-a-hyperlight-guest.md +++ b/docs/how-to-debug-a-hyperlight-guest.md @@ -207,13 +207,12 @@ involved in the gdb debugging of a Hyperlight guest running inside a **KVM** or | └───────────────────────────────────────────────────────────────────────────────────────────────┘ ``` -## Dumping the guest state to an ELF core dump when an unhandled crash occurs +## Dumping the guest state to an ELF core dump -When a guest crashes because of an unknown VmExit or unhandled exception, the vCPU state is dumped to an `ELF` core dump file. +When a guest crashes because of an unknown VmExit or unhandled exception, the vCPU state can be optionally dumped to an `ELF` core dump file. This can be used to inspect the state of the guest at the time of the crash. -To make Hyperlight dump the state of the vCPU (general purpose registers, registers) to an `ELF` core dump file, enable the `crashdump` -feature and run. +To make Hyperlight dump the state of the vCPU (general purpose registers, registers) to an `ELF` core dump file, enable the `crashdump` feature and run. The feature enables the creation of core dump files for both debug and release builds of Hyperlight hosts. By default, Hyperlight places the core dumps in the temporary directory (platform specific). To change this, use the `HYPERLIGHT_CORE_DUMP_DIR` environment variable to specify a directory. @@ -227,6 +226,39 @@ To selectively disable this feature for a specific sandbox, you can set the `gue cfg.set_guest_core_dump(false); // Disable core dump for this sandbox ``` +## Creating a dump on demand + +You can also create a core dump of the current state of the guest on demand by calling the `generate_crashdump` method on the `InitializedMultiUseSandbox` instance. This can be useful for debugging issues in the guest that do not cause crashes (e.g., a guest function that does not return). + +This is only available when the `crashdump` feature is enabled and then only if the sandbox +is also configured to allow core dumps (which is the default behavior). + +### Example + +Attach to your running process with gdb and call this function: + +```shell +sudo gdb -p +(gdb) info threads +# find the thread that is running the guest function you want to debug +(gdb) thread +# switch to the frame where you have access to your MultiUseSandbox instance +(gdb) backtrace +(gdb) frame +# get the pointer to your MultiUseSandbox instance +# Get the sandbox pointer +(gdb) print sandbox +# Call the crashdump function with the pointer + # Call the crashdump function +call sandbox.generate_crashdump() +``` +The crashdump should be available `/tmp` or in the crash dump directory (see `HYPERLIGHT_CORE_DUMP_DIR` env var). To make this process easier, you can also create a gdb script that automates these steps. You can find an example script [here](../scripts/dump_all_sandboxes.gdb). This script will try and generate a crashdump for every active thread except thread 1 , it assumes that the variable sandbox exists in frame 15 on every thread. You can edit it to fit your needs. Then use it like this: + +```shell +(gdb) source scripts/dump_all_sandboxes.gdb +(gdb) dump_all_sandboxes +``` + ### Inspecting the core dump After the core dump has been created, to inspect the state of the guest, load the core dump file using `gdb` or `lldb`. diff --git a/src/hyperlight_host/scripts/dump_all_sandboxes.gdb b/src/hyperlight_host/scripts/dump_all_sandboxes.gdb new file mode 100644 index 000000000..f2ef79c5c --- /dev/null +++ b/src/hyperlight_host/scripts/dump_all_sandboxes.gdb @@ -0,0 +1,41 @@ +define dump_all_sandboxes + set pagination off + + # Get the total number of threads + info threads + + # Loop through all threads (adjust max if you have more than 200 threads) + set $thread_num = 2 + while $thread_num <= 200 + # Try to switch to this thread + thread $thread_num + + # Check if thread switch succeeded (GDB sets $_thread to current thread) + if $_thread == $thread_num + echo \n=== Thread + p $thread_num + echo ===\n + + # Go to frame 15 + frame 15 + + + set $sb = &sandbox + call sandbox.generate_crashdump() + + set $thread_num = $thread_num + 1 + else + # No more threads, exit loop + set $thread_num = 201 + end + end + + echo \nDone dumping all sandboxes\n + set pagination on +end + +document dump_all_sandboxes +Dump crashdumps for sandboxes on all threads (except thread 1). +Assumes sandbox is in frame 15 on each thread. +Usage: dump_all_sandboxes +end \ No newline at end of file diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index b1fd45fa1..765a1a898 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -475,6 +475,47 @@ impl MultiUseSandbox { pub fn interrupt_handle(&self) -> Arc { self.vm.interrupt_handle() } + /// Generate a crash dump of the current state of the VM underlying this sandbox. + /// + /// Creates an ELF core dump file that can be used for debugging. The dump + /// captures the current state of the sandbox including registers, memory regions, + /// and other execution context. + /// + /// The location of the core dump file is determined by the `HYPERLIGHT_CORE_DUMP_DIR` + /// environment variable. If not set, it defaults to the system's temporary directory. + /// + /// This is only available when the `crashdump` feature is enabled and then only if the sandbox + /// is also configured to allow core dumps (which is the default behavior). + /// + /// This can be useful for generating a crash dump from gdb when trying to debug issues in the + /// guest that dont cause crashes (e.g. a guest function that does not return) + /// + /// # Examples + /// + /// Attach to your running process with gdb and call this function: + /// + /// ```shell + /// sudo gdb -p + /// (gdb) info threads + /// # find the thread that is running the guest function you want to debug + /// (gdb) thread + /// # switch to the frame where you have access to your MultiUseSandbox instance + /// (gdb) backtrace + /// (gdb) frame + /// # get the pointer to your MultiUseSandbox instance + /// # Get the sandbox pointer + /// (gdb) print sandbox + /// # Call the crashdump function + /// call sandbox.generate_crashdump() + /// ``` + /// The crashdump should be available in crash dump directory (see `HYPERLIGHT_CORE_DUMP_DIR` env var). + /// + #[cfg(crashdump)] + #[instrument(err(Debug), skip_all, parent = Span::current())] + + pub fn generate_crashdump(&self) -> Result<()> { + crate::hypervisor::crashdump::generate_crashdump(self.vm.as_ref()) + } } impl Callable for MultiUseSandbox { From e0d762d84ca615e2eadfb462b7efc3774237efc1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Oct 2025 04:05:20 +0000 Subject: [PATCH 270/271] Bump heapless from 0.8.0 to 0.9.1 (#976) Bumps [heapless](https://github.com/rust-embedded/heapless) from 0.8.0 to 0.9.1. - [Release notes](https://github.com/rust-embedded/heapless/releases) - [Changelog](https://github.com/rust-embedded/heapless/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-embedded/heapless/compare/v0.8.0...v0.9.1) --- updated-dependencies: - dependency-name: heapless dependency-version: 0.9.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_guest_tracing/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 06bf1b8af..0f3c9ab16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1251,9 +1251,9 @@ checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "heapless" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +checksum = "b1edcd5a338e64688fbdcb7531a846cfd3476a54784dcb918a0844682bc7ada5" dependencies = [ "hash32", "serde", diff --git a/src/hyperlight_guest_tracing/Cargo.toml b/src/hyperlight_guest_tracing/Cargo.toml index 9c67daeaf..5109aba85 100644 --- a/src/hyperlight_guest_tracing/Cargo.toml +++ b/src/hyperlight_guest_tracing/Cargo.toml @@ -10,7 +10,7 @@ readme.workspace = true description = """Provides the tracing functionality for the hyperlight guest.""" [dependencies] -heapless = { version = "0.8.0", features = ["serde"] } +heapless = { version = "0.9.1", features = ["serde"] } hyperlight-common = { workspace = true, default-features = false } spin = "0.10.0" tracing = { version = "0.1.41", default-features = false, features = ["attributes"] } From 0195ff0189f74b5a80e129947d357d3dbb8becdc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Oct 2025 09:43:29 -0700 Subject: [PATCH 271/271] Bump proc-macro2 from 1.0.102 to 1.0.103 (#975) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.102 to 1.0.103. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.102...1.0.103) --- updated-dependencies: - dependency-name: proc-macro2 dependency-version: 1.0.103 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- src/hyperlight_component_macro/Cargo.toml | 2 +- src/hyperlight_component_util/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f3c9ab16..ea3d1c39c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2647,9 +2647,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e0f6df8eaa422d97d72edcd152e1451618fed47fabbdbd5a8864167b1d4aff7" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] diff --git a/src/hyperlight_component_macro/Cargo.toml b/src/hyperlight_component_macro/Cargo.toml index 6082b9828..c9e2f4406 100644 --- a/src/hyperlight_component_macro/Cargo.toml +++ b/src/hyperlight_component_macro/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] wasmparser = { version = "0.240.0" } quote = { version = "1.0.41" } -proc-macro2 = { version = "1.0.102" } +proc-macro2 = { version = "1.0.103" } syn = { version = "2.0.108" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.37" } diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index deb4078bf..338335f10 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -17,7 +17,7 @@ name = "hyperlight_component_util" [dependencies] wasmparser = { version = "0.240.0" } quote = { version = "1.0.41" } -proc-macro2 = { version = "1.0.102" } +proc-macro2 = { version = "1.0.103" } syn = { version = "2.0.108" } itertools = { version = "0.14.0" } prettyplease = { version = "0.2.37" }