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 1/3] 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 2/3] [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 3/3] 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