Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c360e21

Browse files
committed
Auto merge of #135054 - cramertj:file-cstr, r=m-ou-se
Add Location::file_with_nul This is useful for C/C++ APIs which expect the const char* returned from __FILE__ or std::source_location::file_name. ACP: rust-lang/libs-team#466 Tracking issue: #141727
2 parents 425e142 + b541f93 commit c360e21

File tree

3 files changed

+63
-24
lines changed

3 files changed

+63
-24
lines changed

‎compiler/rustc_const_eval/src/util/caller_location.rs‎

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,20 @@ fn alloc_caller_location<'tcx>(
1515
line: u32,
1616
col: u32,
1717
) -> MPlaceTy<'tcx> {
18+
// Ensure that the filename itself does not contain nul bytes.
19+
// This isn't possible via POSIX or Windows, but we should ensure no one
20+
// ever does such a thing.
21+
assert!(!filename.as_str().as_bytes().contains(&0));
22+
1823
let loc_details = ecx.tcx.sess.opts.unstable_opts.location_detail;
19-
// This can fail if rustc runs out of memory right here. Trying to emit an error would be
20-
// pointless, since that would require allocating more memory than these short strings.
21-
let file = if loc_details.file {
22-
ecx.allocate_str_dedup(filename.as_str()).unwrap()
23-
} else {
24-
ecx.allocate_str_dedup("<redacted>").unwrap()
24+
let file_wide_ptr = {
25+
let filename = if loc_details.file { filename.as_str() } else { "<redacted>" };
26+
let filename_with_nul = filename.to_owned() + "0円";
27+
// This can fail if rustc runs out of memory right here. Trying to emit an error would be
28+
// pointless, since that would require allocating more memory than these short strings.
29+
let file_ptr = ecx.allocate_bytes_dedup(filename_with_nul.as_bytes()).unwrap();
30+
Immediate::new_slice(file_ptr.into(), filename_with_nul.len().try_into().unwrap(), ecx)
2531
};
26-
let file = file.map_provenance(CtfeProvenance::as_immutable);
2732
let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
2833
let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
2934

@@ -36,7 +41,7 @@ fn alloc_caller_location<'tcx>(
3641
let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
3742

3843
// Initialize fields.
39-
ecx.write_immediate(file.to_ref(ecx), &ecx.project_field(&location, 0).unwrap())
44+
ecx.write_immediate(file_wide_ptr, &ecx.project_field(&location, 0).unwrap())
4045
.expect("writing to memory we just allocated cannot fail");
4146
ecx.write_scalar(line, &ecx.project_field(&location, 1).unwrap())
4247
.expect("writing to memory we just allocated cannot fail");

‎library/core/src/panic/location.rs‎

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::ffi::CStr;
12
use crate::fmt;
23

34
/// A struct containing information about the location of a panic.
@@ -32,7 +33,12 @@ use crate::fmt;
3233
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
3334
#[stable(feature = "panic_hooks", since = "1.10.0")]
3435
pub struct Location<'a> {
35-
file: &'a str,
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],
3642
line: u32,
3743
col: u32,
3844
}
@@ -125,9 +131,24 @@ impl<'a> Location<'a> {
125131
#[must_use]
126132
#[stable(feature = "panic_hooks", since = "1.10.0")]
127133
#[rustc_const_stable(feature = "const_location_fields", since = "1.79.0")]
128-
#[inline]
129134
pub const fn file(&self) -> &str {
130-
self.file
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) }
139+
}
140+
141+
/// Returns the name of the source file as a nul-terminated `CStr`.
142+
///
143+
/// This is useful for interop with APIs that expect C/C++ `__FILE__` or
144+
/// `std::source_location::file_name`, both of which return a nul-terminated `const char*`.
145+
#[must_use]
146+
#[unstable(feature = "file_with_nul", issue = "141727")]
147+
#[inline]
148+
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) }
131152
}
132153

133154
/// Returns the line number from which the panic originated.
@@ -181,22 +202,10 @@ impl<'a> Location<'a> {
181202
}
182203
}
183204

184-
#[unstable(
185-
feature = "panic_internals",
186-
reason = "internal details of the implementation of the `panic!` and related macros",
187-
issue = "none"
188-
)]
189-
impl<'a> Location<'a> {
190-
#[doc(hidden)]
191-
pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
192-
Location { file, line, col }
193-
}
194-
}
195-
196205
#[stable(feature = "panic_hook_display", since = "1.26.0")]
197206
impl fmt::Display for Location<'_> {
198207
#[inline]
199208
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
200-
write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
209+
write!(formatter, "{}:{}:{}", self.file(), self.line, self.col)
201210
}
202211
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//@ run-pass
2+
#![feature(file_with_nul)]
3+
4+
#[track_caller]
5+
const fn assert_file_has_trailing_zero() {
6+
let caller = core::panic::Location::caller();
7+
let file_str = caller.file();
8+
let file_with_nul = caller.file_with_nul();
9+
if file_str.len() != file_with_nul.count_bytes() {
10+
panic!("mismatched lengths");
11+
}
12+
let trailing_byte: core::ffi::c_char = unsafe {
13+
*file_with_nul.as_ptr().offset(file_with_nul.count_bytes() as _)
14+
};
15+
if trailing_byte != 0 {
16+
panic!("trailing byte was nonzero")
17+
}
18+
}
19+
20+
#[allow(dead_code)]
21+
const _: () = assert_file_has_trailing_zero();
22+
23+
fn main() {
24+
assert_file_has_trailing_zero();
25+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /