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::uninitialized_evolve::evolve_impl_multi_use;
27use crate::func::host_functions::{HostFunction, register_host_function};
28use crate::func::{ParameterTuple, SupportedReturnType};
29#[cfg(feature = "build-metadata")]
30use crate::log_build_details;
31use crate::mem::exe::ExeInfo;
32use crate::mem::memory_region::{DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegionFlags};
33use crate::mem::mgr::SandboxMemoryManager;
34use crate::mem::shared_mem::ExclusiveSharedMemory;
35use crate::sandbox::SandboxConfiguration;
36use crate::{MultiUseSandbox, Result, new_error};
37
38#[cfg(any(crashdump, gdb))]
39#[derive(Clone, Debug, Default)]
40pub(crate) struct SandboxRuntimeConfig {
41 #[cfg(crashdump)]
42 pub(crate) binary_path: Option<String>,
43 #[cfg(gdb)]
44 pub(crate) debug_info: Option<super::config::DebugInfo>,
45 #[cfg(crashdump)]
46 pub(crate) guest_core_dump: bool,
47}
48
49pub struct UninitializedSandbox {
61 pub(crate) host_funcs: Arc<Mutex<FunctionRegistry>>,
63 pub(crate) mgr: SandboxMemoryManager<ExclusiveSharedMemory>,
65 pub(crate) max_guest_log_level: Option<LevelFilter>,
66 pub(crate) config: SandboxConfiguration,
67 #[cfg(any(crashdump, gdb))]
68 pub(crate) rt_cfg: SandboxRuntimeConfig,
69 pub(crate) load_info: crate::mem::exe::LoadInfo,
70}
71
72impl Debug for UninitializedSandbox {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 f.debug_struct("UninitializedSandbox")
75 .field("memory_layout", &self.mgr.layout)
76 .finish()
77 }
78}
79
80#[derive(Debug)]
82pub enum GuestBinary<'a> {
83 Buffer(&'a [u8]),
85 FilePath(String),
87}
88
89#[derive(Debug)]
91pub struct GuestBlob<'a> {
92 pub data: &'a [u8],
94 pub permissions: MemoryRegionFlags,
97}
98
99impl<'a> From<&'a [u8]> for GuestBlob<'a> {
100 fn from(data: &'a [u8]) -> Self {
101 GuestBlob {
102 data,
103 permissions: DEFAULT_GUEST_BLOB_MEM_FLAGS,
104 }
105 }
106}
107
108#[derive(Debug)]
113pub struct GuestEnvironment<'a, 'b> {
114 pub guest_binary: GuestBinary<'a>,
116 pub init_data: Option<GuestBlob<'b>>,
118}
119
120impl<'a, 'b> GuestEnvironment<'a, 'b> {
121 pub fn new(guest_binary: GuestBinary<'a>, init_data: Option<&'b [u8]>) -> Self {
123 GuestEnvironment {
124 guest_binary,
125 init_data: init_data.map(GuestBlob::from),
126 }
127 }
128}
129
130impl<'a> From<GuestBinary<'a>> for GuestEnvironment<'a, '_> {
131 fn from(guest_binary: GuestBinary<'a>) -> Self {
132 GuestEnvironment {
133 guest_binary,
134 init_data: None,
135 }
136 }
137}
138
139impl UninitializedSandbox {
140 #[instrument(
147 err(Debug),
148 skip(env),
149 parent = Span::current()
150 )]
151 pub fn new<'a, 'b>(
152 env: impl Into<GuestEnvironment<'a, 'b>>,
153 cfg: Option<SandboxConfiguration>,
154 ) -> Result<Self> {
155 #[cfg(feature = "build-metadata")]
156 log_build_details();
157
158 #[cfg(target_os = "windows")]
160 check_windows_version()?;
161
162 let env: GuestEnvironment<'_, '_> = env.into();
163 let guest_binary = env.guest_binary;
164 let guest_blob = env.init_data;
165
166 let guest_binary = match guest_binary {
168 GuestBinary::FilePath(binary_path) => {
169 let path = Path::new(&binary_path)
170 .canonicalize()
171 .map_err(|e| new_error!("GuestBinary not found: '{}': {}", binary_path, e))?
172 .into_os_string()
173 .into_string()
174 .map_err(|e| new_error!("Error converting OsString to String: {:?}", e))?;
175
176 GuestBinary::FilePath(path)
177 }
178 buffer @ GuestBinary::Buffer(_) => buffer,
179 };
180
181 let sandbox_cfg = cfg.unwrap_or_default();
182
183 #[cfg(any(crashdump, gdb))]
184 let rt_cfg = {
185 #[cfg(crashdump)]
186 let guest_core_dump = sandbox_cfg.get_guest_core_dump();
187
188 #[cfg(gdb)]
189 let debug_info = sandbox_cfg.get_guest_debug_info();
190
191 #[cfg(crashdump)]
192 let binary_path = if let GuestBinary::FilePath(ref path) = guest_binary {
193 Some(path.clone())
194 } else {
195 None
196 };
197
198 SandboxRuntimeConfig {
199 #[cfg(crashdump)]
200 binary_path,
201 #[cfg(gdb)]
202 debug_info,
203 #[cfg(crashdump)]
204 guest_core_dump,
205 }
206 };
207
208 let (mut mem_mgr_wrapper, load_info) = UninitializedSandbox::load_guest_binary(
209 sandbox_cfg,
210 &guest_binary,
211 guest_blob.as_ref(),
212 )?;
213
214 mem_mgr_wrapper.write_memory_layout()?;
215
216 if let Some(blob) = guest_blob {
218 mem_mgr_wrapper.write_init_data(blob.data)?;
219 }
220
221 let host_funcs = Arc::new(Mutex::new(FunctionRegistry::default()));
222
223 let mut sandbox = Self {
224 host_funcs,
225 mgr: mem_mgr_wrapper,
226 max_guest_log_level: None,
227 config: sandbox_cfg,
228 #[cfg(any(crashdump, gdb))]
229 rt_cfg,
230 load_info,
231 };
232
233 sandbox.register_print(default_writer_func)?;
235
236 crate::debug!("Sandbox created: {:#?}", sandbox);
237
238 Ok(sandbox)
239 }
240
241 #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
247 pub fn evolve(self) -> Result<MultiUseSandbox> {
248 evolve_impl_multi_use(self)
249 }
250
251 #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
262 pub(super) fn load_guest_binary(
263 cfg: SandboxConfiguration,
264 guest_binary: &GuestBinary,
265 guest_blob: Option<&GuestBlob>,
266 ) -> Result<(
267 SandboxMemoryManager<ExclusiveSharedMemory>,
268 crate::mem::exe::LoadInfo,
269 )> {
270 let exe_info = match guest_binary {
271 GuestBinary::FilePath(bin_path_str) => ExeInfo::from_file(bin_path_str)?,
272 GuestBinary::Buffer(buffer) => ExeInfo::from_buf(buffer)?,
273 };
274
275 SandboxMemoryManager::load_guest_binary_into_memory(cfg, exe_info, guest_blob)
276 }
277
278 pub fn set_max_guest_log_level(&mut self, log_level: LevelFilter) {
283 self.max_guest_log_level = Some(log_level);
284 }
285
286 pub fn register<Args: ParameterTuple, Output: SupportedReturnType>(
288 &mut self,
289 name: impl AsRef<str>,
290 host_func: impl Into<HostFunction<Output, Args>>,
291 ) -> Result<()> {
292 register_host_function(host_func, self, name.as_ref())
293 }
294
295 pub fn register_print(
301 &mut self,
302 print_func: impl Into<HostFunction<i32, (String,)>>,
303 ) -> Result<()> {
304 self.register("HostPrint", print_func)
305 }
306}
307#[cfg(target_os = "windows")]
310fn check_windows_version() -> Result<()> {
311 use windows_version::{OsVersion, is_server};
312 const WINDOWS_MAJOR: u32 = 10;
313 const WINDOWS_MINOR: u32 = 0;
314 const WINDOWS_PACK: u32 = 0;
315
316 if is_server() {
318 if OsVersion::current() < OsVersion::new(WINDOWS_MAJOR, WINDOWS_MINOR, WINDOWS_PACK, 20348)
319 {
320 return Err(new_error!(
321 "Hyperlight Requires Windows Server 2022 or newer"
322 ));
323 }
324 } else if OsVersion::current()
325 < OsVersion::new(WINDOWS_MAJOR, WINDOWS_MINOR, WINDOWS_PACK, 22000)
326 {
327 return Err(new_error!("Hyperlight Requires Windows 11 or newer"));
328 }
329 Ok(())
330}
331
332#[cfg(test)]
333mod tests {
334 use std::sync::Arc;
335 use std::sync::mpsc::channel;
336 use std::{fs, thread};
337
338 use crossbeam_queue::ArrayQueue;
339 use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnValue};
340 use hyperlight_testing::simple_guest_as_string;
341
342 use crate::sandbox::SandboxConfiguration;
343 use crate::sandbox::uninitialized::{GuestBinary, GuestEnvironment};
344 use crate::{MultiUseSandbox, Result, UninitializedSandbox, new_error};
345
346 #[test]
347 fn test_load_extra_blob() {
348 let binary_path = simple_guest_as_string().unwrap();
349 let buffer = [0xde, 0xad, 0xbe, 0xef];
350 let guest_env =
351 GuestEnvironment::new(GuestBinary::FilePath(binary_path.clone()), Some(&buffer));
352
353 let uninitialized_sandbox = UninitializedSandbox::new(guest_env, None).unwrap();
354 let mut sandbox: MultiUseSandbox = uninitialized_sandbox.evolve().unwrap();
355
356 let res = sandbox
357 .call::<Vec<u8>>("ReadFromUserMemory", (4u64, buffer.to_vec()))
358 .expect("Failed to call ReadFromUserMemory");
359
360 assert_eq!(res, buffer.to_vec());
361 }
362
363 #[test]
364 fn test_new_sandbox() {
365 let binary_path = simple_guest_as_string().unwrap();
368 let sandbox = UninitializedSandbox::new(GuestBinary::FilePath(binary_path.clone()), None);
369 assert!(sandbox.is_ok());
370
371 let mut binary_path_does_not_exist = binary_path.clone();
374 binary_path_does_not_exist.push_str(".nonexistent");
375 let uninitialized_sandbox =
376 UninitializedSandbox::new(GuestBinary::FilePath(binary_path_does_not_exist), None);
377 assert!(uninitialized_sandbox.is_err());
378
379 let cfg = {
381 let mut cfg = SandboxConfiguration::default();
382 cfg.set_input_data_size(0x1000);
383 cfg.set_output_data_size(0x1000);
384 cfg.set_stack_size(0x1000);
385 cfg.set_heap_size(0x1000);
386 Some(cfg)
387 };
388
389 let uninitialized_sandbox =
390 UninitializedSandbox::new(GuestBinary::FilePath(binary_path.clone()), cfg);
391 assert!(uninitialized_sandbox.is_ok());
392
393 let uninitialized_sandbox =
394 UninitializedSandbox::new(GuestBinary::FilePath(binary_path), None).unwrap();
395
396 let _sandbox: MultiUseSandbox = uninitialized_sandbox.evolve().unwrap();
399
400 let binary_path = simple_guest_as_string().unwrap();
403 let sandbox =
404 UninitializedSandbox::new(GuestBinary::Buffer(&fs::read(binary_path).unwrap()), None);
405 assert!(sandbox.is_ok());
406
407 let binary_path = simple_guest_as_string().unwrap();
410 let mut bytes = fs::read(binary_path).unwrap();
411 let _ = bytes.split_off(100);
412 let sandbox = UninitializedSandbox::new(GuestBinary::Buffer(&bytes), None);
413 assert!(sandbox.is_err());
414 }
415
416 #[test]
417 fn test_load_guest_binary_manual() {
418 let cfg = SandboxConfiguration::default();
419
420 let simple_guest_path = simple_guest_as_string().unwrap();
421
422 UninitializedSandbox::load_guest_binary(
423 cfg,
424 &GuestBinary::FilePath(simple_guest_path),
425 None.as_ref(),
426 )
427 .unwrap();
428 }
429
430 #[test]
431 fn test_host_functions() {
432 let uninitialized_sandbox = || {
433 UninitializedSandbox::new(
434 GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")),
435 None,
436 )
437 .unwrap()
438 };
439
440 {
442 let mut usbox = uninitialized_sandbox();
443
444 usbox.register("test0", |arg: i32| Ok(arg + 1)).unwrap();
445
446 let sandbox: Result<MultiUseSandbox> = usbox.evolve();
447 assert!(sandbox.is_ok());
448 let sandbox = sandbox.unwrap();
449
450 let host_funcs = sandbox
451 ._host_funcs
452 .try_lock()
453 .map_err(|_| new_error!("Error locking"));
454
455 assert!(host_funcs.is_ok());
456
457 let res = host_funcs
458 .unwrap()
459 .call_host_function("test0", vec![ParameterValue::Int(1)])
460 .unwrap();
461
462 assert_eq!(res, ReturnValue::Int(2));
463 }
464
465 {
467 let mut usbox = uninitialized_sandbox();
468
469 usbox.register("test1", |a: i32, b: i32| Ok(a + b)).unwrap();
470
471 let sandbox: Result<MultiUseSandbox> = usbox.evolve();
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
483 .unwrap()
484 .call_host_function(
485 "test1",
486 vec![ParameterValue::Int(1), ParameterValue::Int(2)],
487 )
488 .unwrap();
489
490 assert_eq!(res, ReturnValue::Int(3));
491 }
492
493 {
495 let mut usbox = uninitialized_sandbox();
496
497 usbox
498 .register("test2", |msg: String| {
499 println!("test2 called: {}", msg);
500 Ok(())
501 })
502 .unwrap();
503
504 let sandbox: Result<MultiUseSandbox> = usbox.evolve();
505 assert!(sandbox.is_ok());
506 let sandbox = sandbox.unwrap();
507
508 let host_funcs = sandbox
509 ._host_funcs
510 .try_lock()
511 .map_err(|_| new_error!("Error locking"));
512
513 assert!(host_funcs.is_ok());
514
515 let res = host_funcs.unwrap().call_host_function("test2", vec![]);
516 assert!(res.is_err());
517 }
518
519 {
521 let usbox = uninitialized_sandbox();
522 let sandbox: Result<MultiUseSandbox> = usbox.evolve();
523 assert!(sandbox.is_ok());
524 let sandbox = sandbox.unwrap();
525
526 let host_funcs = sandbox
527 ._host_funcs
528 .try_lock()
529 .map_err(|_| new_error!("Error locking"));
530
531 assert!(host_funcs.is_ok());
532
533 let res = host_funcs.unwrap().call_host_function("test4", vec![]);
534 assert!(res.is_err());
535 }
536 }
537
538 #[test]
539 fn test_host_print() {
540 let (tx, rx) = channel();
545
546 let writer = move |msg| {
547 let _ = tx.send(msg);
548 Ok(0)
549 };
550
551 let mut sandbox = UninitializedSandbox::new(
552 GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")),
553 None,
554 )
555 .expect("Failed to create sandbox");
556
557 sandbox
558 .register_print(writer)
559 .expect("Failed to register host print function");
560
561 let host_funcs = sandbox
562 .host_funcs
563 .try_lock()
564 .map_err(|_| new_error!("Error locking"));
565
566 assert!(host_funcs.is_ok());
567
568 host_funcs.unwrap().host_print("test".to_string()).unwrap();
569
570 drop(sandbox);
571
572 let received_msgs: Vec<_> = rx.into_iter().collect();
573 assert_eq!(received_msgs, ["test"]);
574
575 fn fn_writer(msg: String) -> Result<i32> {
636 assert_eq!(msg, "test2");
637 Ok(0)
638 }
639
640 let mut sandbox = UninitializedSandbox::new(
641 GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")),
642 None,
643 )
644 .expect("Failed to create sandbox");
645
646 sandbox
647 .register_print(fn_writer)
648 .expect("Failed to register host print function");
649
650 let host_funcs = sandbox
651 .host_funcs
652 .try_lock()
653 .map_err(|_| new_error!("Error locking"));
654
655 assert!(host_funcs.is_ok());
656
657 host_funcs.unwrap().host_print("test2".to_string()).unwrap();
658
659 let mut test_host_print = TestHostPrint::new();
662
663 let writer_closure = move |s| test_host_print.write(s);
666
667 let mut sandbox = UninitializedSandbox::new(
668 GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")),
669 None,
670 )
671 .expect("Failed to create sandbox");
672
673 sandbox
674 .register_print(writer_closure)
675 .expect("Failed to register host print function");
676
677 let host_funcs = sandbox
678 .host_funcs
679 .try_lock()
680 .map_err(|_| new_error!("Error locking"));
681
682 assert!(host_funcs.is_ok());
683
684 host_funcs.unwrap().host_print("test3".to_string()).unwrap();
685 }
686
687 struct TestHostPrint {}
688
689 impl TestHostPrint {
690 fn new() -> Self {
691 TestHostPrint {}
692 }
693
694 fn write(&mut self, msg: String) -> Result<i32> {
695 assert_eq!(msg, "test3");
696 Ok(0)
697 }
698 }
699
700 #[test]
701 fn check_create_and_use_sandbox_on_different_threads() {
702 let unintializedsandbox_queue = Arc::new(ArrayQueue::<UninitializedSandbox>::new(10));
703 let sandbox_queue = Arc::new(ArrayQueue::<MultiUseSandbox>::new(10));
704
705 for i in 0..10 {
706 let simple_guest_path = simple_guest_as_string().expect("Guest Binary Missing");
707 let unintializedsandbox = {
708 let err_string = format!("failed to create UninitializedSandbox {i}");
709 let err_str = err_string.as_str();
710 UninitializedSandbox::new(GuestBinary::FilePath(simple_guest_path), None)
711 .expect(err_str)
712 };
713
714 {
715 let err_string = format!("Failed to push UninitializedSandbox {i}");
716 let err_str = err_string.as_str();
717
718 unintializedsandbox_queue
719 .push(unintializedsandbox)
720 .expect(err_str);
721 }
722 }
723
724 let thread_handles = (0..10)
725 .map(|i| {
726 let uq = unintializedsandbox_queue.clone();
727 let sq = sandbox_queue.clone();
728 thread::spawn(move || {
729 let uninitialized_sandbox = uq.pop().unwrap_or_else(|| {
730 panic!("Failed to pop UninitializedSandbox thread {}", i)
731 });
732
733 let host_funcs = uninitialized_sandbox
734 .host_funcs
735 .try_lock()
736 .map_err(|_| new_error!("Error locking"));
737
738 assert!(host_funcs.is_ok());
739
740 host_funcs
741 .unwrap()
742 .host_print(format!("Print from UninitializedSandbox on Thread {}\n", i))
743 .unwrap();
744
745 let sandbox = uninitialized_sandbox.evolve().unwrap_or_else(|_| {
746 panic!("Failed to initialize UninitializedSandbox thread {}", i)
747 });
748
749 sq.push(sandbox).unwrap_or_else(|_| {
750 panic!("Failed to push UninitializedSandbox thread {}", i)
751 })
752 })
753 })
754 .collect::<Vec<_>>();
755
756 for handle in thread_handles {
757 handle.join().unwrap();
758 }
759
760 let thread_handles = (0..10)
761 .map(|i| {
762 let sq = sandbox_queue.clone();
763 thread::spawn(move || {
764 let sandbox = sq
765 .pop()
766 .unwrap_or_else(|| panic!("Failed to pop Sandbox thread {}", i));
767
768 let host_funcs = sandbox
769 ._host_funcs
770 .try_lock()
771 .map_err(|_| new_error!("Error locking"));
772
773 assert!(host_funcs.is_ok());
774
775 host_funcs
776 .unwrap()
777 .host_print(format!("Print from Sandbox on Thread {}\n", i))
778 .unwrap();
779 })
780 })
781 .collect::<Vec<_>>();
782
783 for handle in thread_handles {
784 handle.join().unwrap();
785 }
786 }
787
788 #[test]
789 #[ignore]
795 #[cfg(feature = "build-metadata")]
796 fn test_trace_trace() {
797 use hyperlight_testing::logger::Logger as TestLogger;
798 use hyperlight_testing::tracing_subscriber::TracingSubscriber as TestSubscriber;
799 use serde_json::{Map, Value};
800 use tracing::Level as tracing_level;
801 use tracing_core::Subscriber;
802 use tracing_core::callsite::rebuild_interest_cache;
803 use uuid::Uuid;
804
805 use crate::testing::log_values::build_metadata_testing::try_to_strings;
806 use crate::testing::log_values::test_value_as_str;
807
808 TestLogger::initialize_log_tracer();
809 rebuild_interest_cache();
810 let subscriber = TestSubscriber::new(tracing_level::TRACE);
811 tracing::subscriber::with_default(subscriber.clone(), || {
812 let correlation_id = Uuid::new_v4().as_hyphenated().to_string();
813 let span = tracing::error_span!("test_trace_logs", correlation_id).entered();
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 assert_eq!(current_span_metadata.1.name(), "test_trace_logs");
826
827 let span_data = subscriber.get_span(1);
830 let span_attributes: &Map<String, Value> = span_data
831 .get("span")
832 .unwrap()
833 .get("attributes")
834 .unwrap()
835 .as_object()
836 .unwrap();
837
838 test_value_as_str(span_attributes, "correlation_id", correlation_id.as_str());
839
840 let mut binary_path = simple_guest_as_string().unwrap();
841 binary_path.push_str("does_not_exist");
842
843 let sbox = UninitializedSandbox::new(GuestBinary::FilePath(binary_path), None);
844 assert!(sbox.is_err());
845
846 let current_span = subscriber.current_span();
849 assert!(current_span.is_known(), "Current span is unknown");
850 let current_span_metadata = current_span.into_inner().unwrap();
851 assert_eq!(
852 current_span_metadata.0.into_u64(),
853 1,
854 "Current span is not span 1"
855 );
856
857 let span_metadata = subscriber.get_span_metadata(2);
858 assert_eq!(span_metadata.name(), "new");
859
860 let events = subscriber.get_events();
863 assert_eq!(events.len(), 15);
864
865 let mut count_matching_events = 0;
866
867 for json_value in events {
868 let event_values = json_value.as_object().unwrap().get("event").unwrap();
869 let metadata_values_map =
870 event_values.get("metadata").unwrap().as_object().unwrap();
871 let event_values_map = event_values.as_object().unwrap();
872
873 let expected_error_start = "Error(\"GuestBinary not found:";
874
875 let err_vals_res = try_to_strings([
876 (metadata_values_map, "level"),
877 (event_values_map, "error"),
878 (metadata_values_map, "module_path"),
879 (metadata_values_map, "target"),
880 ]);
881 if let Ok(err_vals) = err_vals_res
882 && err_vals[0] == "ERROR"
883 && err_vals[1].starts_with(expected_error_start)
884 && err_vals[2] == "hyperlight_host::sandbox::uninitialized"
885 && err_vals[3] == "hyperlight_host::sandbox::uninitialized"
886 {
887 count_matching_events += 1;
888 }
889 }
890 assert!(
891 count_matching_events == 1,
892 "Unexpected number of matching events {}",
893 count_matching_events
894 );
895 span.exit();
896 subscriber.clear();
897 });
898 }
899
900 #[test]
901 #[ignore]
902 #[cfg(feature = "build-metadata")]
905 fn test_log_trace() {
906 use std::path::PathBuf;
907
908 use hyperlight_testing::logger::{LOGGER as TEST_LOGGER, Logger as TestLogger};
909 use log::Level;
910 use tracing_core::callsite::rebuild_interest_cache;
911
912 {
913 TestLogger::initialize_test_logger();
914 TEST_LOGGER.set_max_level(log::LevelFilter::Trace);
915
916 rebuild_interest_cache();
920
921 let mut invalid_binary_path = simple_guest_as_string().unwrap();
922 invalid_binary_path.push_str("does_not_exist");
923
924 let sbox = UninitializedSandbox::new(GuestBinary::FilePath(invalid_binary_path), None);
925 assert!(sbox.is_err());
926
927 let num_calls = TEST_LOGGER.num_log_calls();
941 assert_eq!(19, num_calls);
942
943 let logcall = TEST_LOGGER.get_log_call(0).unwrap();
946 assert_eq!(Level::Info, logcall.level);
947
948 assert!(logcall.args.starts_with("new; cfg"));
949 assert_eq!("hyperlight_host::sandbox::uninitialized", logcall.target);
950
951 let logcall = TEST_LOGGER.get_log_call(1).unwrap();
954 assert_eq!(Level::Trace, logcall.level);
955 assert_eq!(logcall.args, "-> new;");
956 assert_eq!("tracing::span::active", logcall.target);
957
958 let logcall = TEST_LOGGER.get_log_call(16).unwrap();
961 assert_eq!(Level::Error, logcall.level);
962 assert!(
963 logcall
964 .args
965 .starts_with("error=Error(\"GuestBinary not found:")
966 );
967 assert_eq!("hyperlight_host::sandbox::uninitialized", logcall.target);
968
969 let logcall = TEST_LOGGER.get_log_call(17).unwrap();
972 assert_eq!(Level::Trace, logcall.level);
973 assert_eq!(logcall.args, "<- new;");
974 assert_eq!("tracing::span::active", logcall.target);
975
976 let logcall = TEST_LOGGER.get_log_call(18).unwrap();
979 assert_eq!(Level::Trace, logcall.level);
980 assert_eq!(logcall.args, "-- new;");
981 assert_eq!("tracing::span", logcall.target);
982 }
983 {
984 TEST_LOGGER.clear_log_calls();
986 TEST_LOGGER.set_max_level(log::LevelFilter::Info);
987
988 let mut valid_binary_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
989 valid_binary_path.push("src");
990 valid_binary_path.push("sandbox");
991 valid_binary_path.push("initialized.rs");
992
993 let sbox = UninitializedSandbox::new(
994 GuestBinary::FilePath(valid_binary_path.into_os_string().into_string().unwrap()),
995 None,
996 );
997 assert!(sbox.is_err());
998
999 let num_calls = TEST_LOGGER.num_log_calls();
1002 assert_eq!(2, num_calls);
1003
1004 let logcall = TEST_LOGGER.get_log_call(0).unwrap();
1007 assert_eq!(Level::Info, logcall.level);
1008
1009 assert!(logcall.args.starts_with("new; cfg"));
1010 assert_eq!("hyperlight_host::sandbox::uninitialized", logcall.target);
1011
1012 let logcall = TEST_LOGGER.get_log_call(1).unwrap();
1015 assert_eq!(Level::Error, logcall.level);
1016 assert!(
1017 logcall
1018 .args
1019 .starts_with("error=Error(\"GuestBinary not found:")
1020 );
1021 assert_eq!("hyperlight_host::sandbox::uninitialized", logcall.target);
1022 }
1023 {
1024 TEST_LOGGER.clear_log_calls();
1025 TEST_LOGGER.set_max_level(log::LevelFilter::Error);
1026
1027 let sbox = {
1028 let res = UninitializedSandbox::new(
1029 GuestBinary::FilePath(simple_guest_as_string().unwrap()),
1030 None,
1031 );
1032 res.unwrap()
1033 };
1034 let _: Result<MultiUseSandbox> = sbox.evolve();
1035
1036 let num_calls = TEST_LOGGER.num_log_calls();
1037
1038 assert_eq!(0, num_calls);
1039 }
1040 }
1041
1042 #[test]
1043 fn test_invalid_path() {
1044 let invalid_path = "some/path/that/does/not/exist";
1045 let sbox = UninitializedSandbox::new(GuestBinary::FilePath(invalid_path.to_string()), None);
1046 println!("{:?}", sbox);
1047 #[cfg(target_os = "windows")]
1048 assert!(
1049 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)"))
1050 );
1051 #[cfg(target_os = "linux")]
1052 assert!(
1053 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)"))
1054 );
1055 }
1056}