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 `CString` type

Add the `CString` type, which is an owned string that is guaranteed
to have exactly one `NUL` byte at the end, i.e. the owned equivalent
to `CStr` introduced earlier.

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

In order to do so, implement the `RawFormatter::new()` constructor
and the `RawFormatter::bytes_written()` method as well.

Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

authored by

Wedson Almeida Filho and committed by
Miguel Ojeda
65e1e497 fffed679

+89 -2
+89 -2
rust/kernel/str.rs
··· 2 2 3 3 //! String representations. 4 4 5 + use alloc::vec::Vec; 5 6 use core::fmt::{self, Write}; 6 7 use core::ops::{self, Deref, Index}; 7 8 ··· 385 384 /// is less than `end`. 386 385 pub(crate) struct RawFormatter { 387 386 // Use `usize` to use `saturating_*` functions. 388 - #[allow(dead_code)] 389 387 beg: usize, 390 388 pos: usize, 391 389 end: usize, 392 390 } 393 391 394 392 impl RawFormatter { 393 + /// Creates a new instance of [`RawFormatter`] with an empty buffer. 394 + fn new() -> Self { 395 + // INVARIANT: The buffer is empty, so the region that needs to be writable is empty. 396 + Self { 397 + beg: 0, 398 + pos: 0, 399 + end: 0, 400 + } 401 + } 402 + 395 403 /// Creates a new instance of [`RawFormatter`] with the given buffer pointers. 396 404 /// 397 405 /// # Safety ··· 438 428 /// N.B. It may point to invalid memory. 439 429 pub(crate) fn pos(&self) -> *mut u8 { 440 430 self.pos as _ 431 + } 432 + 433 + /// Return the number of bytes written to the formatter. 434 + pub(crate) fn bytes_written(&self) -> usize { 435 + self.pos - self.beg 441 436 } 442 437 } 443 438 ··· 484 469 /// 485 470 /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes 486 471 /// for the lifetime of the returned [`Formatter`]. 487 - #[allow(dead_code)] 488 472 pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self { 489 473 // SAFETY: The safety requirements of this function satisfy those of the callee. 490 474 Self(unsafe { RawFormatter::from_buffer(buf, len) }) ··· 508 494 } else { 509 495 Ok(()) 510 496 } 497 + } 498 + } 499 + 500 + /// An owned string that is guaranteed to have exactly one `NUL` byte, which is at the end. 501 + /// 502 + /// Used for interoperability with kernel APIs that take C strings. 503 + /// 504 + /// # Invariants 505 + /// 506 + /// The string is always `NUL`-terminated and contains no other `NUL` bytes. 507 + /// 508 + /// # Examples 509 + /// 510 + /// ``` 511 + /// use kernel::str::CString; 512 + /// 513 + /// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20)).unwrap(); 514 + /// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes()); 515 + /// 516 + /// let tmp = "testing"; 517 + /// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123)).unwrap(); 518 + /// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes()); 519 + /// 520 + /// // This fails because it has an embedded `NUL` byte. 521 + /// let s = CString::try_from_fmt(fmt!("a\0b{}", 123)); 522 + /// assert_eq!(s.is_ok(), false); 523 + /// ``` 524 + pub struct CString { 525 + buf: Vec<u8>, 526 + } 527 + 528 + impl CString { 529 + /// Creates an instance of [`CString`] from the given formatted arguments. 530 + pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> { 531 + // Calculate the size needed (formatted string plus `NUL` terminator). 532 + let mut f = RawFormatter::new(); 533 + f.write_fmt(args)?; 534 + f.write_str("\0")?; 535 + let size = f.bytes_written(); 536 + 537 + // Allocate a vector with the required number of bytes, and write to it. 538 + let mut buf = Vec::try_with_capacity(size)?; 539 + // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes. 540 + let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) }; 541 + f.write_fmt(args)?; 542 + f.write_str("\0")?; 543 + 544 + // SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is 545 + // `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`. 546 + unsafe { buf.set_len(f.bytes_written()) }; 547 + 548 + // Check that there are no `NUL` bytes before the end. 549 + // SAFETY: The buffer is valid for read because `f.bytes_written()` is bounded by `size` 550 + // (which the minimum buffer size) and is non-zero (we wrote at least the `NUL` terminator) 551 + // so `f.bytes_written() - 1` doesn't underflow. 552 + let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, (f.bytes_written() - 1) as _) }; 553 + if !ptr.is_null() { 554 + return Err(EINVAL); 555 + } 556 + 557 + // INVARIANT: We wrote the `NUL` terminator and checked above that no other `NUL` bytes 558 + // exist in the buffer. 559 + Ok(Self { buf }) 560 + } 561 + } 562 + 563 + impl Deref for CString { 564 + type Target = CStr; 565 + 566 + fn deref(&self) -> &Self::Target { 567 + // SAFETY: The type invariants guarantee that the string is `NUL`-terminated and that no 568 + // other `NUL` bytes exist. 569 + unsafe { CStr::from_bytes_with_nul_unchecked(self.buf.as_slice()) } 511 570 } 512 571 }