about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-06-28 22:05:28 +0200
committerGitHub <noreply@github.com>2025-06-28 22:05:28 +0200
commitc6de7ca41a035a30472d51d5c3a5fb8bdc83c73e (patch)
treebae2a2adb8b9fbc18bea15fe0ea1419aac0692cd
parent7394bd5fc220c5bbf7b7dfde573c2e45d7825333 (diff)
parent6a1b7df4854b0023e34b18e2196d3069906da796 (diff)
Rollup merge of #142708 - Darksonn:location-len-without-nul, r=Mark-Simulacrum
Do not include NUL-terminator in computed length

This PR contains just the first commit of rust-lang/rust#142579 which changes it so that the string length stored in the `Location` is the length of the `&str` rather than the length of the `&CStr`. Since most users will want the `&str` length, it seems better to optimize for that use-case.

There should be no visible changes in the behavior or API.
-rw-r--r--compiler/rustc_const_eval/src/util/caller_location.rs12
-rw-r--r--library/core/src/panic/location.rs38
2 files changed, 30 insertions, 20 deletions
diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs
index ab2de279ed8..f489b05fbbd 100644
--- a/compiler/rustc_const_eval/src/util/caller_location.rs
+++ b/compiler/rustc_const_eval/src/util/caller_location.rs
@@ -21,13 +21,14 @@ fn alloc_caller_location<'tcx>(
     assert!(!filename.as_str().as_bytes().contains(&0));
 
     let loc_details = ecx.tcx.sess.opts.unstable_opts.location_detail;
-    let file_wide_ptr = {
+    let filename = {
         let filename = if loc_details.file { filename.as_str() } else { "<redacted>" };
         let filename_with_nul = filename.to_owned() + "\0";
         // This can fail if rustc runs out of memory right here. Trying to emit an error would be
         // pointless, since that would require allocating more memory than these short strings.
         let file_ptr = ecx.allocate_bytes_dedup(filename_with_nul.as_bytes()).unwrap();
-        Immediate::new_slice(file_ptr.into(), filename_with_nul.len().try_into().unwrap(), ecx)
+        let file_len = u64::try_from(filename.len()).unwrap();
+        Immediate::new_slice(file_ptr.into(), file_len, ecx)
     };
     let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
     let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
@@ -41,11 +42,8 @@ fn alloc_caller_location<'tcx>(
     let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
 
     // Initialize fields.
-    ecx.write_immediate(
-        file_wide_ptr,
-        &ecx.project_field(&location, FieldIdx::from_u32(0)).unwrap(),
-    )
-    .expect("writing to memory we just allocated cannot fail");
+    ecx.write_immediate(filename, &ecx.project_field(&location, FieldIdx::from_u32(0)).unwrap())
+        .expect("writing to memory we just allocated cannot fail");
     ecx.write_scalar(line, &ecx.project_field(&location, FieldIdx::from_u32(1)).unwrap())
         .expect("writing to memory we just allocated cannot fail");
     ecx.write_scalar(col, &ecx.project_field(&location, FieldIdx::from_u32(2)).unwrap())
diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs
index f1eedede8aa..97227020885 100644
--- a/library/core/src/panic/location.rs
+++ b/library/core/src/panic/location.rs
@@ -1,5 +1,7 @@
 use crate::ffi::CStr;
 use crate::fmt;
+use crate::marker::PhantomData;
+use crate::ptr::NonNull;
 
 /// A struct containing information about the location of a panic.
 ///
@@ -33,14 +35,13 @@ use crate::fmt;
 #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
 #[stable(feature = "panic_hooks", since = "1.10.0")]
 pub struct Location<'a> {
-    // Note: this filename will have exactly one nul byte at its end, but otherwise
-    // it must never contain interior nul bytes. This is relied on for the conversion
-    // to `CStr` below.
-    //
-    // The prefix of the string without the trailing nul byte will be a regular UTF8 `str`.
-    file_bytes_with_nul: &'a [u8],
+    // A raw pointer is used rather than a reference because the pointer is valid for one more byte
+    // than the length stored in this pointer; the additional byte is the NUL-terminator used by
+    // `Location::file_with_nul`.
+    filename: NonNull<str>,
     line: u32,
     col: u32,
+    _filename: PhantomData<&'a str>,
 }
 
 #[stable(feature = "panic_hooks", since = "1.10.0")]
@@ -143,10 +144,8 @@ impl<'a> Location<'a> {
     #[stable(feature = "panic_hooks", since = "1.10.0")]
     #[rustc_const_stable(feature = "const_location_fields", since = "1.79.0")]
     pub const fn file(&self) -> &str {
-        let str_len = self.file_bytes_with_nul.len() - 1;
-        // SAFETY: `file_bytes_with_nul` without the trailing nul byte is guaranteed to be
-        // valid UTF8.
-        unsafe { crate::str::from_raw_parts(self.file_bytes_with_nul.as_ptr(), str_len) }
+        // SAFETY: The filename is valid.
+        unsafe { self.filename.as_ref() }
     }
 
     /// Returns the name of the source file as a nul-terminated `CStr`.
@@ -157,9 +156,17 @@ impl<'a> Location<'a> {
     #[unstable(feature = "file_with_nul", issue = "141727")]
     #[inline]
     pub const fn file_with_nul(&self) -> &CStr {
-        // SAFETY: `file_bytes_with_nul` is guaranteed to have a trailing nul byte and no
-        // interior nul bytes.
-        unsafe { CStr::from_bytes_with_nul_unchecked(self.file_bytes_with_nul) }
+        let filename = self.filename.as_ptr();
+
+        // SAFETY: The filename is valid for `filename_len+1` bytes, so this addition can't
+        // overflow.
+        let cstr_len = unsafe { crate::mem::size_of_val_raw(filename).unchecked_add(1) };
+
+        // SAFETY: The filename is valid for `filename_len+1` bytes.
+        let slice = unsafe { crate::slice::from_raw_parts(filename.cast(), cstr_len) };
+
+        // SAFETY: The filename is guaranteed to have a trailing nul byte and no interior nul bytes.
+        unsafe { CStr::from_bytes_with_nul_unchecked(slice) }
     }
 
     /// Returns the line number from which the panic originated.
@@ -220,3 +227,8 @@ impl fmt::Display for Location<'_> {
         write!(formatter, "{}:{}:{}", self.file(), self.line, self.col)
     }
 }
+
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+unsafe impl Send for Location<'_> {}
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+unsafe impl Sync for Location<'_> {}