Commit | Line | Data |
---|---|---|
247b365d WAF |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | ||
3 | //! String representations. | |
4 | ||
65e1e497 | 5 | use alloc::vec::Vec; |
c07e67bd GG |
6 | use core::fmt::{self, Write}; |
7 | use core::ops::{self, Deref, Index}; | |
247b365d | 8 | |
d126d238 GG |
9 | use crate::{ |
10 | bindings, | |
11 | error::{code::*, Error}, | |
12 | }; | |
13 | ||
7c597746 GG |
14 | /// Byte string without UTF-8 validity guarantee. |
15 | /// | |
16 | /// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning. | |
17 | pub type BStr = [u8]; | |
18 | ||
650ec515 GG |
19 | /// Creates a new [`BStr`] from a string literal. |
20 | /// | |
21 | /// `b_str!` converts the supplied string literal to byte string, so non-ASCII | |
22 | /// characters can be included. | |
23 | /// | |
24 | /// # Examples | |
25 | /// | |
26 | /// ``` | |
27 | /// # use kernel::b_str; | |
28 | /// # use kernel::str::BStr; | |
29 | /// const MY_BSTR: &BStr = b_str!("My awesome BStr!"); | |
30 | /// ``` | |
31 | #[macro_export] | |
32 | macro_rules! b_str { | |
33 | ($str:literal) => {{ | |
34 | const S: &'static str = $str; | |
35 | const C: &'static $crate::str::BStr = S.as_bytes(); | |
36 | C | |
37 | }}; | |
38 | } | |
39 | ||
d126d238 GG |
40 | /// Possible errors when using conversion functions in [`CStr`]. |
41 | #[derive(Debug, Clone, Copy)] | |
42 | pub enum CStrConvertError { | |
43 | /// Supplied bytes contain an interior `NUL`. | |
44 | InteriorNul, | |
45 | ||
46 | /// Supplied bytes are not terminated by `NUL`. | |
47 | NotNulTerminated, | |
48 | } | |
49 | ||
50 | impl From<CStrConvertError> for Error { | |
51 | #[inline] | |
52 | fn from(_: CStrConvertError) -> Error { | |
53 | EINVAL | |
54 | } | |
55 | } | |
56 | ||
57 | /// A string that is guaranteed to have exactly one `NUL` byte, which is at the | |
58 | /// end. | |
59 | /// | |
60 | /// Used for interoperability with kernel APIs that take C strings. | |
61 | #[repr(transparent)] | |
62 | pub struct CStr([u8]); | |
63 | ||
64 | impl CStr { | |
65 | /// Returns the length of this string excluding `NUL`. | |
66 | #[inline] | |
67 | pub const fn len(&self) -> usize { | |
68 | self.len_with_nul() - 1 | |
69 | } | |
70 | ||
71 | /// Returns the length of this string with `NUL`. | |
72 | #[inline] | |
73 | pub const fn len_with_nul(&self) -> usize { | |
74 | // SAFETY: This is one of the invariant of `CStr`. | |
75 | // We add a `unreachable_unchecked` here to hint the optimizer that | |
76 | // the value returned from this function is non-zero. | |
77 | if self.0.is_empty() { | |
78 | unsafe { core::hint::unreachable_unchecked() }; | |
79 | } | |
80 | self.0.len() | |
81 | } | |
82 | ||
83 | /// Returns `true` if the string only includes `NUL`. | |
84 | #[inline] | |
85 | pub const fn is_empty(&self) -> bool { | |
86 | self.len() == 0 | |
87 | } | |
88 | ||
89 | /// Wraps a raw C string pointer. | |
90 | /// | |
91 | /// # Safety | |
92 | /// | |
93 | /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must | |
94 | /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr` | |
95 | /// must not be mutated. | |
96 | #[inline] | |
97 | pub unsafe fn from_char_ptr<'a>(ptr: *const core::ffi::c_char) -> &'a Self { | |
98 | // SAFETY: The safety precondition guarantees `ptr` is a valid pointer | |
99 | // to a `NUL`-terminated C string. | |
100 | let len = unsafe { bindings::strlen(ptr) } + 1; | |
101 | // SAFETY: Lifetime guaranteed by the safety precondition. | |
102 | let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) }; | |
103 | // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`. | |
104 | // As we have added 1 to `len`, the last byte is known to be `NUL`. | |
105 | unsafe { Self::from_bytes_with_nul_unchecked(bytes) } | |
106 | } | |
107 | ||
108 | /// Creates a [`CStr`] from a `[u8]`. | |
109 | /// | |
110 | /// The provided slice must be `NUL`-terminated, does not contain any | |
111 | /// interior `NUL` bytes. | |
112 | pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> { | |
113 | if bytes.is_empty() { | |
114 | return Err(CStrConvertError::NotNulTerminated); | |
115 | } | |
116 | if bytes[bytes.len() - 1] != 0 { | |
117 | return Err(CStrConvertError::NotNulTerminated); | |
118 | } | |
119 | let mut i = 0; | |
120 | // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking, | |
121 | // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`. | |
122 | while i + 1 < bytes.len() { | |
123 | if bytes[i] == 0 { | |
124 | return Err(CStrConvertError::InteriorNul); | |
125 | } | |
126 | i += 1; | |
127 | } | |
128 | // SAFETY: We just checked that all properties hold. | |
129 | Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) | |
130 | } | |
131 | ||
132 | /// Creates a [`CStr`] from a `[u8]` without performing any additional | |
133 | /// checks. | |
134 | /// | |
135 | /// # Safety | |
136 | /// | |
137 | /// `bytes` *must* end with a `NUL` byte, and should only have a single | |
138 | /// `NUL` byte (or the string will be truncated). | |
139 | #[inline] | |
140 | pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { | |
141 | // SAFETY: Properties of `bytes` guaranteed by the safety precondition. | |
142 | unsafe { core::mem::transmute(bytes) } | |
143 | } | |
144 | ||
145 | /// Returns a C pointer to the string. | |
146 | #[inline] | |
147 | pub const fn as_char_ptr(&self) -> *const core::ffi::c_char { | |
148 | self.0.as_ptr() as _ | |
149 | } | |
150 | ||
151 | /// Convert the string to a byte slice without the trailing 0 byte. | |
152 | #[inline] | |
153 | pub fn as_bytes(&self) -> &[u8] { | |
154 | &self.0[..self.len()] | |
155 | } | |
156 | ||
157 | /// Convert the string to a byte slice containing the trailing 0 byte. | |
158 | #[inline] | |
159 | pub const fn as_bytes_with_nul(&self) -> &[u8] { | |
160 | &self.0 | |
161 | } | |
162 | ||
163 | /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8. | |
164 | /// | |
165 | /// If the contents of the [`CStr`] are valid UTF-8 data, this | |
166 | /// function will return the corresponding [`&str`] slice. Otherwise, | |
167 | /// it will return an error with details of where UTF-8 validation failed. | |
168 | /// | |
169 | /// # Examples | |
170 | /// | |
171 | /// ``` | |
172 | /// # use kernel::str::CStr; | |
173 | /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap(); | |
174 | /// assert_eq!(cstr.to_str(), Ok("foo")); | |
175 | /// ``` | |
176 | #[inline] | |
177 | pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> { | |
178 | core::str::from_utf8(self.as_bytes()) | |
179 | } | |
180 | ||
181 | /// Unsafely convert this [`CStr`] into a [`&str`], without checking for | |
182 | /// valid UTF-8. | |
183 | /// | |
184 | /// # Safety | |
185 | /// | |
186 | /// The contents must be valid UTF-8. | |
187 | /// | |
188 | /// # Examples | |
189 | /// | |
190 | /// ``` | |
191 | /// # use kernel::c_str; | |
192 | /// # use kernel::str::CStr; | |
193 | /// // SAFETY: String literals are guaranteed to be valid UTF-8 | |
194 | /// // by the Rust compiler. | |
195 | /// let bar = c_str!("ツ"); | |
196 | /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ"); | |
197 | /// ``` | |
198 | #[inline] | |
199 | pub unsafe fn as_str_unchecked(&self) -> &str { | |
200 | unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } | |
201 | } | |
202 | } | |
203 | ||
c07e67bd GG |
204 | impl fmt::Display for CStr { |
205 | /// Formats printable ASCII characters, escaping the rest. | |
206 | /// | |
207 | /// ``` | |
208 | /// # use kernel::c_str; | |
209 | /// # use kernel::str::CStr; | |
210 | /// # use kernel::str::CString; | |
211 | /// let penguin = c_str!("🐧"); | |
212 | /// let s = CString::try_from_fmt(fmt!("{}", penguin)).unwrap(); | |
213 | /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes()); | |
214 | /// | |
215 | /// let ascii = c_str!("so \"cool\""); | |
216 | /// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap(); | |
217 | /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes()); | |
218 | /// ``` | |
219 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
220 | for &c in self.as_bytes() { | |
221 | if (0x20..0x7f).contains(&c) { | |
222 | // Printable character. | |
223 | f.write_char(c as char)?; | |
224 | } else { | |
225 | write!(f, "\\x{:02x}", c)?; | |
226 | } | |
227 | } | |
228 | Ok(()) | |
229 | } | |
230 | } | |
231 | ||
232 | impl fmt::Debug for CStr { | |
233 | /// Formats printable ASCII characters with a double quote on either end, escaping the rest. | |
234 | /// | |
235 | /// ``` | |
236 | /// # use kernel::c_str; | |
237 | /// # use kernel::str::CStr; | |
238 | /// # use kernel::str::CString; | |
239 | /// let penguin = c_str!("🐧"); | |
240 | /// let s = CString::try_from_fmt(fmt!("{:?}", penguin)).unwrap(); | |
241 | /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes()); | |
242 | /// | |
243 | /// // Embedded double quotes are escaped. | |
244 | /// let ascii = c_str!("so \"cool\""); | |
245 | /// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap(); | |
246 | /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes()); | |
247 | /// ``` | |
248 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
249 | f.write_str("\"")?; | |
250 | for &c in self.as_bytes() { | |
251 | match c { | |
252 | // Printable characters. | |
253 | b'\"' => f.write_str("\\\"")?, | |
254 | 0x20..=0x7e => f.write_char(c as char)?, | |
255 | _ => write!(f, "\\x{:02x}", c)?, | |
256 | } | |
257 | } | |
258 | f.write_str("\"") | |
259 | } | |
260 | } | |
261 | ||
262 | impl AsRef<BStr> for CStr { | |
263 | #[inline] | |
264 | fn as_ref(&self) -> &BStr { | |
265 | self.as_bytes() | |
266 | } | |
267 | } | |
268 | ||
269 | impl Deref for CStr { | |
270 | type Target = BStr; | |
271 | ||
272 | #[inline] | |
273 | fn deref(&self) -> &Self::Target { | |
274 | self.as_bytes() | |
275 | } | |
276 | } | |
277 | ||
278 | impl Index<ops::RangeFrom<usize>> for CStr { | |
279 | type Output = CStr; | |
280 | ||
281 | #[inline] | |
282 | fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output { | |
283 | // Delegate bounds checking to slice. | |
284 | // Assign to _ to mute clippy's unnecessary operation warning. | |
285 | let _ = &self.as_bytes()[index.start..]; | |
286 | // SAFETY: We just checked the bounds. | |
287 | unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) } | |
288 | } | |
289 | } | |
290 | ||
291 | impl Index<ops::RangeFull> for CStr { | |
292 | type Output = CStr; | |
293 | ||
294 | #[inline] | |
295 | fn index(&self, _index: ops::RangeFull) -> &Self::Output { | |
296 | self | |
297 | } | |
298 | } | |
299 | ||
300 | mod private { | |
301 | use core::ops; | |
302 | ||
303 | // Marker trait for index types that can be forward to `BStr`. | |
304 | pub trait CStrIndex {} | |
305 | ||
306 | impl CStrIndex for usize {} | |
307 | impl CStrIndex for ops::Range<usize> {} | |
308 | impl CStrIndex for ops::RangeInclusive<usize> {} | |
309 | impl CStrIndex for ops::RangeToInclusive<usize> {} | |
310 | } | |
311 | ||
312 | impl<Idx> Index<Idx> for CStr | |
313 | where | |
314 | Idx: private::CStrIndex, | |
315 | BStr: Index<Idx>, | |
316 | { | |
317 | type Output = <BStr as Index<Idx>>::Output; | |
318 | ||
319 | #[inline] | |
320 | fn index(&self, index: Idx) -> &Self::Output { | |
321 | &self.as_bytes()[index] | |
322 | } | |
323 | } | |
324 | ||
b18cb00e GG |
325 | /// Creates a new [`CStr`] from a string literal. |
326 | /// | |
327 | /// The string literal should not contain any `NUL` bytes. | |
328 | /// | |
329 | /// # Examples | |
330 | /// | |
331 | /// ``` | |
332 | /// # use kernel::c_str; | |
333 | /// # use kernel::str::CStr; | |
334 | /// const MY_CSTR: &CStr = c_str!("My awesome CStr!"); | |
335 | /// ``` | |
336 | #[macro_export] | |
337 | macro_rules! c_str { | |
338 | ($str:expr) => {{ | |
339 | const S: &str = concat!($str, "\0"); | |
340 | const C: &$crate::str::CStr = match $crate::str::CStr::from_bytes_with_nul(S.as_bytes()) { | |
341 | Ok(v) => v, | |
342 | Err(_) => panic!("string contains interior NUL"), | |
343 | }; | |
344 | C | |
345 | }}; | |
346 | } | |
347 | ||
985f1f09 ML |
348 | #[cfg(test)] |
349 | mod tests { | |
350 | use super::*; | |
351 | ||
352 | #[test] | |
353 | fn test_cstr_to_str() { | |
354 | let good_bytes = b"\xf0\x9f\xa6\x80\0"; | |
355 | let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap(); | |
356 | let checked_str = checked_cstr.to_str().unwrap(); | |
357 | assert_eq!(checked_str, "🦀"); | |
358 | } | |
359 | ||
360 | #[test] | |
361 | #[should_panic] | |
362 | fn test_cstr_to_str_panic() { | |
363 | let bad_bytes = b"\xc3\x28\0"; | |
364 | let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap(); | |
365 | checked_cstr.to_str().unwrap(); | |
366 | } | |
367 | ||
368 | #[test] | |
369 | fn test_cstr_as_str_unchecked() { | |
370 | let good_bytes = b"\xf0\x9f\x90\xA7\0"; | |
371 | let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap(); | |
372 | let unchecked_str = unsafe { checked_cstr.as_str_unchecked() }; | |
373 | assert_eq!(unchecked_str, "🐧"); | |
374 | } | |
375 | } | |
376 | ||
247b365d WAF |
377 | /// Allows formatting of [`fmt::Arguments`] into a raw buffer. |
378 | /// | |
379 | /// It does not fail if callers write past the end of the buffer so that they can calculate the | |
380 | /// size required to fit everything. | |
381 | /// | |
382 | /// # Invariants | |
383 | /// | |
384 | /// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos` | |
385 | /// is less than `end`. | |
386 | pub(crate) struct RawFormatter { | |
387 | // Use `usize` to use `saturating_*` functions. | |
247b365d WAF |
388 | beg: usize, |
389 | pos: usize, | |
390 | end: usize, | |
391 | } | |
392 | ||
393 | impl RawFormatter { | |
65e1e497 WAF |
394 | /// Creates a new instance of [`RawFormatter`] with an empty buffer. |
395 | fn new() -> Self { | |
396 | // INVARIANT: The buffer is empty, so the region that needs to be writable is empty. | |
397 | Self { | |
398 | beg: 0, | |
399 | pos: 0, | |
400 | end: 0, | |
401 | } | |
402 | } | |
403 | ||
247b365d WAF |
404 | /// Creates a new instance of [`RawFormatter`] with the given buffer pointers. |
405 | /// | |
406 | /// # Safety | |
407 | /// | |
408 | /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end` | |
409 | /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`]. | |
410 | pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self { | |
88e8c2ec | 411 | // INVARIANT: The safety requirements guarantee the type invariants. |
247b365d WAF |
412 | Self { |
413 | beg: pos as _, | |
414 | pos: pos as _, | |
415 | end: end as _, | |
416 | } | |
417 | } | |
418 | ||
fffed679 WAF |
419 | /// Creates a new instance of [`RawFormatter`] with the given buffer. |
420 | /// | |
421 | /// # Safety | |
422 | /// | |
423 | /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes | |
424 | /// for the lifetime of the returned [`RawFormatter`]. | |
425 | pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self { | |
426 | let pos = buf as usize; | |
427 | // INVARIANT: We ensure that `end` is never less then `buf`, and the safety requirements | |
428 | // guarantees that the memory region is valid for writes. | |
429 | Self { | |
430 | pos, | |
431 | beg: pos, | |
432 | end: pos.saturating_add(len), | |
433 | } | |
434 | } | |
435 | ||
247b365d WAF |
436 | /// Returns the current insert position. |
437 | /// | |
438 | /// N.B. It may point to invalid memory. | |
439 | pub(crate) fn pos(&self) -> *mut u8 { | |
440 | self.pos as _ | |
441 | } | |
65e1e497 WAF |
442 | |
443 | /// Return the number of bytes written to the formatter. | |
444 | pub(crate) fn bytes_written(&self) -> usize { | |
445 | self.pos - self.beg | |
446 | } | |
247b365d WAF |
447 | } |
448 | ||
449 | impl fmt::Write for RawFormatter { | |
450 | fn write_str(&mut self, s: &str) -> fmt::Result { | |
451 | // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we | |
452 | // don't want it to wrap around to 0. | |
453 | let pos_new = self.pos.saturating_add(s.len()); | |
454 | ||
455 | // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`. | |
456 | let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos); | |
457 | ||
458 | if len_to_copy > 0 { | |
459 | // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end` | |
460 | // yet, so it is valid for write per the type invariants. | |
461 | unsafe { | |
462 | core::ptr::copy_nonoverlapping( | |
463 | s.as_bytes().as_ptr(), | |
464 | self.pos as *mut u8, | |
465 | len_to_copy, | |
466 | ) | |
467 | }; | |
468 | } | |
469 | ||
470 | self.pos = pos_new; | |
471 | Ok(()) | |
472 | } | |
473 | } | |
fffed679 WAF |
474 | |
475 | /// Allows formatting of [`fmt::Arguments`] into a raw buffer. | |
476 | /// | |
477 | /// Fails if callers attempt to write more than will fit in the buffer. | |
478 | pub(crate) struct Formatter(RawFormatter); | |
479 | ||
480 | impl Formatter { | |
481 | /// Creates a new instance of [`Formatter`] with the given buffer. | |
482 | /// | |
483 | /// # Safety | |
484 | /// | |
485 | /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes | |
486 | /// for the lifetime of the returned [`Formatter`]. | |
fffed679 WAF |
487 | pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self { |
488 | // SAFETY: The safety requirements of this function satisfy those of the callee. | |
489 | Self(unsafe { RawFormatter::from_buffer(buf, len) }) | |
490 | } | |
491 | } | |
492 | ||
493 | impl Deref for Formatter { | |
494 | type Target = RawFormatter; | |
495 | ||
496 | fn deref(&self) -> &Self::Target { | |
497 | &self.0 | |
498 | } | |
499 | } | |
500 | ||
501 | impl fmt::Write for Formatter { | |
502 | fn write_str(&mut self, s: &str) -> fmt::Result { | |
503 | self.0.write_str(s)?; | |
504 | ||
505 | // Fail the request if we go past the end of the buffer. | |
506 | if self.0.pos > self.0.end { | |
507 | Err(fmt::Error) | |
508 | } else { | |
509 | Ok(()) | |
510 | } | |
511 | } | |
512 | } | |
65e1e497 WAF |
513 | |
514 | /// An owned string that is guaranteed to have exactly one `NUL` byte, which is at the end. | |
515 | /// | |
516 | /// Used for interoperability with kernel APIs that take C strings. | |
517 | /// | |
518 | /// # Invariants | |
519 | /// | |
520 | /// The string is always `NUL`-terminated and contains no other `NUL` bytes. | |
521 | /// | |
522 | /// # Examples | |
523 | /// | |
524 | /// ``` | |
525 | /// use kernel::str::CString; | |
526 | /// | |
527 | /// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20)).unwrap(); | |
528 | /// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes()); | |
529 | /// | |
530 | /// let tmp = "testing"; | |
531 | /// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123)).unwrap(); | |
532 | /// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes()); | |
533 | /// | |
534 | /// // This fails because it has an embedded `NUL` byte. | |
535 | /// let s = CString::try_from_fmt(fmt!("a\0b{}", 123)); | |
536 | /// assert_eq!(s.is_ok(), false); | |
537 | /// ``` | |
538 | pub struct CString { | |
539 | buf: Vec<u8>, | |
540 | } | |
541 | ||
542 | impl CString { | |
543 | /// Creates an instance of [`CString`] from the given formatted arguments. | |
544 | pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> { | |
545 | // Calculate the size needed (formatted string plus `NUL` terminator). | |
546 | let mut f = RawFormatter::new(); | |
547 | f.write_fmt(args)?; | |
548 | f.write_str("\0")?; | |
549 | let size = f.bytes_written(); | |
550 | ||
551 | // Allocate a vector with the required number of bytes, and write to it. | |
552 | let mut buf = Vec::try_with_capacity(size)?; | |
553 | // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes. | |
554 | let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) }; | |
555 | f.write_fmt(args)?; | |
556 | f.write_str("\0")?; | |
557 | ||
558 | // SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is | |
559 | // `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`. | |
560 | unsafe { buf.set_len(f.bytes_written()) }; | |
561 | ||
562 | // Check that there are no `NUL` bytes before the end. | |
563 | // SAFETY: The buffer is valid for read because `f.bytes_written()` is bounded by `size` | |
564 | // (which the minimum buffer size) and is non-zero (we wrote at least the `NUL` terminator) | |
565 | // so `f.bytes_written() - 1` doesn't underflow. | |
566 | let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, (f.bytes_written() - 1) as _) }; | |
567 | if !ptr.is_null() { | |
568 | return Err(EINVAL); | |
569 | } | |
570 | ||
571 | // INVARIANT: We wrote the `NUL` terminator and checked above that no other `NUL` bytes | |
572 | // exist in the buffer. | |
573 | Ok(Self { buf }) | |
574 | } | |
575 | } | |
576 | ||
577 | impl Deref for CString { | |
578 | type Target = CStr; | |
579 | ||
580 | fn deref(&self) -> &Self::Target { | |
581 | // SAFETY: The type invariants guarantee that the string is `NUL`-terminated and that no | |
582 | // other `NUL` bytes exist. | |
583 | unsafe { CStr::from_bytes_with_nul_unchecked(self.buf.as_slice()) } | |
584 | } | |
585 | } | |
ef320549 WAF |
586 | |
587 | /// A convenience alias for [`core::format_args`]. | |
588 | #[macro_export] | |
589 | macro_rules! fmt { | |
590 | ($($f:tt)*) => ( core::format_args!($($f)*) ) | |
591 | } |