kernel/library/std/
string.rs1use alloc::string::String;
2use alloc::vec::Vec;
3
4#[derive(Debug, PartialEq)]
5pub enum StringConversionError {
6 NullPointer,
7 ExceedsMaxLength,
8 Utf8Error,
9 TranslationError,
10 TooManyStrings,
11}
12
13pub fn cstring_to_string(
15 cstr_ptr: *const u8,
16 max_len: usize,
17) -> Result<(String, usize), StringConversionError> {
18 if cstr_ptr.is_null() {
19 return Err(StringConversionError::NullPointer);
20 }
21 if max_len == 0 {
22 return Ok((String::new(), 0));
23 }
24
25 let mut len = 0;
26 while len < max_len && unsafe { *cstr_ptr.add(len) } != 0 {
27 len += 1;
28 }
29
30 if len > max_len {
31 return Err(StringConversionError::ExceedsMaxLength);
32 }
33
34 let bytes = unsafe { alloc::slice::from_raw_parts(cstr_ptr, len) };
35 match String::from_utf8(bytes.to_vec()) {
36 Ok(string) => Ok((string, len)),
37 Err(_) => Err(StringConversionError::Utf8Error),
38 }
39}
40
41pub fn parse_c_string_from_userspace(
43 task: &crate::task::Task,
44 ptr: usize,
45 max_len: usize,
46) -> Result<String, StringConversionError> {
47 if ptr == 0 {
48 return Err(StringConversionError::NullPointer);
49 }
50
51 let c_str_ptr = task
52 .vm_manager
53 .translate_vaddr(ptr)
54 .ok_or(StringConversionError::TranslationError)? as *const u8;
55
56 let (string, _) = cstring_to_string(c_str_ptr, max_len)?;
57 Ok(string)
58}
59
60pub fn parse_string_array_from_userspace(
62 task: &crate::task::Task,
63 array_ptr: usize,
64 max_strings: usize,
65 max_string_len: usize,
66) -> Result<Vec<String>, StringConversionError> {
67 if array_ptr == 0 {
68 return Ok(Vec::new());
69 }
70
71 let ptr_array = task
72 .vm_manager
73 .translate_vaddr(array_ptr)
74 .ok_or(StringConversionError::TranslationError)? as *const usize;
75
76 let mut strings = Vec::new();
77 let mut i = 0;
78
79 unsafe {
80 loop {
81 let str_ptr = *ptr_array.add(i);
82 if str_ptr == 0 {
83 break; }
85
86 let string = parse_c_string_from_userspace(task, str_ptr, max_string_len)?;
87 strings.push(string);
88 i += 1;
89
90 if i > max_strings {
91 return Err(StringConversionError::TooManyStrings);
92 }
93 }
94 }
95
96 Ok(strings)
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test_case]
104 fn test_cstring_to_string() {
105 let cstr = b"Hello, world!\0";
106 let res = cstring_to_string(cstr.as_ptr(), cstr.len()).unwrap();
107 assert_eq!(res, ("Hello, world!".into(), 13));
108 }
109
110 #[test_case]
111 fn test_cstring_to_string_empty() {
112 let cstr = b"\0";
113 let result = cstring_to_string(cstr.as_ptr(), cstr.len()).unwrap();
114 assert_eq!(result, ("".into(), 0));
115 }
116
117 #[test_case]
118 fn test_cstring_to_string_truncated() {
119 let cstr = b"Hello\0World\0";
120 let result = cstring_to_string(cstr.as_ptr(), 5);
121 assert_eq!(result, Ok(("Hello".into(), 5)));
122 }
123
124 #[test_case]
125 fn test_cstring_to_string_utf8_error() {
126 let invalid_utf8 = &[0xFF, 0xFE, 0xFD, 0x00]; let result = cstring_to_string(invalid_utf8.as_ptr(), 4);
128 assert_eq!(result, Err(StringConversionError::Utf8Error));
129 }
130
131 #[test_case]
132 fn test_parse_c_string_from_userspace_null_pointer() {
133 let task = crate::task::new_user_task("test".into(), 1);
135
136 let result = parse_c_string_from_userspace(&task, 0, 100);
138 assert_eq!(result, Err(StringConversionError::NullPointer));
139 }
140
141 #[test_case]
142 fn test_parse_string_array_from_userspace_null_pointer() {
143 let task = crate::task::new_user_task("test".into(), 1);
145
146 let result = parse_string_array_from_userspace(&task, 0, 10, 100);
148 assert!(result.is_ok());
149 assert_eq!(result.unwrap().len(), 0);
150 }
151}