1use std::fmt::Debug;
18use std::option::Option;
19use std::path::Path;
20use std::sync::{Arc, Mutex};
21
22use log::LevelFilter;
23use tracing::{Span, instrument};
24
25use super::host_funcs::{FunctionRegistry, default_writer_func};
26use super::mem_mgr::MemMgrWrapper;
27use super::uninitialized_evolve::evolve_impl_multi_use;
28use crate::func::host_functions::{HostFunction, register_host_function};
29use crate::func::{ParameterTuple, SupportedReturnType};
30#[cfg(feature = "build-metadata")]
31use crate::log_build_details;
32use crate::mem::exe::ExeInfo;
33use crate::mem::mgr::{STACK_COOKIE_LEN, SandboxMemoryManager};
34use crate::mem::shared_mem::ExclusiveSharedMemory;
35use crate::sandbox::SandboxConfiguration;
36use crate::sandbox_state::sandbox::EvolvableSandbox;
37use crate::sandbox_state::transition::Noop;
38use crate::{MultiUseSandbox, Result, log_then_return, new_error};
39
40#[cfg(all(target_os = "linux", feature = "seccomp"))]
41const EXTRA_ALLOWED_SYSCALLS_FOR_WRITER_FUNC: &[super::ExtraAllowedSyscall] = &[
42 libc::SYS_mmap,
49 libc::SYS_brk,
50 libc::SYS_mprotect,
51 #[cfg(mshv)]
52 libc::SYS_close,
53];
54
55pub struct UninitializedSandbox {
63 pub(crate) host_funcs: Arc<Mutex<FunctionRegistry>>,
65 pub(crate) mgr: MemMgrWrapper<ExclusiveSharedMemory>,
67 pub(crate) max_guest_log_level: Option<LevelFilter>,
68 pub(crate) config: SandboxConfiguration,
69}
70
71impl crate::sandbox_state::sandbox::UninitializedSandbox for UninitializedSandbox {
72 #[instrument(skip_all, parent = Span::current(), level = "Trace")]
73 fn get_uninitialized_sandbox(&self) -> &crate::sandbox::UninitializedSandbox {
74 self
75 }
76
77 #[instrument(skip_all, parent = Span::current(), level = "Trace")]
78 fn get_uninitialized_sandbox_mut(&mut self) -> &mut crate::sandbox::UninitializedSandbox {
79 self
80 }
81}
82
83impl Debug for UninitializedSandbox {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 f.debug_struct("UninitializedSandbox")
86 .field("memory_layout", &self.mgr.unwrap_mgr().layout)
87 .finish()
88 }
89}
90
91impl crate::sandbox_state::sandbox::Sandbox for UninitializedSandbox {
92 fn check_stack_guard(&self) -> Result<bool> {
93 log_then_return!(
94 "Checking the stack cookie before the sandbox is initialized is unsupported"
95 );
96 }
97}
98
99impl
100 EvolvableSandbox<
101 UninitializedSandbox,
102 MultiUseSandbox,
103 Noop<UninitializedSandbox, MultiUseSandbox>,
104 > for UninitializedSandbox
105{
106 #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
108 fn evolve(self, _: Noop<UninitializedSandbox, MultiUseSandbox>) -> Result<MultiUseSandbox> {
109 evolve_impl_multi_use(self)
110 }
111}
112
113#[derive(Debug)]
115pub enum GuestBinary<'a> {
116 Buffer(&'a [u8]),
118 FilePath(String),
120}
121
122impl UninitializedSandbox {
123 #[instrument(
131 err(Debug),
132 skip(guest_binary),
133 parent = Span::current()
134 )]
135 pub fn new(guest_binary: GuestBinary, cfg: Option<SandboxConfiguration>) -> Result<Self> {
136 #[cfg(feature = "build-metadata")]
137 log_build_details();
138
139 #[cfg(target_os = "windows")]
141 check_windows_version()?;
142
143 let guest_binary = match guest_binary {
145 GuestBinary::FilePath(binary_path) => {
146 let path = Path::new(&binary_path)
147 .canonicalize()
148 .map_err(|e| new_error!("GuestBinary not found: '{}': {}", binary_path, e))?;
149 GuestBinary::FilePath(
150 path.into_os_string()
151 .into_string()
152 .map_err(|e| new_error!("Error converting OsString to String: {:?}", e))?,
153 )
154 }
155 buffer @ GuestBinary::Buffer(_) => buffer,
156 };
157
158 let sandbox_cfg = cfg.unwrap_or_default();
159
160 let mut mem_mgr_wrapper = {
161 let mut mgr = UninitializedSandbox::load_guest_binary(sandbox_cfg, &guest_binary)?;
162 let stack_guard = Self::create_stack_guard();
163 mgr.set_stack_guard(&stack_guard)?;
164 MemMgrWrapper::new(mgr, stack_guard)
165 };
166
167 mem_mgr_wrapper.write_memory_layout()?;
168
169 let host_funcs = Arc::new(Mutex::new(FunctionRegistry::default()));
170
171 let mut sandbox = Self {
172 host_funcs,
173 mgr: mem_mgr_wrapper,
174 max_guest_log_level: None,
175 config: sandbox_cfg,
176 };
177
178 sandbox.register_print(default_writer_func)?;
180
181 crate::debug!("Sandbox created: {:#?}", sandbox);
182
183 Ok(sandbox)
184 }
185
186 #[instrument(skip_all, parent = Span::current(), level = "Trace")]
187 fn create_stack_guard() -> [u8; STACK_COOKIE_LEN] {
188 rand::random::<[u8; STACK_COOKIE_LEN]>()
189 }
190
191 #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
202 pub(super) fn load_guest_binary(
203 cfg: SandboxConfiguration,
204 guest_binary: &GuestBinary,
205 ) -> Result<SandboxMemoryManager<ExclusiveSharedMemory>> {
206 let mut exe_info = match guest_binary {
207 GuestBinary::FilePath(bin_path_str) => ExeInfo::from_file(bin_path_str)?,
208 GuestBinary::Buffer(buffer) => ExeInfo::from_buf(buffer)?,
209 };
210
211 SandboxMemoryManager::load_guest_binary_into_memory(cfg, &mut exe_info)
212 }
213
214 pub fn set_max_guest_log_level(&mut self, log_level: LevelFilter) {
218 self.max_guest_log_level = Some(log_level);
219 }
220
221 pub fn register<Args: ParameterTuple, Output: SupportedReturnType>(
223 &mut self,
224 name: impl AsRef<str>,
225 host_func: impl Into<HostFunction<Output, Args>>,
226 ) -> Result<()> {
227 register_host_function(host_func, self, name.as_ref(), None)
228 }
229
230 #[cfg(all(feature = "seccomp", target_os = "linux"))]
234 pub fn register_with_extra_allowed_syscalls<
235 Args: ParameterTuple,
236 Output: SupportedReturnType,
237 >(
238 &mut self,
239 name: impl AsRef<str>,
240 host_func: impl Into<HostFunction<Output, Args>>,
241 extra_allowed_syscalls: impl IntoIterator<Item = crate::sandbox::ExtraAllowedSyscall>,
242 ) -> Result<()> {
243 let extra_allowed_syscalls: Vec<_> = extra_allowed_syscalls.into_iter().collect();
244 register_host_function(host_func, self, name.as_ref(), Some(extra_allowed_syscalls))
245 }
246
247 pub fn register_print(
252 &mut self,
253 print_func: impl Into<HostFunction<i32, (String,)>>,
254 ) -> Result<()> {
255 #[cfg(not(all(target_os = "linux", feature = "seccomp")))]
256 self.register("HostPrint", print_func)?;
257
258 #[cfg(all(target_os = "linux", feature = "seccomp"))]
259 self.register_with_extra_allowed_syscalls(
260 "HostPrint",
261 print_func,
262 EXTRA_ALLOWED_SYSCALLS_FOR_WRITER_FUNC.iter().copied(),
263 )?;
264
265 Ok(())
266 }
267
268 #[cfg(all(feature = "seccomp", target_os = "linux"))]
275 pub fn register_print_with_extra_allowed_syscalls(
276 &mut self,
277 print_func: impl Into<HostFunction<i32, (String,)>>,
278 extra_allowed_syscalls: impl IntoIterator<Item = crate::sandbox::ExtraAllowedSyscall>,
279 ) -> Result<()> {
280 #[cfg(all(target_os = "linux", feature = "seccomp"))]
281 self.register_with_extra_allowed_syscalls(
282 "HostPrint",
283 print_func,
284 EXTRA_ALLOWED_SYSCALLS_FOR_WRITER_FUNC
285 .iter()
286 .copied()
287 .chain(extra_allowed_syscalls),
288 )?;
289
290 Ok(())
291 }
292}
293#[cfg(target_os = "windows")]
296fn check_windows_version() -> Result<()> {
297 use windows_version::{OsVersion, is_server};
298 const WINDOWS_MAJOR: u32 = 10;
299 const WINDOWS_MINOR: u32 = 0;
300 const WINDOWS_PACK: u32 = 0;
301
302 if is_server() {
304 if OsVersion::current() < OsVersion::new(WINDOWS_MAJOR, WINDOWS_MINOR, WINDOWS_PACK, 20348)
305 {
306 return Err(new_error!(
307 "Hyperlight Requires Windows Server 2022 or newer"
308 ));
309 }
310 } else if OsVersion::current()
311 < OsVersion::new(WINDOWS_MAJOR, WINDOWS_MINOR, WINDOWS_PACK, 22000)
312 {
313 return Err(new_error!("Hyperlight Requires Windows 11 or newer"));
314 }
315 Ok(())
316}
317
318#[cfg(test)]
319mod tests {
320 use std::sync::Arc;
321 use std::sync::mpsc::channel;
322 use std::{fs, thread};
323
324 use crossbeam_queue::ArrayQueue;
325 use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnValue};
326 use hyperlight_testing::simple_guest_as_string;
327
328 use crate::sandbox::SandboxConfiguration;
329 use crate::sandbox::uninitialized::GuestBinary;
330 use crate::sandbox_state::sandbox::EvolvableSandbox;
331 use crate::sandbox_state::transition::Noop;
332 use crate::{MultiUseSandbox, Result, UninitializedSandbox, new_error};
333
334 #[test]
335 fn test_new_sandbox() {
336 let binary_path = simple_guest_as_string().unwrap();
339 let sandbox = UninitializedSandbox::new(GuestBinary::FilePath(binary_path.clone()), None);
340 assert!(sandbox.is_ok());
341
342 let mut binary_path_does_not_exist = binary_path.clone();
345 binary_path_does_not_exist.push_str(".nonexistent");
346 let uninitialized_sandbox =
347 UninitializedSandbox::new(GuestBinary::FilePath(binary_path_does_not_exist), None);
348 assert!(uninitialized_sandbox.is_err());
349
350 let cfg = {
352 let mut cfg = SandboxConfiguration::default();
353 cfg.set_input_data_size(0x1000);
354 cfg.set_output_data_size(0x1000);
355 cfg.set_stack_size(0x1000);
356 cfg.set_heap_size(0x1000);
357 Some(cfg)
358 };
359
360 let uninitialized_sandbox =
361 UninitializedSandbox::new(GuestBinary::FilePath(binary_path.clone()), cfg);
362 assert!(uninitialized_sandbox.is_ok());
363
364 let uninitialized_sandbox =
365 UninitializedSandbox::new(GuestBinary::FilePath(binary_path), None).unwrap();
366
367 let _sandbox: MultiUseSandbox = uninitialized_sandbox.evolve(Noop::default()).unwrap();
370
371 let binary_path = simple_guest_as_string().unwrap();
374 let sandbox =
375 UninitializedSandbox::new(GuestBinary::Buffer(&fs::read(binary_path).unwrap()), None);
376 assert!(sandbox.is_ok());
377
378 let binary_path = simple_guest_as_string().unwrap();
381 let mut bytes = fs::read(binary_path).unwrap();
382 let _ = bytes.split_off(100);
383 let sandbox = UninitializedSandbox::new(GuestBinary::Buffer(&bytes), None);
384 assert!(sandbox.is_err());
385 }
386
387 #[test]
388 fn test_load_guest_binary_manual() {
389 let cfg = SandboxConfiguration::default();
390
391 let simple_guest_path = simple_guest_as_string().unwrap();
392
393 UninitializedSandbox::load_guest_binary(cfg, &GuestBinary::FilePath(simple_guest_path))
394 .unwrap();
395 }
396
397 #[test]
398 fn test_host_functions() {
399 let uninitialized_sandbox = || {
400 UninitializedSandbox::new(
401 GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")),
402 None,
403 )
404 .unwrap()
405 };
406
407 {
409 let mut usbox = uninitialized_sandbox();
410
411 usbox.register("test0", |arg: i32| Ok(arg + 1)).unwrap();
412
413 let sandbox: Result<MultiUseSandbox> = usbox.evolve(Noop::default());
414 assert!(sandbox.is_ok());
415 let sandbox = sandbox.unwrap();
416
417 let host_funcs = sandbox
418 ._host_funcs
419 .try_lock()
420 .map_err(|_| new_error!("Error locking"));
421
422 assert!(host_funcs.is_ok());
423
424 let res = host_funcs
425 .unwrap()
426 .call_host_function("test0", vec![ParameterValue::Int(1)])
427 .unwrap();
428
429 assert_eq!(res, ReturnValue::Int(2));
430 }
431
432 {
434 let mut usbox = uninitialized_sandbox();
435
436 usbox.register("test1", |a: i32, b: i32| Ok(a + b)).unwrap();
437
438 let sandbox: Result<MultiUseSandbox> = usbox.evolve(Noop::default());
439 assert!(sandbox.is_ok());
440 let sandbox = sandbox.unwrap();
441
442 let host_funcs = sandbox
443 ._host_funcs
444 .try_lock()
445 .map_err(|_| new_error!("Error locking"));
446
447 assert!(host_funcs.is_ok());
448
449 let res = host_funcs
450 .unwrap()
451 .call_host_function(
452 "test1",
453 vec![ParameterValue::Int(1), ParameterValue::Int(2)],
454 )
455 .unwrap();
456
457 assert_eq!(res, ReturnValue::Int(3));
458 }
459
460 {
462 let mut usbox = uninitialized_sandbox();
463
464 usbox
465 .register("test2", |msg: String| {
466 println!("test2 called: {}", msg);
467 Ok(())
468 })
469 .unwrap();
470
471 let sandbox: Result<MultiUseSandbox> = usbox.evolve(Noop::default());
472 assert!(sandbox.is_ok());
473 let sandbox = sandbox.unwrap();
474
475 let host_funcs = sandbox
476 ._host_funcs
477 .try_lock()
478 .map_err(|_| new_error!("Error locking"));
479
480 assert!(host_funcs.is_ok());
481
482 let res = host_funcs.unwrap().call_host_function("test2", vec![]);
483 assert!(res.is_err());
484 }
485
486 {
488 let usbox = uninitialized_sandbox();
489 let sandbox: Result<MultiUseSandbox> = usbox.evolve(Noop::default());
490 assert!(sandbox.is_ok());
491 let sandbox = sandbox.unwrap();
492
493 let host_funcs = sandbox
494 ._host_funcs
495 .try_lock()
496 .map_err(|_| new_error!("Error locking"));
497
498 assert!(host_funcs.is_ok());
499
500 let res = host_funcs.unwrap().call_host_function("test4", vec![]);
501 assert!(res.is_err());
502 }
503 }
504
505 #[test]
506 fn test_host_print() {
507 let (tx, rx) = channel();
512
513 let writer = move |msg| {
514 let _ = tx.send(msg);
515 Ok(0)
516 };
517
518 let mut sandbox = UninitializedSandbox::new(
519 GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")),
520 None,
521 )
522 .expect("Failed to create sandbox");
523
524 sandbox
525 .register_print(writer)
526 .expect("Failed to register host print function");
527
528 let host_funcs = sandbox
529 .host_funcs
530 .try_lock()
531 .map_err(|_| new_error!("Error locking"));
532
533 assert!(host_funcs.is_ok());
534
535 host_funcs.unwrap().host_print("test".to_string()).unwrap();
536
537 drop(sandbox);
538
539 let received_msgs: Vec<_> = rx.into_iter().collect();
540 assert_eq!(received_msgs, ["test"]);
541
542 fn fn_writer(msg: String) -> Result<i32> {
603 assert_eq!(msg, "test2");
604 Ok(0)
605 }
606
607 let mut sandbox = UninitializedSandbox::new(
608 GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")),
609 None,
610 )
611 .expect("Failed to create sandbox");
612
613 sandbox
614 .register_print(fn_writer)
615 .expect("Failed to register host print function");
616
617 let host_funcs = sandbox
618 .host_funcs
619 .try_lock()
620 .map_err(|_| new_error!("Error locking"));
621
622 assert!(host_funcs.is_ok());
623
624 host_funcs.unwrap().host_print("test2".to_string()).unwrap();
625
626 let mut test_host_print = TestHostPrint::new();
629
630 let writer_closure = move |s| test_host_print.write(s);
633
634 let mut sandbox = UninitializedSandbox::new(
635 GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")),
636 None,
637 )
638 .expect("Failed to create sandbox");
639
640 sandbox
641 .register_print(writer_closure)
642 .expect("Failed to register host print function");
643
644 let host_funcs = sandbox
645 .host_funcs
646 .try_lock()
647 .map_err(|_| new_error!("Error locking"));
648
649 assert!(host_funcs.is_ok());
650
651 host_funcs.unwrap().host_print("test3".to_string()).unwrap();
652 }
653
654 struct TestHostPrint {}
655
656 impl TestHostPrint {
657 fn new() -> Self {
658 TestHostPrint {}
659 }
660
661 fn write(&mut self, msg: String) -> Result<i32> {
662 assert_eq!(msg, "test3");
663 Ok(0)
664 }
665 }
666
667 #[test]
668 fn check_create_and_use_sandbox_on_different_threads() {
669 let unintializedsandbox_queue = Arc::new(ArrayQueue::<UninitializedSandbox>::new(10));
670 let sandbox_queue = Arc::new(ArrayQueue::<MultiUseSandbox>::new(10));
671
672 for i in 0..10 {
673 let simple_guest_path = simple_guest_as_string().expect("Guest Binary Missing");
674 let unintializedsandbox = {
675 let err_string = format!("failed to create UninitializedSandbox {i}");
676 let err_str = err_string.as_str();
677 UninitializedSandbox::new(GuestBinary::FilePath(simple_guest_path), None)
678 .expect(err_str)
679 };
680
681 {
682 let err_string = format!("Failed to push UninitializedSandbox {i}");
683 let err_str = err_string.as_str();
684
685 unintializedsandbox_queue
686 .push(unintializedsandbox)
687 .expect(err_str);
688 }
689 }
690
691 let thread_handles = (0..10)
692 .map(|i| {
693 let uq = unintializedsandbox_queue.clone();
694 let sq = sandbox_queue.clone();
695 thread::spawn(move || {
696 let uninitialized_sandbox = uq.pop().unwrap_or_else(|| {
697 panic!("Failed to pop UninitializedSandbox thread {}", i)
698 });
699
700 let host_funcs = uninitialized_sandbox
701 .host_funcs
702 .try_lock()
703 .map_err(|_| new_error!("Error locking"));
704
705 assert!(host_funcs.is_ok());
706
707 host_funcs
708 .unwrap()
709 .host_print(format!("Print from UninitializedSandbox on Thread {}\n", i))
710 .unwrap();
711
712 let sandbox = uninitialized_sandbox
713 .evolve(Noop::default())
714 .unwrap_or_else(|_| {
715 panic!("Failed to initialize UninitializedSandbox thread {}", i)
716 });
717
718 sq.push(sandbox).unwrap_or_else(|_| {
719 panic!("Failed to push UninitializedSandbox thread {}", i)
720 })
721 })
722 })
723 .collect::<Vec<_>>();
724
725 for handle in thread_handles {
726 handle.join().unwrap();
727 }
728
729 let thread_handles = (0..10)
730 .map(|i| {
731 let sq = sandbox_queue.clone();
732 thread::spawn(move || {
733 let sandbox = sq
734 .pop()
735 .unwrap_or_else(|| panic!("Failed to pop Sandbox thread {}", i));
736
737 let host_funcs = sandbox
738 ._host_funcs
739 .try_lock()
740 .map_err(|_| new_error!("Error locking"));
741
742 assert!(host_funcs.is_ok());
743
744 host_funcs
745 .unwrap()
746 .host_print(format!("Print from Sandbox on Thread {}\n", i))
747 .unwrap();
748 })
749 })
750 .collect::<Vec<_>>();
751
752 for handle in thread_handles {
753 handle.join().unwrap();
754 }
755 }
756
757 #[test]
758 #[ignore]
764 #[cfg(feature = "build-metadata")]
765 fn test_trace_trace() {
766 use hyperlight_testing::logger::Logger as TestLogger;
767 use hyperlight_testing::tracing_subscriber::TracingSubscriber as TestSubscriber;
768 use serde_json::{Map, Value};
769 use tracing::Level as tracing_level;
770 use tracing_core::Subscriber;
771 use tracing_core::callsite::rebuild_interest_cache;
772 use uuid::Uuid;
773
774 use crate::testing::log_values::build_metadata_testing::try_to_strings;
775 use crate::testing::log_values::test_value_as_str;
776
777 TestLogger::initialize_log_tracer();
778 rebuild_interest_cache();
779 let subscriber = TestSubscriber::new(tracing_level::TRACE);
780 tracing::subscriber::with_default(subscriber.clone(), || {
781 let correlation_id = Uuid::new_v4().as_hyphenated().to_string();
782 let span = tracing::error_span!("test_trace_logs", correlation_id).entered();
783
784 let current_span = subscriber.current_span();
787 assert!(current_span.is_known(), "Current span is unknown");
788 let current_span_metadata = current_span.into_inner().unwrap();
789 assert_eq!(
790 current_span_metadata.0.into_u64(),
791 1,
792 "Current span is not span 1"
793 );
794 assert_eq!(current_span_metadata.1.name(), "test_trace_logs");
795
796 let span_data = subscriber.get_span(1);
799 let span_attributes: &Map<String, Value> = span_data
800 .get("span")
801 .unwrap()
802 .get("attributes")
803 .unwrap()
804 .as_object()
805 .unwrap();
806
807 test_value_as_str(span_attributes, "correlation_id", correlation_id.as_str());
808
809 let mut binary_path = simple_guest_as_string().unwrap();
810 binary_path.push_str("does_not_exist");
811
812 let sbox = UninitializedSandbox::new(GuestBinary::FilePath(binary_path), None);
813 assert!(sbox.is_err());
814
815 let current_span = subscriber.current_span();
818 assert!(current_span.is_known(), "Current span is unknown");
819 let current_span_metadata = current_span.into_inner().unwrap();
820 assert_eq!(
821 current_span_metadata.0.into_u64(),
822 1,
823 "Current span is not span 1"
824 );
825
826 let span_metadata = subscriber.get_span_metadata(2);
827 assert_eq!(span_metadata.name(), "new");
828
829 let events = subscriber.get_events();
832 assert_eq!(events.len(), 15);
833
834 let mut count_matching_events = 0;
835
836 for json_value in events {
837 let event_values = json_value.as_object().unwrap().get("event").unwrap();
838 let metadata_values_map =
839 event_values.get("metadata").unwrap().as_object().unwrap();
840 let event_values_map = event_values.as_object().unwrap();
841
842 let expected_error_start = "Error(\"GuestBinary not found:";
843
844 let err_vals_res = try_to_strings([
845 (metadata_values_map, "level"),
846 (event_values_map, "error"),
847 (metadata_values_map, "module_path"),
848 (metadata_values_map, "target"),
849 ]);
850 if let Ok(err_vals) = err_vals_res {
851 if err_vals[0] == "ERROR"
852 && err_vals[1].starts_with(expected_error_start)
853 && err_vals[2] == "hyperlight_host::sandbox::uninitialized"
854 && err_vals[3] == "hyperlight_host::sandbox::uninitialized"
855 {
856 count_matching_events += 1;
857 }
858 }
859 }
860 assert!(
861 count_matching_events == 1,
862 "Unexpected number of matching events {}",
863 count_matching_events
864 );
865 span.exit();
866 subscriber.clear();
867 });
868 }
869
870 #[test]
871 #[ignore]
872 #[cfg(feature = "build-metadata")]
875 fn test_log_trace() {
876 use std::path::PathBuf;
877
878 use hyperlight_testing::logger::{LOGGER as TEST_LOGGER, Logger as TestLogger};
879 use log::Level;
880 use tracing_core::callsite::rebuild_interest_cache;
881
882 {
883 TestLogger::initialize_test_logger();
884 TEST_LOGGER.set_max_level(log::LevelFilter::Trace);
885
886 rebuild_interest_cache();
890
891 let mut invalid_binary_path = simple_guest_as_string().unwrap();
892 invalid_binary_path.push_str("does_not_exist");
893
894 let sbox = UninitializedSandbox::new(GuestBinary::FilePath(invalid_binary_path), None);
895 assert!(sbox.is_err());
896
897 let num_calls = TEST_LOGGER.num_log_calls();
911 assert_eq!(19, num_calls);
912
913 let logcall = TEST_LOGGER.get_log_call(0).unwrap();
916 assert_eq!(Level::Info, logcall.level);
917
918 assert!(logcall.args.starts_with("new; cfg"));
919 assert_eq!("hyperlight_host::sandbox::uninitialized", logcall.target);
920
921 let logcall = TEST_LOGGER.get_log_call(1).unwrap();
924 assert_eq!(Level::Trace, logcall.level);
925 assert_eq!(logcall.args, "-> new;");
926 assert_eq!("tracing::span::active", logcall.target);
927
928 let logcall = TEST_LOGGER.get_log_call(16).unwrap();
931 assert_eq!(Level::Error, logcall.level);
932 assert!(
933 logcall
934 .args
935 .starts_with("error=Error(\"GuestBinary not found:")
936 );
937 assert_eq!("hyperlight_host::sandbox::uninitialized", logcall.target);
938
939 let logcall = TEST_LOGGER.get_log_call(17).unwrap();
942 assert_eq!(Level::Trace, logcall.level);
943 assert_eq!(logcall.args, "<- new;");
944 assert_eq!("tracing::span::active", logcall.target);
945
946 let logcall = TEST_LOGGER.get_log_call(18).unwrap();
949 assert_eq!(Level::Trace, logcall.level);
950 assert_eq!(logcall.args, "-- new;");
951 assert_eq!("tracing::span", logcall.target);
952 }
953 {
954 TEST_LOGGER.clear_log_calls();
956 TEST_LOGGER.set_max_level(log::LevelFilter::Info);
957
958 let mut valid_binary_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
959 valid_binary_path.push("src");
960 valid_binary_path.push("sandbox");
961 valid_binary_path.push("initialized.rs");
962
963 let sbox = UninitializedSandbox::new(
964 GuestBinary::FilePath(valid_binary_path.into_os_string().into_string().unwrap()),
965 None,
966 );
967 assert!(sbox.is_err());
968
969 let num_calls = TEST_LOGGER.num_log_calls();
972 assert_eq!(2, num_calls);
973
974 let logcall = TEST_LOGGER.get_log_call(0).unwrap();
977 assert_eq!(Level::Info, logcall.level);
978
979 assert!(logcall.args.starts_with("new; cfg"));
980 assert_eq!("hyperlight_host::sandbox::uninitialized", logcall.target);
981
982 let logcall = TEST_LOGGER.get_log_call(1).unwrap();
985 assert_eq!(Level::Error, logcall.level);
986 assert!(
987 logcall
988 .args
989 .starts_with("error=Error(\"GuestBinary not found:")
990 );
991 assert_eq!("hyperlight_host::sandbox::uninitialized", logcall.target);
992 }
993 {
994 TEST_LOGGER.clear_log_calls();
995 TEST_LOGGER.set_max_level(log::LevelFilter::Error);
996
997 let sbox = {
998 let res = UninitializedSandbox::new(
999 GuestBinary::FilePath(simple_guest_as_string().unwrap()),
1000 None,
1001 );
1002 res.unwrap()
1003 };
1004 let _: Result<MultiUseSandbox> = sbox.evolve(Noop::default());
1005
1006 let num_calls = TEST_LOGGER.num_log_calls();
1007
1008 assert_eq!(0, num_calls);
1009 }
1010 }
1011
1012 #[test]
1013 fn test_invalid_path() {
1014 let invalid_path = "some/path/that/does/not/exist";
1015 let sbox = UninitializedSandbox::new(GuestBinary::FilePath(invalid_path.to_string()), None);
1016 println!("{:?}", sbox);
1017 #[cfg(target_os = "windows")]
1018 assert!(
1019 matches!(sbox, Err(e) if e.to_string().contains("GuestBinary not found: 'some/path/that/does/not/exist': The system cannot find the path specified. (os error 3)"))
1020 );
1021 #[cfg(target_os = "linux")]
1022 assert!(
1023 matches!(sbox, Err(e) if e.to_string().contains("GuestBinary not found: 'some/path/that/does/not/exist': No such file or directory (os error 2)"))
1024 );
1025 }
1026}