Coverage Report

Created: 2026-02-26 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustix-1.1.4/src/cstr.rs
Line
Count
Source
1
/// A macro for [`CStr`] literals.
2
///
3
/// This can make passing string literals to rustix APIs more efficient, since
4
/// most underlying system calls with string arguments expect NUL-terminated
5
/// strings, and passing strings to rustix as `CStr`s means that rustix doesn't
6
/// need to copy them into a separate buffer to NUL-terminate them.
7
///
8
/// In Rust ≥ 1.77, users can use [C-string literals] instead of this macro.
9
///
10
/// [`CStr`]: crate::ffi::CStr
11
/// [C-string literals]: https://blog.rust-lang.org/2024/03/21/Rust-1.77.0.html#c-string-literals
12
///
13
/// # Examples
14
///
15
/// ```
16
/// # #[cfg(feature = "fs")]
17
/// # fn main() -> rustix::io::Result<()> {
18
/// use rustix::cstr;
19
/// use rustix::fs::{statat, AtFlags, CWD};
20
///
21
/// let metadata = statat(CWD, cstr!("Cargo.toml"), AtFlags::empty())?;
22
/// # Ok(())
23
/// # }
24
/// # #[cfg(not(feature = "fs"))]
25
/// # fn main() {}
26
/// ```
27
#[allow(unused_macros)]
28
#[macro_export]
29
macro_rules! cstr {
30
    ($str:literal) => {{
31
        // Check for NUL manually, to ensure safety.
32
        //
33
        // In release builds, with strings that don't contain NULs, this
34
        // constant-folds away.
35
        //
36
        // We don't use std's `CStr::from_bytes_with_nul`; as of this writing,
37
        // that function isn't defined as `#[inline]` in std and doesn't
38
        // constant-fold away.
39
        ::core::assert!(
40
0
            !::core::iter::Iterator::any(&mut ::core::primitive::str::bytes($str), |b| b == b'\0'),
Unexecuted instantiation: <rustix::backend::fs::dir::Dir>::_read_from::{closure#0}
Unexecuted instantiation: rustix_linux_procfs::proc_self_fd::{closure#0}::{closure#1}
Unexecuted instantiation: rustix_linux_procfs::proc_self_fdinfo::{closure#0}::{closure#1}
Unexecuted instantiation: rustix_linux_procfs::proc::{closure#0}::{closure#1}
Unexecuted instantiation: rustix_linux_procfs::proc_self::{closure#0}::{closure#2}
Unexecuted instantiation: rustix_linux_procfs::proc_self::{closure#0}::{closure#1}
Unexecuted instantiation: rustix_linux_procfs::is_mountpoint::{closure#0}
Unexecuted instantiation: rustix_linux_procfs::is_mountpoint::{closure#1}
Unexecuted instantiation: rustix_linux_procfs::open_and_check_file::{closure#3}
Unexecuted instantiation: rustix_linux_procfs::open_and_check_file::{closure#4}
Unexecuted instantiation: rustix_linux_procfs::proc_self_maps::{closure#0}
Unexecuted instantiation: rustix_linux_procfs::proc_self_status::{closure#0}
Unexecuted instantiation: rustix_linux_procfs::proc_self_pagemap::{closure#0}
Unexecuted instantiation: <rustix::backend::fs::dir::Dir>::_read_from::{closure#0}
Unexecuted instantiation: rustix::backend::vdso_wrappers::init::{closure#0}
Unexecuted instantiation: rustix::backend::vdso_wrappers::init::{closure#1}
41
            "cstr argument contains embedded NUL bytes",
42
        );
43
44
        #[allow(unsafe_code, unused_unsafe)]
45
        {
46
            // Now that we know the string doesn't have embedded NULs, we can
47
            // call `from_bytes_with_nul_unchecked`, which as of this writing
48
            // is defined as `#[inline]` and completely optimizes away.
49
            //
50
            // SAFETY: We have manually checked that the string does not
51
            // contain embedded NULs above, and we append or own NUL terminator
52
            // here.
53
            unsafe {
54
                $crate::ffi::CStr::from_bytes_with_nul_unchecked(
55
                    ::core::concat!($str, "\0").as_bytes(),
56
                )
57
            }
58
        }
59
    }};
60
}
61
62
#[cfg(test)]
63
mod tests {
64
    #[allow(unused_imports)]
65
    use super::*;
66
67
    #[test]
68
    fn test_cstr() {
69
        use crate::ffi::CString;
70
        use alloc::borrow::ToOwned as _;
71
        assert_eq!(cstr!(""), &*CString::new("").unwrap());
72
        assert_eq!(cstr!("").to_owned(), CString::new("").unwrap());
73
        assert_eq!(cstr!("hello"), &*CString::new("hello").unwrap());
74
        assert_eq!(cstr!("hello").to_owned(), CString::new("hello").unwrap());
75
    }
76
77
    #[test]
78
    #[should_panic]
79
    fn test_invalid_cstr() {
80
        let _ = cstr!("hello\0world");
81
    }
82
83
    #[test]
84
    #[should_panic]
85
    fn test_invalid_empty_cstr() {
86
        let _ = cstr!("\0");
87
    }
88
89
    #[no_implicit_prelude]
90
    mod hygiene {
91
        #[allow(unused_macros)]
92
        #[test]
93
        fn macro_hygiene() {
94
            macro_rules! assert {
95
                ($($tt:tt)*) => {
96
                    ::core::panic!("cstr! called the wrong assert! macro");
97
                };
98
            }
99
            macro_rules! concat {
100
                ($($tt:tt)*) => {{
101
                    let v: &str = ::core::panic!("cstr! called the wrong concat! macro");
102
                    v
103
                }};
104
            }
105
106
            let _ = cstr!("foo");
107
        }
108
    }
109
}