-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Null terminate core::panic::Location
file strings
#117431
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ use rustc_middle::mir; | |
use rustc_middle::ty::layout::LayoutOf; | ||
use rustc_middle::ty::{self, TyCtxt}; | ||
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; | ||
use rustc_target::abi::Align; | ||
use rustc_type_ir::Mutability; | ||
|
||
use crate::const_eval::{mk_eval_cx, CanAccessStatics, CompileTimeEvalContext}; | ||
|
@@ -19,13 +20,23 @@ fn alloc_caller_location<'mir, 'tcx>( | |
// 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 = if loc_details.file { | ||
ecx.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not).unwrap() | ||
let mut bytes = filename.as_str().to_owned().into_bytes(); | ||
bytes.push(0); | ||
ecx.allocate_bytes_ptr(&bytes, Align::ONE, MemoryKind::CallerLocation, Mutability::Not) | ||
.unwrap() | ||
} else { | ||
// FIXME: This creates a new allocation each time. It might be preferable to | ||
// perform this allocation only once, and re-use the `MPlaceTy`. | ||
// See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398 | ||
ecx.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not).unwrap() | ||
ecx.allocate_bytes_ptr( | ||
b"<redacted>\0", | ||
Align::ONE, | ||
MemoryKind::CallerLocation, | ||
Mutability::Not, | ||
) | ||
.unwrap() | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can avoid the interning change by instead manually interning the inner allocation with the string here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that sounds good. how exactly do i do the interning? is it the let alloc = tcx.mk_const_alloc(alloc);
tcx.set_alloc_id_memory(alloc_id, alloc); part? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah that's the core thing. We have some helpers in |
||
let file = Scalar::from_pointer(file, 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) }; | ||
|
||
|
@@ -38,11 +49,11 @@ fn alloc_caller_location<'mir, 'tcx>( | |
let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap(); | ||
|
||
// Initialize fields. | ||
ecx.write_immediate(file.to_ref(ecx), &ecx.project_field(&location, 0).unwrap()) | ||
ecx.write_scalar(file, &ecx.project_field(&location, 0).unwrap()) | ||
.expect("writing to memory we just allocated cannot fail"); | ||
ecx.write_scalar(line, &ecx.project_field(&location, 1).unwrap()) | ||
ecx.write_scalar(line, &ecx.project_field(&location, 2).unwrap()) | ||
.expect("writing to memory we just allocated cannot fail"); | ||
ecx.write_scalar(col, &ecx.project_field(&location, 2).unwrap()) | ||
ecx.write_scalar(col, &ecx.project_field(&location, 3).unwrap()) | ||
.expect("writing to memory we just allocated cannot fail"); | ||
|
||
location | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
use crate::fmt; | ||
#[cfg(not(bootstrap))] | ||
use crate::{ffi::CStr, marker::PhantomData}; | ||
|
||
/// A struct containing information about the location of a panic. | ||
/// | ||
|
@@ -28,8 +30,21 @@ use crate::fmt; | |
/// Files are compared as strings, not `Path`, which could be unexpected. | ||
/// See [`Location::file`]'s documentation for more discussion. | ||
#[lang = "panic_location"] | ||
#[derive(Copy, Clone)] | ||
#[stable(feature = "panic_hooks", since = "1.10.0")] | ||
#[cfg(not(bootstrap))] | ||
pub struct Location<'a> { | ||
file: *const (), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needs an explicit |
||
_file_actual: PhantomData<&'a CStr>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know either - but it's stable :( |
||
line: u32, | ||
col: u32, | ||
} | ||
|
||
/// Location | ||
#[lang = "panic_location"] | ||
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] | ||
#[stable(feature = "panic_hooks", since = "1.10.0")] | ||
#[cfg(bootstrap)] | ||
pub struct Location<'a> { | ||
file: &'a str, | ||
line: u32, | ||
|
@@ -126,7 +141,17 @@ impl<'a> Location<'a> { | |
#[rustc_const_unstable(feature = "const_location_fields", issue = "102911")] | ||
#[inline] | ||
pub const fn file(&self) -> &str { | ||
self.file | ||
#[cfg(bootstrap)] | ||
{ | ||
self.file | ||
} | ||
#[cfg(not(bootstrap))] | ||
// SAFETY: Codegen ensures that there is a null byte. | ||
unsafe { | ||
let cstr = CStr::from_ptr(self.file as _); | ||
let len = cstr.count_bytes(); | ||
crate::str::from_utf8_unchecked(crate::slice::from_raw_parts(self.file as _, len)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This makes calls here and to related (Hash, Debug, PartialEq, etc.) functions much more expensive. I guess we may not be able to do much better... but I think the binary size vs. possibly slower binaries that are keeping these locations around (e.g., HashMap) isn't as obvious. It's possible we could make this near equivalent by avoiding the upfront 0-byte search internally. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another option would be doing a varint length prefix instead of a nul terminator. For short paths it would only be 1 byte so the same size as a nul terminator. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these ever on the hot path? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Logging, maybe? |
||
} | ||
} | ||
|
||
/// Returns the line number from which the panic originated. | ||
|
@@ -180,21 +205,63 @@ impl<'a> Location<'a> { | |
} | ||
} | ||
|
||
#[unstable( | ||
feature = "panic_internals", | ||
reason = "internal details of the implementation of the `panic!` and related macros", | ||
issue = "none" | ||
)] | ||
impl<'a> Location<'a> { | ||
#[doc(hidden)] | ||
pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self { | ||
Location { file, line, col } | ||
// cfg(not(bootstrap)) NOTE: inline this module when bumping, it's only here to group the cfg | ||
#[cfg(not(bootstrap))] | ||
mod location_impls { | ||
use super::Location; | ||
|
||
impl Location<'_> { | ||
fn to_parts(&self) -> (&str, u32, u32) { | ||
(self.file(), self.line, self.col) | ||
} | ||
} | ||
|
||
#[stable(feature = "panic_hooks", since = "1.10.0")] | ||
impl crate::fmt::Debug for Location<'_> { | ||
fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { | ||
f.debug_struct("Location") | ||
.field("file", &self.file()) | ||
.field("line", &self.line) | ||
.field("col", &self.col) | ||
.finish() | ||
} | ||
} | ||
|
||
#[stable(feature = "panic_hooks", since = "1.10.0")] | ||
impl crate::cmp::PartialEq for Location<'_> { | ||
fn eq(&self, other: &Self) -> bool { | ||
self.to_parts() == other.to_parts() | ||
} | ||
} | ||
|
||
#[stable(feature = "panic_hooks", since = "1.10.0")] | ||
impl crate::cmp::Eq for Location<'_> {} | ||
|
||
#[stable(feature = "panic_hooks", since = "1.10.0")] | ||
impl crate::cmp::PartialOrd for Location<'_> { | ||
fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> { | ||
self.to_parts().partial_cmp(&other.to_parts()) | ||
} | ||
} | ||
|
||
#[stable(feature = "panic_hooks", since = "1.10.0")] | ||
impl crate::cmp::Ord for Location<'_> { | ||
fn cmp(&self, other: &Self) -> crate::cmp::Ordering { | ||
self.to_parts().cmp(&other.to_parts()) | ||
} | ||
} | ||
|
||
#[stable(feature = "panic_hooks", since = "1.10.0")] | ||
impl crate::hash::Hash for Location<'_> { | ||
fn hash<H: crate::hash::Hasher>(&self, state: &mut H) { | ||
self.to_parts().hash(state) | ||
} | ||
} | ||
} | ||
|
||
#[stable(feature = "panic_hook_display", since = "1.26.0")] | ||
impl fmt::Display for Location<'_> { | ||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(formatter, "{}:{}:{}", self.file, self.line, self.col) | ||
write!(formatter, "{}:{}:{}", self.file(), self.line, self.col) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uh, this is bad. That code is already terrible and my attempts at cleaning it up in #116745 are kind of stuck. I really don't like adding more complications here.