1#![doc = include_str!("../README.md")]
4#![deny(missing_docs, missing_debug_implementations)]
5#![no_std]
6
7mod write_buffer;
8
9use core::ffi::c_void;
10use mc_sgx_core_sys_types::sgx_status_t;
11use mc_sgx_core_types::Error;
12use mc_sgx_util::ResultInto;
13pub use write_buffer::WriteBuffer;
14
15pub fn stderr_write_all(buffer: &[u8]) -> Result<(), Error> {
26 unsafe { ocall_stderr(buffer.as_ptr() as *const c_void, buffer.len()) }.into_result()
27}
28
29extern "C" {
30 fn ocall_stderr(input: *const c_void, len: usize) -> sgx_status_t;
42}
43
44#[cfg(test)]
46extern crate std;
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use core::slice;
52 use once_cell::sync::Lazy;
53 use serial_test::serial;
54 use std::string::String;
55 use std::sync::Mutex;
56
57 static TEST_STREAM: Lazy<Mutex<String>> = Lazy::new(|| Mutex::new(String::new()));
58 static TEST_STREAM_RESULT: Lazy<Mutex<sgx_status_t>> =
59 Lazy::new(|| Mutex::new(sgx_status_t::SGX_SUCCESS));
60
61 fn reset_test_stream() {
62 let mut stream = TEST_STREAM.lock().expect("Mutex has been poisoned");
63 stream.clear();
64 let mut status = TEST_STREAM_RESULT.lock().expect("Mutex has been poisoned");
65 *status = sgx_status_t::SGX_SUCCESS;
66 }
67
68 #[no_mangle]
69 extern "C" fn ocall_stderr(input: *const c_void, len: usize) -> sgx_status_t {
70 let bytes = unsafe { slice::from_raw_parts(input as *const u8, len) };
71 let message =
72 std::str::from_utf8(bytes).expect("Expected valid UTF8 from stderr in enclave");
73 let mut stream = TEST_STREAM.lock().expect("Mutex has been poisoned");
74 stream.clear();
75 stream.push_str(message);
76 let status = TEST_STREAM_RESULT.lock().expect("Mutex has been poisoned");
77 *status
78 }
79
80 #[test]
81 #[serial]
82 fn single_line_output_to_stderr() {
83 reset_test_stream();
84 let test_message = b"what";
85 stderr_write_all(test_message).expect("Expected the write to succeed");
86
87 let written = TEST_STREAM.lock().expect("Mutex has been poisoned");
88 assert_eq!(written.as_bytes(), test_message);
89 }
90
91 #[test]
92 #[serial]
93 fn multi_line_output_to_stderr() {
94 reset_test_stream();
95 let test_message = b"this\nhas\nmultiple\nlines";
96 stderr_write_all(test_message).expect("Expected the write to succeed");
97
98 let written = TEST_STREAM.lock().expect("Mutex has been poisoned");
99 assert_eq!(written.as_bytes(), test_message);
100 }
101
102 #[test]
103 #[serial]
104 fn error_when_outputting_to_stderr() {
105 reset_test_stream();
106 let expected_error = sgx_status_t::SGX_ERROR_FILE_BAD_STATUS;
107 {
108 let mut status = TEST_STREAM_RESULT.lock().expect("Mutex has been poisoned");
109 *status = expected_error;
110 }
111
112 let error = stderr_write_all(b"what").unwrap_err();
113 assert_eq!(error, Error::FileBadStatus);
114 }
115}