Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: str: add `CStr` type

Add the `CStr` type, which is a borrowed string that is guaranteed
to have exactly one `NUL` byte, which is at the end.

It is used for interoperability with kernel APIs that take C strings.

Add it to the prelude too.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

authored by

Gary Guo and committed by
Miguel Ojeda
d126d238 650ec515

+170 -1
+1 -1
rust/kernel/prelude.rs
··· 21 21 22 22 pub use super::error::{code::*, Error, Result}; 23 23 24 - pub use super::ThisModule; 24 + pub use super::{str::CStr, ThisModule};
+169
rust/kernel/str.rs
··· 4 4 5 5 use core::fmt; 6 6 7 + use crate::{ 8 + bindings, 9 + error::{code::*, Error}, 10 + }; 11 + 7 12 /// Byte string without UTF-8 validity guarantee. 8 13 /// 9 14 /// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning. ··· 33 28 const C: &'static $crate::str::BStr = S.as_bytes(); 34 29 C 35 30 }}; 31 + } 32 + 33 + /// Possible errors when using conversion functions in [`CStr`]. 34 + #[derive(Debug, Clone, Copy)] 35 + pub enum CStrConvertError { 36 + /// Supplied bytes contain an interior `NUL`. 37 + InteriorNul, 38 + 39 + /// Supplied bytes are not terminated by `NUL`. 40 + NotNulTerminated, 41 + } 42 + 43 + impl From<CStrConvertError> for Error { 44 + #[inline] 45 + fn from(_: CStrConvertError) -> Error { 46 + EINVAL 47 + } 48 + } 49 + 50 + /// A string that is guaranteed to have exactly one `NUL` byte, which is at the 51 + /// end. 52 + /// 53 + /// Used for interoperability with kernel APIs that take C strings. 54 + #[repr(transparent)] 55 + pub struct CStr([u8]); 56 + 57 + impl CStr { 58 + /// Returns the length of this string excluding `NUL`. 59 + #[inline] 60 + pub const fn len(&self) -> usize { 61 + self.len_with_nul() - 1 62 + } 63 + 64 + /// Returns the length of this string with `NUL`. 65 + #[inline] 66 + pub const fn len_with_nul(&self) -> usize { 67 + // SAFETY: This is one of the invariant of `CStr`. 68 + // We add a `unreachable_unchecked` here to hint the optimizer that 69 + // the value returned from this function is non-zero. 70 + if self.0.is_empty() { 71 + unsafe { core::hint::unreachable_unchecked() }; 72 + } 73 + self.0.len() 74 + } 75 + 76 + /// Returns `true` if the string only includes `NUL`. 77 + #[inline] 78 + pub const fn is_empty(&self) -> bool { 79 + self.len() == 0 80 + } 81 + 82 + /// Wraps a raw C string pointer. 83 + /// 84 + /// # Safety 85 + /// 86 + /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must 87 + /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr` 88 + /// must not be mutated. 89 + #[inline] 90 + pub unsafe fn from_char_ptr<'a>(ptr: *const core::ffi::c_char) -> &'a Self { 91 + // SAFETY: The safety precondition guarantees `ptr` is a valid pointer 92 + // to a `NUL`-terminated C string. 93 + let len = unsafe { bindings::strlen(ptr) } + 1; 94 + // SAFETY: Lifetime guaranteed by the safety precondition. 95 + let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) }; 96 + // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`. 97 + // As we have added 1 to `len`, the last byte is known to be `NUL`. 98 + unsafe { Self::from_bytes_with_nul_unchecked(bytes) } 99 + } 100 + 101 + /// Creates a [`CStr`] from a `[u8]`. 102 + /// 103 + /// The provided slice must be `NUL`-terminated, does not contain any 104 + /// interior `NUL` bytes. 105 + pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> { 106 + if bytes.is_empty() { 107 + return Err(CStrConvertError::NotNulTerminated); 108 + } 109 + if bytes[bytes.len() - 1] != 0 { 110 + return Err(CStrConvertError::NotNulTerminated); 111 + } 112 + let mut i = 0; 113 + // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking, 114 + // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`. 115 + while i + 1 < bytes.len() { 116 + if bytes[i] == 0 { 117 + return Err(CStrConvertError::InteriorNul); 118 + } 119 + i += 1; 120 + } 121 + // SAFETY: We just checked that all properties hold. 122 + Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) 123 + } 124 + 125 + /// Creates a [`CStr`] from a `[u8]` without performing any additional 126 + /// checks. 127 + /// 128 + /// # Safety 129 + /// 130 + /// `bytes` *must* end with a `NUL` byte, and should only have a single 131 + /// `NUL` byte (or the string will be truncated). 132 + #[inline] 133 + pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { 134 + // SAFETY: Properties of `bytes` guaranteed by the safety precondition. 135 + unsafe { core::mem::transmute(bytes) } 136 + } 137 + 138 + /// Returns a C pointer to the string. 139 + #[inline] 140 + pub const fn as_char_ptr(&self) -> *const core::ffi::c_char { 141 + self.0.as_ptr() as _ 142 + } 143 + 144 + /// Convert the string to a byte slice without the trailing 0 byte. 145 + #[inline] 146 + pub fn as_bytes(&self) -> &[u8] { 147 + &self.0[..self.len()] 148 + } 149 + 150 + /// Convert the string to a byte slice containing the trailing 0 byte. 151 + #[inline] 152 + pub const fn as_bytes_with_nul(&self) -> &[u8] { 153 + &self.0 154 + } 155 + 156 + /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8. 157 + /// 158 + /// If the contents of the [`CStr`] are valid UTF-8 data, this 159 + /// function will return the corresponding [`&str`] slice. Otherwise, 160 + /// it will return an error with details of where UTF-8 validation failed. 161 + /// 162 + /// # Examples 163 + /// 164 + /// ``` 165 + /// # use kernel::str::CStr; 166 + /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap(); 167 + /// assert_eq!(cstr.to_str(), Ok("foo")); 168 + /// ``` 169 + #[inline] 170 + pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> { 171 + core::str::from_utf8(self.as_bytes()) 172 + } 173 + 174 + /// Unsafely convert this [`CStr`] into a [`&str`], without checking for 175 + /// valid UTF-8. 176 + /// 177 + /// # Safety 178 + /// 179 + /// The contents must be valid UTF-8. 180 + /// 181 + /// # Examples 182 + /// 183 + /// ``` 184 + /// # use kernel::c_str; 185 + /// # use kernel::str::CStr; 186 + /// // SAFETY: String literals are guaranteed to be valid UTF-8 187 + /// // by the Rust compiler. 188 + /// let bar = c_str!("ツ"); 189 + /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ"); 190 + /// ``` 191 + #[inline] 192 + pub unsafe fn as_str_unchecked(&self) -> &str { 193 + unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } 194 + } 36 195 } 37 196 38 197 /// Allows formatting of [`fmt::Arguments`] into a raw buffer.