Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3ebb69a
Update cargo hash in flake.nix
adamperlin Aug 22, 2025
7ab4735
Remove allocations in panic handler by formatting panic message
adamperlin Aug 28, 2025
65d1676
Clear buffer before recursive panics
adamperlin Aug 22, 2025
6a3b887
Update cargoHash in flake.nix
adamperlin Aug 22, 2025
b7d9e40
Remove unused imports
adamperlin Aug 22, 2025
33450d3
Add copyright header to fixed_buf.rrs
adamperlin Aug 22, 2025
f96c81e
Call abort_with_code_and_message directly in case of format failure i…
adamperlin Aug 22, 2025
6754a7e
Update src/hyperlight_host/tests/integration_test.rs
adamperlin Aug 22, 2025
4b13017
Update src/tests/rust_guests/simpleguest/src/main.rs
adamperlin Aug 22, 2025
abe4d0f
Make FixedBuf take ownership of underlying byte slice
adamperlin Aug 22, 2025
a5ba136
Apply cargo fmt
adamperlin Aug 25, 2025
e3cdbc7
Remove unused import
adamperlin Aug 25, 2025
afb1ee5
1. Add vec allocation after alloc::alloc failure to ensure panic in
adamperlin Aug 25, 2025
fe3eb06
Use heapless crate instead of custom fixed string buffer
adamperlin Aug 26, 2025
51269c7
Downgrade heapless to 0.8.0 to fix cargo crash
adamperlin Aug 26, 2025
246518c
apply cargo fmt
adamperlin Aug 26, 2025
c58668d
Remove whitespace in panic handler and rename test function in
adamperlin Aug 28, 2025
1df1be6
Write null terminator as part of initial panic message format
adamperlin Aug 29, 2025
43e5480
Stack allocate panic message buffer to avoid use of mutex on static
adamperlin Aug 29, 2025
f75d9fc
Merge remote-tracking branch 'hl-origin/main' into adamperlin/panic-r…
adamperlin Sep 2, 2025
cf5efdb
Increase panic buffer size and add description to format error message
adamperlin Sep 2, 2025
e9f5ace
Create an fmt::Write implementation that writes formatted string to p…
adamperlin Sep 3, 2025
12f46ba
Remove heapless dependency
adamperlin Sep 3, 2025
1732dce
Merge remote-tracking branch 'hl-origin/main' into adamperlin/panic-r…
adamperlin Sep 3, 2025
92b1ca7
fmt-apply
adamperlin Sep 4, 2025
b894870
Remove unnecessary unsafe in write_abort
adamperlin Sep 4, 2025
16697ed
Merge remote-tracking branch 'hl-origin/main' into adamperlin/panic-r…
adamperlin Sep 5, 2025
4230484
Merge branch 'main' into adamperlin/panic-remove-allocations
jsturtevant Sep 9, 2025
4844ee3
Update src/hyperlight_guest/src/exit.rs
jsturtevant Sep 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
pname = "hyperlight";
version = "0.0.0";
src = lib.cleanSource ./.;
cargoHash = "sha256-mNKnsaSKVz4khzWO7VhmN0cR+Ed5ML7fD1PJJCeQQ6E=";
cargoHash = "sha256-hoeJEBdxaoyLlhQQ4X4Wk5X1QVtQ7RRQYaxkiGg8rWA=";

nativeBuildInputs = [
azure-cli
Expand Down
1 change: 1 addition & 0 deletions src/hyperlight_guest_bin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ 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"
heapless = "0.8.0"

[lints]
workspace = true
Expand Down
40 changes: 35 additions & 5 deletions src/hyperlight_guest_bin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ limitations under the License.
// === Dependencies ===
extern crate alloc;

use alloc::string::ToString;
use core::ffi::CStr;
use core::fmt::Write;

use buddy_system_allocator::LockedHeap;
#[cfg(target_arch = "x86_64")]
use exceptions::{gdt::load_gdt, idtr::load_idt};
use guest_function::call::dispatch_function;
use guest_function::register::GuestFunctionRegister;
use guest_logger::init_logger;
use heapless::String;
use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
use hyperlight_common::mem::HyperlightPEB;
#[cfg(feature = "mem_profile")]
Expand Down Expand Up @@ -139,11 +141,39 @@ 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)
}

#[inline(always)]
fn _panic_handler(info: &core::panic::PanicInfo) -> ! {
// stack allocate a 512-byte message buffer.
let mut panic_buf = String::<512>::new();
let write_res = write!(panic_buf, "{}\0", info);
if write_res.is_err() {
unsafe {
abort_with_code_and_message(
&[ErrorCode::UnknownError as u8],
c"panic: message format failed (limit: 512 bytes)".as_ptr(),
)
}
}

unsafe { abort_with_code_and_message(&[ErrorCode::UnknownError as u8], c_string.as_ptr()) }
let c_str_res = CStr::from_bytes_with_nul(panic_buf.as_bytes());
if c_str_res.is_err() {
unsafe {
abort_with_code_and_message(
&[ErrorCode::UnknownError as u8],
c"panic: failed to convert to CString".as_ptr(),
)
}
}

unsafe {
abort_with_code_and_message(
&[ErrorCode::UnknownError as u8],
c_str_res.unwrap().as_ptr(),
)
}
}

// === Entrypoint ===
Expand Down
30 changes: 30 additions & 0 deletions src/hyperlight_host/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,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::<i32>(
"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() {
Expand Down
32 changes: 32 additions & 0 deletions src/tests/rust_guests/callbackguest/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions src/tests/rust_guests/dummyguest/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions src/tests/rust_guests/simpleguest/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions src/tests/rust_guests/simpleguest/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -507,6 +508,23 @@ fn call_malloc(function_call: &FunctionCall) -> Result<Vec<u8>> {
}
}

#[hyperlight_guest_tracing::trace_function]
unsafe fn exhaust_heap(_: &FunctionCall) -> ! {
let layout: Layout = Layout::new::<u8>();
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::<i32>::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<Vec<u8>> {
if let ParameterValue::Int(size) = function_call.parameters.clone().unwrap()[0].clone() {
Expand Down Expand Up @@ -1023,6 +1041,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]),
Expand Down
Loading
Loading