Skip to content

Commit cfed78e

Browse files
committed
Do not include NUL-terminator in computed length
1 parent fe5c95d commit cfed78e

File tree

2 files changed

+22
-20
lines changed

2 files changed

+22
-20
lines changed

compiler/rustc_const_eval/src/util/caller_location.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@ fn alloc_caller_location<'tcx>(
2222
assert!(!filename.as_str().as_bytes().contains(&0));
2323

2424
let loc_details = ecx.tcx.sess.opts.unstable_opts.location_detail;
25-
let file_wide_ptr = {
25+
let filename = {
2626
let filename = if loc_details.file { filename.as_str() } else { "<redacted>" };
2727
let filename_with_nul = filename.to_owned() + "\0";
2828
// This can fail if rustc runs out of memory right here. Trying to emit an error would be
2929
// pointless, since that would require allocating more memory than these short strings.
3030
let file_ptr = ecx.allocate_bytes_dedup(filename_with_nul.as_bytes()).unwrap();
31-
Immediate::new_slice(file_ptr.into(), filename_with_nul.len().try_into().unwrap(), ecx)
31+
let file_len = u64::try_from(filename.len()).unwrap();
32+
Immediate::new_slice(file_ptr.into(), file_len, ecx)
3233
};
3334
let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
3435
let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
@@ -42,11 +43,8 @@ fn alloc_caller_location<'tcx>(
4243
let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
4344

4445
// Initialize fields.
45-
ecx.write_immediate(
46-
file_wide_ptr,
47-
&ecx.project_field(&location, FieldIdx::from_u32(0)).unwrap(),
48-
)
49-
.expect("writing to memory we just allocated cannot fail");
46+
ecx.write_immediate(filename, &ecx.project_field(&location, FieldIdx::from_u32(0)).unwrap())
47+
.expect("writing to memory we just allocated cannot fail");
5048
ecx.write_scalar(line, &ecx.project_field(&location, FieldIdx::from_u32(1)).unwrap())
5149
.expect("writing to memory we just allocated cannot fail");
5250
ecx.write_scalar(col, &ecx.project_field(&location, FieldIdx::from_u32(2)).unwrap())

library/core/src/panic/location.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::ffi::CStr;
22
use crate::fmt;
3+
use crate::marker::PhantomData;
34

45
/// A struct containing information about the location of a panic.
56
///
@@ -33,14 +34,13 @@ use crate::fmt;
3334
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
3435
#[stable(feature = "panic_hooks", since = "1.10.0")]
3536
pub struct Location<'a> {
36-
// Note: this filename will have exactly one nul byte at its end, but otherwise
37-
// it must never contain interior nul bytes. This is relied on for the conversion
38-
// to `CStr` below.
39-
//
40-
// The prefix of the string without the trailing nul byte will be a regular UTF8 `str`.
41-
file_bytes_with_nul: &'a [u8],
37+
// A raw pointer is used rather than a reference because the pointer is valid for one more byte
38+
// than the length stored in this pointer; the additional byte is the NUL-terminator used by
39+
// `Location::file_with_nul`.
40+
filename: *const str,
4241
line: u32,
4342
col: u32,
43+
_filename: PhantomData<&'a str>,
4444
}
4545

4646
impl<'a> Location<'a> {
@@ -132,10 +132,8 @@ impl<'a> Location<'a> {
132132
#[stable(feature = "panic_hooks", since = "1.10.0")]
133133
#[rustc_const_stable(feature = "const_location_fields", since = "1.79.0")]
134134
pub const fn file(&self) -> &str {
135-
let str_len = self.file_bytes_with_nul.len() - 1;
136-
// SAFETY: `file_bytes_with_nul` without the trailing nul byte is guaranteed to be
137-
// valid UTF8.
138-
unsafe { crate::str::from_raw_parts(self.file_bytes_with_nul.as_ptr(), str_len) }
135+
// SAFETY: The filename is valid.
136+
unsafe { &*self.filename }
139137
}
140138

141139
/// Returns the name of the source file as a nul-terminated `CStr`.
@@ -146,9 +144,15 @@ impl<'a> Location<'a> {
146144
#[unstable(feature = "file_with_nul", issue = "141727")]
147145
#[inline]
148146
pub const fn file_with_nul(&self) -> &CStr {
149-
// SAFETY: `file_bytes_with_nul` is guaranteed to have a trailing nul byte and no
150-
// interior nul bytes.
151-
unsafe { CStr::from_bytes_with_nul_unchecked(self.file_bytes_with_nul) }
147+
// SAFETY: The filename is valid for `filename_len+1` bytes, so this addition can't
148+
// overflow.
149+
let cstr_len = unsafe { crate::mem::size_of_val_raw(self.filename).unchecked_add(1) };
150+
151+
// SAFETY: The filename is valid for `filename_len+1` bytes.
152+
let slice = unsafe { crate::slice::from_raw_parts(self.filename as *const _, cstr_len) };
153+
154+
// SAFETY: The filename is guaranteed to have a trailing nul byte and no interior nul bytes.
155+
unsafe { CStr::from_bytes_with_nul_unchecked(slice) }
152156
}
153157

154158
/// Returns the line number from which the panic originated.

0 commit comments

Comments
 (0)