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: replace `CStr` with `core::ffi::CStr`

`kernel::ffi::CStr` was introduced in commit d126d2380131 ("rust: str:
add `CStr` type") in November 2022 as an upstreaming of earlier work
that was done in May 2021[0]. That earlier work, having predated the
inclusion of `CStr` in `core`, largely duplicated the implementation of
`std::ffi::CStr`.

`std::ffi::CStr` was moved to `core::ffi::CStr` in Rust 1.64 in
September 2022. Hence replace `kernel::str::CStr` with `core::ffi::CStr`
to reduce our custom code footprint, and retain needed custom
functionality through an extension trait.

Add `CStr` to `ffi` and the kernel prelude.

Link: https://github.com/Rust-for-Linux/linux/commit/faa3cbcca03d0dec8f8e43f1d8d5c0860d98a23f [0]
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Reviewed-by: Benno Lossin <lossin@kernel.org>
Signed-off-by: Tamir Duberstein <tamird@gmail.com>
Link: https://patch.msgid.link/20251018-cstr-core-v18-16-9378a54385f8@gmail.com
[ Removed assert that would now depend on the Rust version. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

authored by

Tamir Duberstein and committed by
Miguel Ojeda
3b83f5d5 c5cf01ba

+127 -330
+1 -1
drivers/android/binder/stats.rs
··· 61 61 62 62 mod strings { 63 63 use core::str::from_utf8_unchecked; 64 - use kernel::str::CStr; 64 + use kernel::str::{CStr, CStrExt as _}; 65 65 66 66 extern "C" { 67 67 static binder_command_strings: [*const u8; super::BC_COUNT];
+2
rust/ffi.rs
··· 46 46 } 47 47 48 48 pub use core::ffi::c_void; 49 + 50 + pub use core::ffi::CStr;
+1 -1
rust/kernel/debugfs/entry.rs
··· 3 3 4 4 use crate::debugfs::file_ops::FileOps; 5 5 use crate::ffi::c_void; 6 - use crate::str::CStr; 6 + use crate::str::{CStr, CStrExt as _}; 7 7 use crate::sync::Arc; 8 8 use core::marker::PhantomData; 9 9
+1
rust/kernel/device.rs
··· 13 13 14 14 #[cfg(CONFIG_PRINTK)] 15 15 use crate::c_str; 16 + use crate::str::CStrExt as _; 16 17 17 18 pub mod property; 18 19
+3 -1
rust/kernel/drm/ioctl.rs
··· 156 156 Some($cmd) 157 157 }, 158 158 flags: $flags, 159 - name: $crate::c_str!(::core::stringify!($cmd)).as_char_ptr(), 159 + name: $crate::str::as_char_ptr_in_const_context( 160 + $crate::c_str!(::core::stringify!($cmd)), 161 + ), 160 162 } 161 163 ),*]; 162 164 ioctls
+2
rust/kernel/error.rs
··· 182 182 if ptr.is_null() { 183 183 None 184 184 } else { 185 + use crate::str::CStrExt as _; 186 + 185 187 // SAFETY: The string returned by `errname` is static and `NUL`-terminated. 186 188 Some(unsafe { CStr::from_char_ptr(ptr) }) 187 189 }
+8 -1
rust/kernel/firmware.rs
··· 4 4 //! 5 5 //! C header: [`include/linux/firmware.h`](srctree/include/linux/firmware.h) 6 6 7 - use crate::{bindings, device::Device, error::Error, error::Result, ffi, str::CStr}; 7 + use crate::{ 8 + bindings, 9 + device::Device, 10 + error::Error, 11 + error::Result, 12 + ffi, 13 + str::{CStr, CStrExt as _}, 14 + }; 8 15 use core::ptr::NonNull; 9 16 10 17 /// # Invariants
+2 -2
rust/kernel/prelude.rs
··· 19 19 20 20 pub use ::ffi::{ 21 21 c_char, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong, c_ulonglong, 22 - c_ushort, c_void, 22 + c_ushort, c_void, CStr, 23 23 }; 24 24 25 25 pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec, Vec}; ··· 43 43 44 44 pub use super::error::{code::*, Error, Result}; 45 45 46 - pub use super::{str::CStr, ThisModule}; 46 + pub use super::{str::CStrExt as _, ThisModule}; 47 47 48 48 pub use super::init::InPlaceInit; 49 49
+1 -1
rust/kernel/seq_file.rs
··· 4 4 //! 5 5 //! C header: [`include/linux/seq_file.h`](srctree/include/linux/seq_file.h) 6 6 7 - use crate::{bindings, c_str, fmt, types::NotThreadSafe, types::Opaque}; 7 + use crate::{bindings, c_str, fmt, str::CStrExt as _, types::NotThreadSafe, types::Opaque}; 8 8 9 9 /// A utility for generating the contents of a seq file. 10 10 #[repr(transparent)]
+103 -320
rust/kernel/str.rs
··· 10 10 }; 11 11 use core::{ 12 12 marker::PhantomData, 13 - ops::{self, Deref, DerefMut, Index}, 13 + ops::{Deref, DerefMut, Index}, 14 14 }; 15 + 16 + pub use crate::prelude::CStr; 15 17 16 18 /// Byte string without UTF-8 validity guarantee. 17 19 #[repr(transparent)] ··· 188 186 // - error[E0379]: functions in trait impls cannot be declared const 189 187 #[inline] 190 188 pub const fn as_char_ptr_in_const_context(c_str: &CStr) -> *const c_char { 191 - c_str.0.as_ptr() 189 + c_str.as_ptr().cast() 192 190 } 193 191 194 - /// Possible errors when using conversion functions in [`CStr`]. 195 - #[derive(Debug, Clone, Copy)] 196 - pub enum CStrConvertError { 197 - /// Supplied bytes contain an interior `NUL`. 198 - InteriorNul, 192 + mod private { 193 + pub trait Sealed {} 199 194 200 - /// Supplied bytes are not terminated by `NUL`. 201 - NotNulTerminated, 195 + impl Sealed for super::CStr {} 202 196 } 203 197 204 - impl From<CStrConvertError> for Error { 205 - #[inline] 206 - fn from(_: CStrConvertError) -> Error { 207 - EINVAL 208 - } 209 - } 210 - 211 - /// A string that is guaranteed to have exactly one `NUL` byte, which is at the 212 - /// end. 213 - /// 214 - /// Used for interoperability with kernel APIs that take C strings. 215 - #[repr(transparent)] 216 - pub struct CStr([u8]); 217 - 218 - impl CStr { 219 - /// Returns the length of this string excluding `NUL`. 220 - #[inline] 221 - pub const fn len(&self) -> usize { 222 - self.len_with_nul() - 1 223 - } 224 - 225 - /// Returns the length of this string with `NUL`. 226 - #[inline] 227 - pub const fn len_with_nul(&self) -> usize { 228 - if self.0.is_empty() { 229 - // SAFETY: This is one of the invariant of `CStr`. 230 - // We add a `unreachable_unchecked` here to hint the optimizer that 231 - // the value returned from this function is non-zero. 232 - unsafe { core::hint::unreachable_unchecked() }; 233 - } 234 - self.0.len() 235 - } 236 - 237 - /// Returns `true` if the string only includes `NUL`. 238 - #[inline] 239 - pub const fn is_empty(&self) -> bool { 240 - self.len() == 0 241 - } 242 - 198 + /// Extensions to [`CStr`]. 199 + pub trait CStrExt: private::Sealed { 243 200 /// Wraps a raw C string pointer. 244 201 /// 245 202 /// # Safety ··· 206 245 /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must 207 246 /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr` 208 247 /// must not be mutated. 209 - #[inline] 210 - pub unsafe fn from_char_ptr<'a>(ptr: *const c_char) -> &'a Self { 211 - // SAFETY: The safety precondition guarantees `ptr` is a valid pointer 212 - // to a `NUL`-terminated C string. 213 - let len = unsafe { bindings::strlen(ptr) } + 1; 214 - // SAFETY: Lifetime guaranteed by the safety precondition. 215 - let bytes = unsafe { core::slice::from_raw_parts(ptr.cast(), len) }; 216 - // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`. 217 - // As we have added 1 to `len`, the last byte is known to be `NUL`. 218 - unsafe { Self::from_bytes_with_nul_unchecked(bytes) } 219 - } 220 - 221 - /// Creates a [`CStr`] from a `[u8]`. 222 - /// 223 - /// The provided slice must be `NUL`-terminated, does not contain any 224 - /// interior `NUL` bytes. 225 - pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> { 226 - if bytes.is_empty() { 227 - return Err(CStrConvertError::NotNulTerminated); 228 - } 229 - if bytes[bytes.len() - 1] != 0 { 230 - return Err(CStrConvertError::NotNulTerminated); 231 - } 232 - let mut i = 0; 233 - // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking, 234 - // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`. 235 - while i + 1 < bytes.len() { 236 - if bytes[i] == 0 { 237 - return Err(CStrConvertError::InteriorNul); 238 - } 239 - i += 1; 240 - } 241 - // SAFETY: We just checked that all properties hold. 242 - Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) 243 - } 244 - 245 - /// Creates a [`CStr`] from a `[u8]` without performing any additional 246 - /// checks. 247 - /// 248 - /// # Safety 249 - /// 250 - /// `bytes` *must* end with a `NUL` byte, and should only have a single 251 - /// `NUL` byte (or the string will be truncated). 252 - #[inline] 253 - pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { 254 - // SAFETY: Properties of `bytes` guaranteed by the safety precondition. 255 - unsafe { core::mem::transmute(bytes) } 256 - } 248 + // This function exists to paper over the fact that `CStr::from_ptr` takes a `*const 249 + // core::ffi::c_char` rather than a `*const crate::ffi::c_char`. 250 + unsafe fn from_char_ptr<'a>(ptr: *const c_char) -> &'a Self; 257 251 258 252 /// Creates a mutable [`CStr`] from a `[u8]` without performing any 259 253 /// additional checks. ··· 217 301 /// 218 302 /// `bytes` *must* end with a `NUL` byte, and should only have a single 219 303 /// `NUL` byte (or the string will be truncated). 220 - #[inline] 221 - pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr { 222 - // SAFETY: Properties of `bytes` guaranteed by the safety precondition. 223 - unsafe { &mut *(core::ptr::from_mut(bytes) as *mut CStr) } 224 - } 304 + unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut Self; 225 305 226 306 /// Returns a C pointer to the string. 227 - /// 228 - /// Using this function in a const context is deprecated in favor of 229 - /// [`as_char_ptr_in_const_context`] in preparation for replacing `CStr` with `core::ffi::CStr` 230 - /// which does not have this method. 231 - #[inline] 232 - pub const fn as_char_ptr(&self) -> *const c_char { 233 - as_char_ptr_in_const_context(self) 234 - } 235 - 236 - /// Convert the string to a byte slice without the trailing `NUL` byte. 237 - #[inline] 238 - pub fn to_bytes(&self) -> &[u8] { 239 - &self.0[..self.len()] 240 - } 241 - 242 - /// Convert the string to a byte slice without the trailing `NUL` byte. 243 - /// 244 - /// This function is deprecated in favor of [`Self::to_bytes`] in preparation for replacing 245 - /// `CStr` with `core::ffi::CStr` which does not have this method. 246 - #[inline] 247 - pub fn as_bytes(&self) -> &[u8] { 248 - self.to_bytes() 249 - } 250 - 251 - /// Convert the string to a byte slice containing the trailing `NUL` byte. 252 - #[inline] 253 - pub const fn to_bytes_with_nul(&self) -> &[u8] { 254 - &self.0 255 - } 256 - 257 - /// Convert the string to a byte slice containing the trailing `NUL` byte. 258 - /// 259 - /// This function is deprecated in favor of [`Self::to_bytes_with_nul`] in preparation for 260 - /// replacing `CStr` with `core::ffi::CStr` which does not have this method. 261 - #[inline] 262 - pub const fn as_bytes_with_nul(&self) -> &[u8] { 263 - self.to_bytes_with_nul() 264 - } 265 - 266 - /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8. 267 - /// 268 - /// If the contents of the [`CStr`] are valid UTF-8 data, this 269 - /// function will return the corresponding [`&str`] slice. Otherwise, 270 - /// it will return an error with details of where UTF-8 validation failed. 271 - /// 272 - /// # Examples 273 - /// 274 - /// ``` 275 - /// # use kernel::str::CStr; 276 - /// let cstr = CStr::from_bytes_with_nul(b"foo\0")?; 277 - /// assert_eq!(cstr.to_str(), Ok("foo")); 278 - /// # Ok::<(), kernel::error::Error>(()) 279 - /// ``` 280 - #[inline] 281 - pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> { 282 - core::str::from_utf8(self.as_bytes()) 283 - } 284 - 285 - /// Unsafely convert this [`CStr`] into a [`&str`], without checking for 286 - /// valid UTF-8. 287 - /// 288 - /// # Safety 289 - /// 290 - /// The contents must be valid UTF-8. 291 - /// 292 - /// # Examples 293 - /// 294 - /// ``` 295 - /// # use kernel::c_str; 296 - /// # use kernel::str::CStr; 297 - /// let bar = c_str!("ツ"); 298 - /// // SAFETY: String literals are guaranteed to be valid UTF-8 299 - /// // by the Rust compiler. 300 - /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ"); 301 - /// ``` 302 - #[inline] 303 - pub unsafe fn as_str_unchecked(&self) -> &str { 304 - // SAFETY: TODO. 305 - unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } 306 - } 307 + // This function exists to paper over the fact that `CStr::as_ptr` returns a `*const 308 + // core::ffi::c_char` rather than a `*const crate::ffi::c_char`. 309 + fn as_char_ptr(&self) -> *const c_char; 307 310 308 311 /// Convert this [`CStr`] into a [`CString`] by allocating memory and 309 312 /// copying over the string data. 310 - pub fn to_cstring(&self) -> Result<CString, AllocError> { 311 - CString::try_from(self) 312 - } 313 + fn to_cstring(&self) -> Result<CString, AllocError>; 313 314 314 315 /// Converts this [`CStr`] to its ASCII lower case equivalent in-place. 315 316 /// ··· 237 404 /// [`to_ascii_lowercase()`]. 238 405 /// 239 406 /// [`to_ascii_lowercase()`]: #method.to_ascii_lowercase 240 - pub fn make_ascii_lowercase(&mut self) { 241 - // INVARIANT: This doesn't introduce or remove NUL bytes in the C 242 - // string. 243 - self.0.make_ascii_lowercase(); 244 - } 407 + fn make_ascii_lowercase(&mut self); 245 408 246 409 /// Converts this [`CStr`] to its ASCII upper case equivalent in-place. 247 410 /// ··· 248 419 /// [`to_ascii_uppercase()`]. 249 420 /// 250 421 /// [`to_ascii_uppercase()`]: #method.to_ascii_uppercase 251 - pub fn make_ascii_uppercase(&mut self) { 252 - // INVARIANT: This doesn't introduce or remove NUL bytes in the C 253 - // string. 254 - self.0.make_ascii_uppercase(); 255 - } 422 + fn make_ascii_uppercase(&mut self); 256 423 257 424 /// Returns a copy of this [`CString`] where each character is mapped to its 258 425 /// ASCII lower case equivalent. ··· 259 434 /// To lowercase the value in-place, use [`make_ascii_lowercase`]. 260 435 /// 261 436 /// [`make_ascii_lowercase`]: str::make_ascii_lowercase 262 - pub fn to_ascii_lowercase(&self) -> Result<CString, AllocError> { 263 - let mut s = self.to_cstring()?; 264 - 265 - s.make_ascii_lowercase(); 266 - 267 - Ok(s) 268 - } 437 + fn to_ascii_lowercase(&self) -> Result<CString, AllocError>; 269 438 270 439 /// Returns a copy of this [`CString`] where each character is mapped to its 271 440 /// ASCII upper case equivalent. ··· 270 451 /// To uppercase the value in-place, use [`make_ascii_uppercase`]. 271 452 /// 272 453 /// [`make_ascii_uppercase`]: str::make_ascii_uppercase 273 - pub fn to_ascii_uppercase(&self) -> Result<CString, AllocError> { 274 - let mut s = self.to_cstring()?; 275 - 276 - s.make_ascii_uppercase(); 277 - 278 - Ok(s) 279 - } 454 + fn to_ascii_uppercase(&self) -> Result<CString, AllocError>; 280 455 } 281 456 282 457 impl fmt::Display for CStr { ··· 303 490 } 304 491 } 305 492 306 - impl fmt::Debug for CStr { 307 - /// Formats printable ASCII characters with a double quote on either end, escaping the rest. 308 - /// 309 - /// ``` 310 - /// # use kernel::c_str; 311 - /// # use kernel::prelude::fmt; 312 - /// # use kernel::str::CStr; 313 - /// # use kernel::str::CString; 314 - /// let penguin = c_str!("🐧"); 315 - /// let s = CString::try_from_fmt(fmt!("{penguin:?}"))?; 316 - /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes()); 317 - /// 318 - /// // Embedded double quotes are escaped. 319 - /// let ascii = c_str!("so \"cool\""); 320 - /// let s = CString::try_from_fmt(fmt!("{ascii:?}"))?; 321 - /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes()); 322 - /// # Ok::<(), kernel::error::Error>(()) 323 - /// ``` 324 - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 325 - f.write_str("\"")?; 326 - for &c in self.as_bytes() { 327 - match c { 328 - // Printable characters. 329 - b'\"' => f.write_str("\\\"")?, 330 - 0x20..=0x7e => f.write_char(c as char)?, 331 - _ => write!(f, "\\x{c:02x}")?, 332 - } 333 - } 334 - f.write_str("\"") 493 + /// Converts a mutable C string to a mutable byte slice. 494 + /// 495 + /// # Safety 496 + /// 497 + /// The caller must ensure that the slice ends in a NUL byte and contains no other NUL bytes before 498 + /// the borrow ends and the underlying [`CStr`] is used. 499 + unsafe fn to_bytes_mut(s: &mut CStr) -> &mut [u8] { 500 + // SAFETY: the cast from `&CStr` to `&[u8]` is safe since `CStr` has the same layout as `&[u8]` 501 + // (this is technically not guaranteed, but we rely on it here). The pointer dereference is 502 + // safe since it comes from a mutable reference which is guaranteed to be valid for writes. 503 + unsafe { &mut *(core::ptr::from_mut(s) as *mut [u8]) } 504 + } 505 + 506 + impl CStrExt for CStr { 507 + #[inline] 508 + unsafe fn from_char_ptr<'a>(ptr: *const c_char) -> &'a Self { 509 + // SAFETY: The safety preconditions are the same as for `CStr::from_ptr`. 510 + unsafe { CStr::from_ptr(ptr.cast()) } 511 + } 512 + 513 + #[inline] 514 + unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut Self { 515 + // SAFETY: the cast from `&[u8]` to `&CStr` is safe since the properties of `bytes` are 516 + // guaranteed by the safety precondition and `CStr` has the same layout as `&[u8]` (this is 517 + // technically not guaranteed, but we rely on it here). The pointer dereference is safe 518 + // since it comes from a mutable reference which is guaranteed to be valid for writes. 519 + unsafe { &mut *(core::ptr::from_mut(bytes) as *mut CStr) } 520 + } 521 + 522 + #[inline] 523 + fn as_char_ptr(&self) -> *const c_char { 524 + self.as_ptr().cast() 525 + } 526 + 527 + fn to_cstring(&self) -> Result<CString, AllocError> { 528 + CString::try_from(self) 529 + } 530 + 531 + fn make_ascii_lowercase(&mut self) { 532 + // SAFETY: This doesn't introduce or remove NUL bytes in the C string. 533 + unsafe { to_bytes_mut(self) }.make_ascii_lowercase(); 534 + } 535 + 536 + fn make_ascii_uppercase(&mut self) { 537 + // SAFETY: This doesn't introduce or remove NUL bytes in the C string. 538 + unsafe { to_bytes_mut(self) }.make_ascii_uppercase(); 539 + } 540 + 541 + fn to_ascii_lowercase(&self) -> Result<CString, AllocError> { 542 + let mut s = self.to_cstring()?; 543 + 544 + s.make_ascii_lowercase(); 545 + 546 + Ok(s) 547 + } 548 + 549 + fn to_ascii_uppercase(&self) -> Result<CString, AllocError> { 550 + let mut s = self.to_cstring()?; 551 + 552 + s.make_ascii_uppercase(); 553 + 554 + Ok(s) 335 555 } 336 556 } 337 557 338 558 impl AsRef<BStr> for CStr { 339 559 #[inline] 340 560 fn as_ref(&self) -> &BStr { 341 - BStr::from_bytes(self.as_bytes()) 342 - } 343 - } 344 - 345 - impl Deref for CStr { 346 - type Target = BStr; 347 - 348 - #[inline] 349 - fn deref(&self) -> &Self::Target { 350 - self.as_ref() 351 - } 352 - } 353 - 354 - impl Index<ops::RangeFrom<usize>> for CStr { 355 - type Output = CStr; 356 - 357 - #[inline] 358 - fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output { 359 - // Delegate bounds checking to slice. 360 - // Assign to _ to mute clippy's unnecessary operation warning. 361 - let _ = &self.as_bytes()[index.start..]; 362 - // SAFETY: We just checked the bounds. 363 - unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) } 364 - } 365 - } 366 - 367 - impl Index<ops::RangeFull> for CStr { 368 - type Output = CStr; 369 - 370 - #[inline] 371 - fn index(&self, _index: ops::RangeFull) -> &Self::Output { 372 - self 373 - } 374 - } 375 - 376 - mod private { 377 - use core::ops; 378 - 379 - // Marker trait for index types that can be forward to `BStr`. 380 - pub trait CStrIndex {} 381 - 382 - impl CStrIndex for usize {} 383 - impl CStrIndex for ops::Range<usize> {} 384 - impl CStrIndex for ops::RangeInclusive<usize> {} 385 - impl CStrIndex for ops::RangeToInclusive<usize> {} 386 - } 387 - 388 - impl<Idx> Index<Idx> for CStr 389 - where 390 - Idx: private::CStrIndex, 391 - BStr: Index<Idx>, 392 - { 393 - type Output = <BStr as Index<Idx>>::Output; 394 - 395 - #[inline] 396 - fn index(&self, index: Idx) -> &Self::Output { 397 - &self.as_ref()[index] 561 + BStr::from_bytes(self.to_bytes()) 398 562 } 399 563 } 400 564 ··· 402 612 mod tests { 403 613 use super::*; 404 614 615 + impl From<core::ffi::FromBytesWithNulError> for Error { 616 + #[inline] 617 + fn from(_: core::ffi::FromBytesWithNulError) -> Error { 618 + EINVAL 619 + } 620 + } 621 + 405 622 macro_rules! format { 406 623 ($($f:tt)*) => ({ 407 624 CString::try_from_fmt(fmt!($($f)*))?.to_str()? ··· 431 634 432 635 #[test] 433 636 fn test_cstr_to_str() -> Result { 434 - let good_bytes = b"\xf0\x9f\xa6\x80\0"; 435 - let checked_cstr = CStr::from_bytes_with_nul(good_bytes)?; 436 - let checked_str = checked_cstr.to_str()?; 637 + let cstr = c"\xf0\x9f\xa6\x80"; 638 + let checked_str = cstr.to_str()?; 437 639 assert_eq!(checked_str, "🦀"); 438 640 Ok(()) 439 641 } 440 642 441 643 #[test] 442 644 fn test_cstr_to_str_invalid_utf8() -> Result { 443 - let bad_bytes = b"\xc3\x28\0"; 444 - let checked_cstr = CStr::from_bytes_with_nul(bad_bytes)?; 445 - assert!(checked_cstr.to_str().is_err()); 446 - Ok(()) 447 - } 448 - 449 - #[test] 450 - fn test_cstr_as_str_unchecked() -> Result { 451 - let good_bytes = b"\xf0\x9f\x90\xA7\0"; 452 - let checked_cstr = CStr::from_bytes_with_nul(good_bytes)?; 453 - // SAFETY: The contents come from a string literal which contains valid UTF-8. 454 - let unchecked_str = unsafe { checked_cstr.as_str_unchecked() }; 455 - assert_eq!(unchecked_str, "🐧"); 645 + let cstr = c"\xc3\x28"; 646 + assert!(cstr.to_str().is_err()); 456 647 Ok(()) 457 648 } 458 649 459 650 #[test] 460 651 fn test_cstr_display() -> Result { 461 - let hello_world = CStr::from_bytes_with_nul(b"hello, world!\0")?; 652 + let hello_world = c"hello, world!"; 462 653 assert_eq!(format!("{hello_world}"), "hello, world!"); 463 - let non_printables = CStr::from_bytes_with_nul(b"\x01\x09\x0a\0")?; 654 + let non_printables = c"\x01\x09\x0a"; 464 655 assert_eq!(format!("{non_printables}"), "\\x01\\x09\\x0a"); 465 - let non_ascii = CStr::from_bytes_with_nul(b"d\xe9j\xe0 vu\0")?; 656 + let non_ascii = c"d\xe9j\xe0 vu"; 466 657 assert_eq!(format!("{non_ascii}"), "d\\xe9j\\xe0 vu"); 467 - let good_bytes = CStr::from_bytes_with_nul(b"\xf0\x9f\xa6\x80\0")?; 658 + let good_bytes = c"\xf0\x9f\xa6\x80"; 468 659 assert_eq!(format!("{good_bytes}"), "\\xf0\\x9f\\xa6\\x80"); 469 660 Ok(()) 470 661 } ··· 471 686 472 687 #[test] 473 688 fn test_cstr_debug() -> Result { 474 - let hello_world = CStr::from_bytes_with_nul(b"hello, world!\0")?; 689 + let hello_world = c"hello, world!"; 475 690 assert_eq!(format!("{hello_world:?}"), "\"hello, world!\""); 476 - let non_printables = CStr::from_bytes_with_nul(b"\x01\x09\x0a\0")?; 477 - assert_eq!(format!("{non_printables:?}"), "\"\\x01\\x09\\x0a\""); 478 - let non_ascii = CStr::from_bytes_with_nul(b"d\xe9j\xe0 vu\0")?; 691 + let non_printables = c"\x01\x09\x0a"; 692 + assert_eq!(format!("{non_printables:?}"), "\"\\x01\\t\\n\""); 693 + let non_ascii = c"d\xe9j\xe0 vu"; 479 694 assert_eq!(format!("{non_ascii:?}"), "\"d\\xe9j\\xe0 vu\""); 480 - let good_bytes = CStr::from_bytes_with_nul(b"\xf0\x9f\xa6\x80\0")?; 481 - assert_eq!(format!("{good_bytes:?}"), "\"\\xf0\\x9f\\xa6\\x80\""); 482 695 Ok(()) 483 696 } 484 697
+1 -1
rust/kernel/sync/condvar.rs
··· 8 8 use super::{lock::Backend, lock::Guard, LockClassKey}; 9 9 use crate::{ 10 10 ffi::{c_int, c_long}, 11 - str::CStr, 11 + str::{CStr, CStrExt as _}, 12 12 task::{ 13 13 MAX_SCHEDULE_TIMEOUT, TASK_FREEZABLE, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE, 14 14 },
+1 -1
rust/kernel/sync/lock.rs
··· 7 7 8 8 use super::LockClassKey; 9 9 use crate::{ 10 - str::CStr, 10 + str::{CStr, CStrExt as _}, 11 11 types::{NotThreadSafe, Opaque, ScopeGuard}, 12 12 }; 13 13 use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};
+1 -1
rust/kernel/sync/lock/global.rs
··· 5 5 //! Support for defining statics containing locks. 6 6 7 7 use crate::{ 8 - str::CStr, 8 + str::{CStr, CStrExt as _}, 9 9 sync::lock::{Backend, Guard, Lock}, 10 10 sync::{LockClassKey, LockedBy}, 11 11 types::Opaque,