Skip to content

Commit e97fa1e

Browse files
committed
libstd/ffi/c_str.rs: #![deny(unsafe_op_in_unsafe_fn)], enclose unsafe operations in unsafe blocks
1 parent b6396b7 commit e97fa1e

File tree

1 file changed

+32
-7
lines changed

1 file changed

+32
-7
lines changed

library/std/src/ffi/c_str.rs

+32-7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![deny(unsafe_op_in_unsafe_fn)]
12
use crate::ascii;
23
use crate::borrow::{Borrow, Cow};
34
use crate::cmp::Ordering;
@@ -510,9 +511,16 @@ impl CString {
510511
/// ```
511512
#[stable(feature = "cstr_memory", since = "1.4.0")]
512513
pub unsafe fn from_raw(ptr: *mut c_char) -> CString {
513-
let len = sys::strlen(ptr) + 1; // Including the NUL byte
514-
let slice = slice::from_raw_parts_mut(ptr, len as usize);
515-
CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) }
514+
// SAFETY: This is called with a pointer that was obtained from a call
515+
// to `CString::into_raw` and the length has not been modified. As such,
516+
// we know there is a NUL byte (and only one) at the end and that the
517+
// information about the size of the allocation is correct on Rust's
518+
// side.
519+
unsafe {
520+
let len = sys::strlen(ptr) + 1; // Including the NUL byte
521+
let slice = slice::from_raw_parts_mut(ptr, len as usize);
522+
CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) }
523+
}
516524
}
517525

518526
/// Consumes the `CString` and transfers ownership of the string to a C caller.
@@ -1228,9 +1236,21 @@ impl CStr {
12281236
/// ```
12291237
#[stable(feature = "rust1", since = "1.0.0")]
12301238
pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
1231-
let len = sys::strlen(ptr);
1232-
let ptr = ptr as *const u8;
1233-
CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
1239+
// SAFETY: The caller has provided a pointer that points to a valid C
1240+
// string with a NUL terminator of size less than `isize::MAX`, whose
1241+
// content remain valid and doesn't change for the lifetime of the
1242+
// returned `CStr`.
1243+
//
1244+
// Thus computing the length is fine (a NUL byte exists), the call to
1245+
// from_raw_parts is safe because we know the length is at most `isize::MAX`, meaning
1246+
// the call to `from_bytes_with_nul_unchecked` is correct.
1247+
//
1248+
// The cast from c_char to u8 is ok because a c_char is always one byte.
1249+
unsafe {
1250+
let len = sys::strlen(ptr);
1251+
let ptr = ptr as *const u8;
1252+
CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
1253+
}
12341254
}
12351255

12361256
/// Creates a C string wrapper from a byte slice.
@@ -1299,7 +1319,12 @@ impl CStr {
12991319
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
13001320
#[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "none")]
13011321
pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
1302-
&*(bytes as *const [u8] as *const CStr)
1322+
// SAFETY: Casting to CStr is safe because its internal representation
1323+
// is a [u8] too (safe only inside std).
1324+
// Dereferencing the obtained pointer is safe because it comes from a
1325+
// reference. Making a reference is then safe because its lifetime
1326+
// is bound by the lifetime of the given `bytes`.
1327+
unsafe { &*(bytes as *const [u8] as *const CStr) }
13031328
}
13041329

13051330
/// Returns the inner pointer to this C string.

0 commit comments

Comments
 (0)