1 /* 2 * This file is derived from src/ffi/c_str.rs in the Rust standard library, used 3 * under the Apache License, Version 2.0. The following is the original 4 * copyright information from the Rust project: 5 * 6 * Copyrights in the Rust project are retained by their contributors. No 7 * copyright assignment is required to contribute to the Rust project. 8 * 9 * Some files include explicit copyright notices and/or license notices. 10 * For full authorship information, see the version control history or 11 * https://thanks.rust-lang.org 12 * 13 * Except as otherwise noted (below and/or in individual files), Rust is 14 * licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or 15 * <http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 16 * <LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. 17 * 18 * 19 * Licensed under the Apache License, Version 2.0 (the "License"); 20 * you may not use this file except in compliance with the License. 21 * You may obtain a copy of the License at 22 * 23 * http://www.apache.org/licenses/LICENSE-2.0 24 * 25 * Unless required by applicable law or agreed to in writing, software 26 * distributed under the License is distributed on an "AS IS" BASIS, 27 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 * See the License for the specific language governing permissions and 29 * limitations under the License. 30 */ 31 32 //! Implementation of CString and CStr for use in Trusty. 33 //! 34 //! This module is a lightly modified version of `ffi/c_str.rs` from the Rust 35 //! std crate. `CString::new()` is replaced by the fallible allocating 36 //! [`CString::try_new()`] and other APIs which can allocate infallibly are 37 //! removed. 38 39 use crate::alloc::{AllocError, TryAllocInto}; 40 use crate::TryClone; 41 use alloc::ffi::CString; 42 use alloc::vec::Vec; 43 use core::slice::memchr; 44 45 #[derive(PartialEq, Eq, Debug)] 46 pub enum TryNewError { 47 /// An error indicating that an interior nul byte was found. 48 /// 49 /// While Rust strings may contain nul bytes in the middle, C strings 50 /// can't, as that byte would effectively truncate the string. 51 /// 52 /// This error is created by the [`CString::try_new`] method. 53 /// See its documentation for more. 54 /// 55 /// # Examples 56 /// 57 /// ``` 58 /// use std::ffi::{CString, NulError}; 59 /// 60 /// let _: NulError = CString::new(b"f\0oo".to_vec()).unwrap_err(); 61 /// ``` 62 NulError(usize, Vec<u8>), 63 64 AllocError, 65 } 66 67 impl From<AllocError> for TryNewError { from(_err: AllocError) -> Self68 fn from(_err: AllocError) -> Self { 69 TryNewError::AllocError 70 } 71 } 72 73 pub trait FallibleCString { 74 /// Creates a new C-compatible string from a container of bytes. 75 /// 76 /// This function will consume the provided data and use the 77 /// underlying bytes to construct a new string, ensuring that 78 /// there is a trailing 0 byte. This trailing 0 byte will be 79 /// appended by this function; the provided data should *not* 80 /// contain any 0 bytes in it. 81 /// 82 /// # Examples 83 /// 84 /// ```ignore (extern-declaration) 85 /// use std::ffi::CString; 86 /// use std::os::raw::c_char; 87 /// 88 /// extern "C" { fn puts(s: *const c_char); } 89 /// 90 /// let to_print = CString::new("Hello!").expect("CString::new failed"); 91 /// unsafe { 92 /// puts(to_print.as_ptr()); 93 /// } 94 /// ``` 95 /// 96 /// # Errors 97 /// 98 /// This function will return an error if the supplied bytes contain an 99 /// internal 0 byte. The [`TryNewError::NulError`] returned will contain the bytes as well as 100 /// the position of the nul byte. try_new<T: TryAllocInto<Vec<u8>>>(t: T) -> Result<CString, TryNewError>101 fn try_new<T: TryAllocInto<Vec<u8>>>(t: T) -> Result<CString, TryNewError>; 102 103 /// Creates a C-compatible string by consuming a byte vector, 104 /// without checking for interior 0 bytes. 105 /// 106 /// This method is equivalent to [`CString::try_new`] except that no runtime 107 /// assertion is made that `v` contains no 0 bytes, and it requires an 108 /// actual byte vector, not anything that can be converted to one with Into. 109 /// 110 /// # Examples 111 /// 112 /// ``` 113 /// use std::ffi::CString; 114 /// 115 /// let raw = b"foo".to_vec(); 116 /// unsafe { 117 /// let c_string = CString::from_vec_unchecked(raw); 118 /// } 119 /// ``` try_from_vec_unchecked(v: Vec<u8>) -> Result<CString, AllocError>120 unsafe fn try_from_vec_unchecked(v: Vec<u8>) -> Result<CString, AllocError>; 121 } 122 123 impl FallibleCString for CString { try_new<T: TryAllocInto<Vec<u8>>>(t: T) -> Result<CString, TryNewError>124 fn try_new<T: TryAllocInto<Vec<u8>>>(t: T) -> Result<CString, TryNewError> { 125 trait SpecIntoVec { 126 fn into_vec(self) -> Result<Vec<u8>, AllocError>; 127 } 128 impl<T: TryAllocInto<Vec<u8>>> SpecIntoVec for T { 129 default fn into_vec(self) -> Result<Vec<u8>, AllocError> { 130 self.try_alloc_into() 131 } 132 } 133 // Specialization for avoiding reallocation. 134 impl SpecIntoVec for &'_ [u8] { 135 fn into_vec(self) -> Result<Vec<u8>, AllocError> { 136 let mut v = Vec::new(); 137 v.try_reserve_exact(self.len() + 1).or(Err(AllocError))?; 138 v.extend_from_slice(self); 139 Ok(v) 140 } 141 } 142 impl SpecIntoVec for &'_ str { 143 fn into_vec(self) -> Result<Vec<u8>, AllocError> { 144 let mut v = Vec::new(); 145 v.try_reserve_exact(self.len() + 1).or(Err(AllocError))?; 146 v.extend_from_slice(self.as_bytes()); 147 Ok(v) 148 } 149 } 150 151 let bytes = SpecIntoVec::into_vec(t)?; 152 match memchr::memchr(0, &bytes) { 153 Some(i) => Err(TryNewError::NulError(i, bytes)), 154 None => Ok(unsafe { CString::try_from_vec_unchecked(bytes)? }), 155 } 156 } 157 try_from_vec_unchecked(mut v: Vec<u8>) -> Result<CString, AllocError>158 unsafe fn try_from_vec_unchecked(mut v: Vec<u8>) -> Result<CString, AllocError> { 159 v.try_reserve_exact(1).or(Err(AllocError))?; 160 v.push(0); 161 Ok(CString::from_vec_with_nul_unchecked(v)) 162 } 163 } 164 165 impl TryClone for CString { 166 type Error = AllocError; 167 try_clone(&self) -> Result<Self, Self::Error>168 fn try_clone(&self) -> Result<Self, Self::Error> { 169 let inner = self.as_bytes_with_nul().try_alloc_into()?; 170 171 // SAFETY: The `Vec` used here was cloned directly from an existing `CString`, 172 // and so upholds the invariants required. 173 Ok(unsafe { CString::from_vec_with_nul_unchecked(inner) }) 174 } 175 } 176