mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 07:22:42 +00:00
Auto merge of #74876 - oli-obk:lumberjack_disable, r=RalfJung
Replace all uses of `log::log_enabled` with `Debug` printers cc @RalfJung this touches a bunch of logging in the miri engine. There are some visual changes, mainly that in several cases we stop prepending lines with the module path and just have a newline.
This commit is contained in:
commit
1799d31847
@ -2,7 +2,7 @@ use crate::interface::{Compiler, Result};
|
||||
use crate::proc_macro_decls;
|
||||
use crate::util;
|
||||
|
||||
use log::{info, log_enabled, warn};
|
||||
use log::{info, warn};
|
||||
use once_cell::sync::Lazy;
|
||||
use rustc_ast::mut_visit::MutVisitor;
|
||||
use rustc_ast::{self, ast, visit};
|
||||
@ -1015,10 +1015,7 @@ pub fn start_codegen<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
outputs: &OutputFilenames,
|
||||
) -> Box<dyn Any> {
|
||||
if log_enabled!(::log::Level::Info) {
|
||||
println!("Pre-codegen");
|
||||
tcx.print_debug_stats();
|
||||
}
|
||||
info!("Pre-codegen\n{:?}", tcx.debug_stats());
|
||||
|
||||
let (metadata, need_metadata_module) = encode_and_write_metadata(tcx, outputs);
|
||||
|
||||
@ -1026,10 +1023,7 @@ pub fn start_codegen<'tcx>(
|
||||
codegen_backend.codegen_crate(tcx, metadata, need_metadata_module)
|
||||
});
|
||||
|
||||
if log_enabled!(::log::Level::Info) {
|
||||
println!("Post-codegen");
|
||||
tcx.print_debug_stats();
|
||||
}
|
||||
info!("Post-codegen\n{:?}", tcx.debug_stats());
|
||||
|
||||
if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
|
||||
if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, outputs) {
|
||||
|
@ -26,7 +26,7 @@ use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::spec::{PanicStrategy, TargetTriple};
|
||||
|
||||
use log::{debug, info, log_enabled};
|
||||
use log::{debug, info};
|
||||
use proc_macro::bridge::client::ProcMacro;
|
||||
use std::path::Path;
|
||||
use std::{cmp, env, fs};
|
||||
@ -82,24 +82,36 @@ impl std::ops::Deref for CrateMetadataRef<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn dump_crates(cstore: &CStore) {
|
||||
info!("resolved crates:");
|
||||
cstore.iter_crate_data(|cnum, data| {
|
||||
info!(" name: {}", data.name());
|
||||
info!(" cnum: {}", cnum);
|
||||
info!(" hash: {}", data.hash());
|
||||
info!(" reqd: {:?}", data.dep_kind());
|
||||
let CrateSource { dylib, rlib, rmeta } = data.source();
|
||||
if let Some(dylib) = dylib {
|
||||
info!(" dylib: {}", dylib.0.display());
|
||||
}
|
||||
if let Some(rlib) = rlib {
|
||||
info!(" rlib: {}", rlib.0.display());
|
||||
}
|
||||
if let Some(rmeta) = rmeta {
|
||||
info!(" rmeta: {}", rmeta.0.display());
|
||||
}
|
||||
});
|
||||
struct CrateDump<'a>(&'a CStore);
|
||||
|
||||
impl<'a> std::fmt::Debug for CrateDump<'a> {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(fmt, "resolved crates:")?;
|
||||
// `iter_crate_data` does not allow returning values. Thus we use a mutable variable here
|
||||
// that aggregates the value (and any errors that could happen).
|
||||
let mut res = Ok(());
|
||||
self.0.iter_crate_data(|cnum, data| {
|
||||
res = res.and(
|
||||
try {
|
||||
writeln!(fmt, " name: {}", data.name())?;
|
||||
writeln!(fmt, " cnum: {}", cnum)?;
|
||||
writeln!(fmt, " hash: {}", data.hash())?;
|
||||
writeln!(fmt, " reqd: {:?}", data.dep_kind())?;
|
||||
let CrateSource { dylib, rlib, rmeta } = data.source();
|
||||
if let Some(dylib) = dylib {
|
||||
writeln!(fmt, " dylib: {}", dylib.0.display())?;
|
||||
}
|
||||
if let Some(rlib) = rlib {
|
||||
writeln!(fmt, " rlib: {}", rlib.0.display())?;
|
||||
}
|
||||
if let Some(rmeta) = rmeta {
|
||||
writeln!(fmt, " rmeta: {}", rmeta.0.display())?;
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl CStore {
|
||||
@ -864,9 +876,7 @@ impl<'a> CrateLoader<'a> {
|
||||
self.inject_allocator_crate(krate);
|
||||
self.inject_panic_runtime(krate);
|
||||
|
||||
if log_enabled!(log::Level::Info) {
|
||||
dump_crates(&self.cstore);
|
||||
}
|
||||
info!("{:?}", CrateDump(&self.cstore));
|
||||
|
||||
self.report_unused_deps(krate);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(never_type)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
|
@ -1831,7 +1831,7 @@ pub mod tls {
|
||||
}
|
||||
|
||||
macro_rules! sty_debug_print {
|
||||
($ctxt: expr, $($variant: ident),*) => {{
|
||||
($fmt: expr, $ctxt: expr, $($variant: ident),*) => {{
|
||||
// Curious inner module to allow variant names to be used as
|
||||
// variable names.
|
||||
#[allow(non_snake_case)]
|
||||
@ -1848,7 +1848,7 @@ macro_rules! sty_debug_print {
|
||||
all_infer: usize,
|
||||
}
|
||||
|
||||
pub fn go(tcx: TyCtxt<'_>) {
|
||||
pub fn go(fmt: &mut std::fmt::Formatter<'_>, tcx: TyCtxt<'_>) -> std::fmt::Result {
|
||||
let mut total = DebugStat {
|
||||
total: 0,
|
||||
lt_infer: 0,
|
||||
@ -1878,8 +1878,8 @@ macro_rules! sty_debug_print {
|
||||
if ct { total.ct_infer += 1; variant.ct_infer += 1 }
|
||||
if lt && ty && ct { total.all_infer += 1; variant.all_infer += 1 }
|
||||
}
|
||||
println!("Ty interner total ty lt ct all");
|
||||
$(println!(" {:18}: {uses:6} {usespc:4.1}%, \
|
||||
writeln!(fmt, "Ty interner total ty lt ct all")?;
|
||||
$(writeln!(fmt, " {:18}: {uses:6} {usespc:4.1}%, \
|
||||
{ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%",
|
||||
stringify!($variant),
|
||||
uses = $variant.total,
|
||||
@ -1887,9 +1887,9 @@ macro_rules! sty_debug_print {
|
||||
ty = $variant.ty_infer as f64 * 100.0 / total.total as f64,
|
||||
lt = $variant.lt_infer as f64 * 100.0 / total.total as f64,
|
||||
ct = $variant.ct_infer as f64 * 100.0 / total.total as f64,
|
||||
all = $variant.all_infer as f64 * 100.0 / total.total as f64);
|
||||
all = $variant.all_infer as f64 * 100.0 / total.total as f64)?;
|
||||
)*
|
||||
println!(" total {uses:6} \
|
||||
writeln!(fmt, " total {uses:6} \
|
||||
{ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%",
|
||||
uses = total.total,
|
||||
ty = total.ty_infer as f64 * 100.0 / total.total as f64,
|
||||
@ -1899,41 +1899,56 @@ macro_rules! sty_debug_print {
|
||||
}
|
||||
}
|
||||
|
||||
inner::go($ctxt)
|
||||
inner::go($fmt, $ctxt)
|
||||
}}
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
pub fn print_debug_stats(self) {
|
||||
sty_debug_print!(
|
||||
self,
|
||||
Adt,
|
||||
Array,
|
||||
Slice,
|
||||
RawPtr,
|
||||
Ref,
|
||||
FnDef,
|
||||
FnPtr,
|
||||
Placeholder,
|
||||
Generator,
|
||||
GeneratorWitness,
|
||||
Dynamic,
|
||||
Closure,
|
||||
Tuple,
|
||||
Bound,
|
||||
Param,
|
||||
Infer,
|
||||
Projection,
|
||||
Opaque,
|
||||
Foreign
|
||||
);
|
||||
pub fn debug_stats(self) -> impl std::fmt::Debug + 'tcx {
|
||||
struct DebugStats<'tcx>(TyCtxt<'tcx>);
|
||||
|
||||
println!("InternalSubsts interner: #{}", self.interners.substs.len());
|
||||
println!("Region interner: #{}", self.interners.region.len());
|
||||
println!("Stability interner: #{}", self.stability_interner.len());
|
||||
println!("Const Stability interner: #{}", self.const_stability_interner.len());
|
||||
println!("Allocation interner: #{}", self.allocation_interner.len());
|
||||
println!("Layout interner: #{}", self.layout_interner.len());
|
||||
impl std::fmt::Debug for DebugStats<'tcx> {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
sty_debug_print!(
|
||||
fmt,
|
||||
self.0,
|
||||
Adt,
|
||||
Array,
|
||||
Slice,
|
||||
RawPtr,
|
||||
Ref,
|
||||
FnDef,
|
||||
FnPtr,
|
||||
Placeholder,
|
||||
Generator,
|
||||
GeneratorWitness,
|
||||
Dynamic,
|
||||
Closure,
|
||||
Tuple,
|
||||
Bound,
|
||||
Param,
|
||||
Infer,
|
||||
Projection,
|
||||
Opaque,
|
||||
Foreign
|
||||
)?;
|
||||
|
||||
writeln!(fmt, "InternalSubsts interner: #{}", self.0.interners.substs.len())?;
|
||||
writeln!(fmt, "Region interner: #{}", self.0.interners.region.len())?;
|
||||
writeln!(fmt, "Stability interner: #{}", self.0.stability_interner.len())?;
|
||||
writeln!(
|
||||
fmt,
|
||||
"Const Stability interner: #{}",
|
||||
self.0.const_stability_interner.len()
|
||||
)?;
|
||||
writeln!(fmt, "Allocation interner: #{}", self.0.allocation_interner.len())?;
|
||||
writeln!(fmt, "Layout interner: #{}", self.0.layout_interner.len())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
DebugStats(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
|
||||
self.copy_op(place.into(), dest)?;
|
||||
|
||||
self.return_to_block(ret.map(|r| r.1))?;
|
||||
self.dump_place(*dest);
|
||||
trace!("{:?}", self.dump_place(*dest));
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
use std::cell::Cell;
|
||||
use std::fmt::Write;
|
||||
use std::mem;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
@ -728,7 +727,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
if let Some(return_place) = frame.return_place {
|
||||
let op = self.access_local(&frame, mir::RETURN_PLACE, None)?;
|
||||
self.copy_op_transmute(op, return_place)?;
|
||||
self.dump_place(*return_place);
|
||||
trace!("{:?}", self.dump_place(*return_place));
|
||||
} else {
|
||||
throw_ub!(Unreachable);
|
||||
}
|
||||
@ -823,9 +822,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// All locals have a backing allocation, even if the allocation is empty
|
||||
// due to the local having ZST type.
|
||||
let ptr = ptr.assert_ptr();
|
||||
if log_enabled!(::log::Level::Trace) {
|
||||
self.memory.dump_alloc(ptr.alloc_id);
|
||||
}
|
||||
trace!("{:?}", self.memory.dump_alloc(ptr.alloc_id));
|
||||
self.memory.deallocate_local(ptr)?;
|
||||
};
|
||||
Ok(())
|
||||
@ -881,69 +878,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
self.raw_const_to_mplace(val)
|
||||
}
|
||||
|
||||
pub fn dump_place(&self, place: Place<M::PointerTag>) {
|
||||
// Debug output
|
||||
if !log_enabled!(::log::Level::Trace) {
|
||||
return;
|
||||
}
|
||||
match place {
|
||||
Place::Local { frame, local } => {
|
||||
let mut allocs = Vec::new();
|
||||
let mut msg = format!("{:?}", local);
|
||||
if frame != self.frame_idx() {
|
||||
write!(msg, " ({} frames up)", self.frame_idx() - frame).unwrap();
|
||||
}
|
||||
write!(msg, ":").unwrap();
|
||||
|
||||
match self.stack()[frame].locals[local].value {
|
||||
LocalValue::Dead => write!(msg, " is dead").unwrap(),
|
||||
LocalValue::Uninitialized => write!(msg, " is uninitialized").unwrap(),
|
||||
LocalValue::Live(Operand::Indirect(mplace)) => match mplace.ptr {
|
||||
Scalar::Ptr(ptr) => {
|
||||
write!(
|
||||
msg,
|
||||
" by align({}){} ref:",
|
||||
mplace.align.bytes(),
|
||||
match mplace.meta {
|
||||
MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta),
|
||||
MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(),
|
||||
}
|
||||
)
|
||||
.unwrap();
|
||||
allocs.push(ptr.alloc_id);
|
||||
}
|
||||
ptr => write!(msg, " by integral ref: {:?}", ptr).unwrap(),
|
||||
},
|
||||
LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
|
||||
write!(msg, " {:?}", val).unwrap();
|
||||
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val {
|
||||
allocs.push(ptr.alloc_id);
|
||||
}
|
||||
}
|
||||
LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
|
||||
write!(msg, " ({:?}, {:?})", val1, val2).unwrap();
|
||||
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val1 {
|
||||
allocs.push(ptr.alloc_id);
|
||||
}
|
||||
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val2 {
|
||||
allocs.push(ptr.alloc_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trace!("{}", msg);
|
||||
self.memory.dump_allocs(allocs);
|
||||
}
|
||||
Place::Ptr(mplace) => match mplace.ptr {
|
||||
Scalar::Ptr(ptr) => {
|
||||
trace!("by align({}) ref:", mplace.align.bytes());
|
||||
self.memory.dump_alloc(ptr.alloc_id);
|
||||
}
|
||||
ptr => trace!(" integral by ref: {:?}", ptr),
|
||||
},
|
||||
}
|
||||
#[must_use]
|
||||
pub fn dump_place(&'a self, place: Place<M::PointerTag>) -> PlacePrinter<'a, 'mir, 'tcx, M> {
|
||||
PlacePrinter { ecx: self, place }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>> {
|
||||
let mut frames = Vec::new();
|
||||
for frame in self.stack().iter().rev() {
|
||||
@ -963,6 +903,76 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// Helper struct for the `dump_place` function.
|
||||
pub struct PlacePrinter<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
|
||||
ecx: &'a InterpCx<'mir, 'tcx, M>,
|
||||
place: Place<M::PointerTag>,
|
||||
}
|
||||
|
||||
impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug
|
||||
for PlacePrinter<'a, 'mir, 'tcx, M>
|
||||
{
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.place {
|
||||
Place::Local { frame, local } => {
|
||||
let mut allocs = Vec::new();
|
||||
write!(fmt, "{:?}", local)?;
|
||||
if frame != self.ecx.frame_idx() {
|
||||
write!(fmt, " ({} frames up)", self.ecx.frame_idx() - frame)?;
|
||||
}
|
||||
write!(fmt, ":")?;
|
||||
|
||||
match self.ecx.stack()[frame].locals[local].value {
|
||||
LocalValue::Dead => write!(fmt, " is dead")?,
|
||||
LocalValue::Uninitialized => write!(fmt, " is uninitialized")?,
|
||||
LocalValue::Live(Operand::Indirect(mplace)) => match mplace.ptr {
|
||||
Scalar::Ptr(ptr) => {
|
||||
write!(
|
||||
fmt,
|
||||
" by align({}){} ref:",
|
||||
mplace.align.bytes(),
|
||||
match mplace.meta {
|
||||
MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta),
|
||||
MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(),
|
||||
}
|
||||
)?;
|
||||
allocs.push(ptr.alloc_id);
|
||||
}
|
||||
ptr => write!(fmt, " by integral ref: {:?}", ptr)?,
|
||||
},
|
||||
LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
|
||||
write!(fmt, " {:?}", val)?;
|
||||
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val {
|
||||
allocs.push(ptr.alloc_id);
|
||||
}
|
||||
}
|
||||
LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
|
||||
write!(fmt, " ({:?}, {:?})", val1, val2)?;
|
||||
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val1 {
|
||||
allocs.push(ptr.alloc_id);
|
||||
}
|
||||
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val2 {
|
||||
allocs.push(ptr.alloc_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
write!(fmt, ": {:?}", self.ecx.memory.dump_allocs(allocs))
|
||||
}
|
||||
Place::Ptr(mplace) => match mplace.ptr {
|
||||
Scalar::Ptr(ptr) => write!(
|
||||
fmt,
|
||||
"by align({}) ref: {:?}",
|
||||
mplace.align.bytes(),
|
||||
self.ecx.memory.dump_alloc(ptr.alloc_id)
|
||||
),
|
||||
ptr => write!(fmt, " integral by ref: {:?}", ptr),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, 'mir, 'tcx, Tag, Extra> HashStable<StableHashingContext<'ctx>>
|
||||
for Frame<'mir, 'tcx, Tag, Extra>
|
||||
where
|
||||
|
@ -430,7 +430,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
_ => return Ok(false),
|
||||
}
|
||||
|
||||
self.dump_place(*dest);
|
||||
trace!("{:?}", self.dump_place(*dest));
|
||||
self.go_to_block(ret);
|
||||
Ok(true)
|
||||
}
|
||||
|
@ -667,69 +667,20 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Print an allocation and all allocations it points to, recursively.
|
||||
/// This prints directly to stderr, ignoring RUSTC_LOG! It is up to the caller to
|
||||
/// control for this.
|
||||
pub fn dump_alloc(&self, id: AllocId) {
|
||||
self.dump_allocs(vec![id]);
|
||||
/// Create a lazy debug printer that prints the given allocation and all allocations it points
|
||||
/// to, recursively.
|
||||
#[must_use]
|
||||
pub fn dump_alloc<'a>(&'a self, id: AllocId) -> DumpAllocs<'a, 'mir, 'tcx, M> {
|
||||
self.dump_allocs(vec![id])
|
||||
}
|
||||
|
||||
/// Print a list of allocations and all allocations they point to, recursively.
|
||||
/// This prints directly to stderr, ignoring RUSTC_LOG! It is up to the caller to
|
||||
/// control for this.
|
||||
pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) {
|
||||
// Cannot be a closure because it is generic in `Tag`, `Extra`.
|
||||
fn write_allocation_track_relocs<'tcx, Tag: Copy + fmt::Debug, Extra>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
allocs_to_print: &mut VecDeque<AllocId>,
|
||||
alloc: &Allocation<Tag, Extra>,
|
||||
) {
|
||||
for &(_, target_id) in alloc.relocations().values() {
|
||||
allocs_to_print.push_back(target_id);
|
||||
}
|
||||
pretty::write_allocation(tcx, alloc, &mut std::io::stderr()).unwrap();
|
||||
}
|
||||
|
||||
/// Create a lazy debug printer for a list of allocations and all allocations they point to,
|
||||
/// recursively.
|
||||
#[must_use]
|
||||
pub fn dump_allocs<'a>(&'a self, mut allocs: Vec<AllocId>) -> DumpAllocs<'a, 'mir, 'tcx, M> {
|
||||
allocs.sort();
|
||||
allocs.dedup();
|
||||
let mut allocs_to_print = VecDeque::from(allocs);
|
||||
// `allocs_printed` contains all allocations that we have already printed.
|
||||
let mut allocs_printed = FxHashSet::default();
|
||||
|
||||
while let Some(id) = allocs_to_print.pop_front() {
|
||||
if !allocs_printed.insert(id) {
|
||||
// Already printed, so skip this.
|
||||
continue;
|
||||
}
|
||||
|
||||
eprint!("{}", id);
|
||||
match self.alloc_map.get(id) {
|
||||
Some(&(kind, ref alloc)) => {
|
||||
// normal alloc
|
||||
eprint!(" ({}, ", kind);
|
||||
write_allocation_track_relocs(self.tcx, &mut allocs_to_print, alloc);
|
||||
}
|
||||
None => {
|
||||
// global alloc
|
||||
match self.tcx.get_global_alloc(id) {
|
||||
Some(GlobalAlloc::Memory(alloc)) => {
|
||||
eprint!(" (unchanged global, ");
|
||||
write_allocation_track_relocs(self.tcx, &mut allocs_to_print, alloc);
|
||||
}
|
||||
Some(GlobalAlloc::Function(func)) => {
|
||||
eprint!(" (fn: {})", func);
|
||||
}
|
||||
Some(GlobalAlloc::Static(did)) => {
|
||||
eprint!(" (static: {})", self.tcx.def_path_str(did));
|
||||
}
|
||||
None => {
|
||||
eprint!(" (deallocated)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
eprintln!();
|
||||
}
|
||||
DumpAllocs { mem: self, allocs }
|
||||
}
|
||||
|
||||
/// Print leaked memory. Allocations reachable from `static_roots` or a `Global` allocation
|
||||
@ -760,8 +711,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
||||
});
|
||||
let n = leaks.len();
|
||||
if n > 0 {
|
||||
eprintln!("The following memory was leaked:");
|
||||
self.dump_allocs(leaks);
|
||||
eprintln!("The following memory was leaked: {:?}", self.dump_allocs(leaks));
|
||||
}
|
||||
n
|
||||
}
|
||||
@ -772,6 +722,80 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// There's no way to use this directly, it's just a helper struct for the `dump_alloc(s)` methods.
|
||||
pub struct DumpAllocs<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
|
||||
mem: &'a Memory<'mir, 'tcx, M>,
|
||||
allocs: Vec<AllocId>,
|
||||
}
|
||||
|
||||
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, 'mir, 'tcx, M> {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// Cannot be a closure because it is generic in `Tag`, `Extra`.
|
||||
fn write_allocation_track_relocs<'tcx, Tag: Copy + fmt::Debug, Extra>(
|
||||
fmt: &mut std::fmt::Formatter<'_>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
allocs_to_print: &mut VecDeque<AllocId>,
|
||||
alloc: &Allocation<Tag, Extra>,
|
||||
) -> std::fmt::Result {
|
||||
for &(_, target_id) in alloc.relocations().values() {
|
||||
allocs_to_print.push_back(target_id);
|
||||
}
|
||||
write!(fmt, "{}", pretty::display_allocation(tcx, alloc))
|
||||
}
|
||||
|
||||
let mut allocs_to_print: VecDeque<_> = self.allocs.iter().copied().collect();
|
||||
// `allocs_printed` contains all allocations that we have already printed.
|
||||
let mut allocs_printed = FxHashSet::default();
|
||||
|
||||
while let Some(id) = allocs_to_print.pop_front() {
|
||||
if !allocs_printed.insert(id) {
|
||||
// Already printed, so skip this.
|
||||
continue;
|
||||
}
|
||||
|
||||
write!(fmt, "{}", id)?;
|
||||
match self.mem.alloc_map.get(id) {
|
||||
Some(&(kind, ref alloc)) => {
|
||||
// normal alloc
|
||||
write!(fmt, " ({}, ", kind)?;
|
||||
write_allocation_track_relocs(
|
||||
&mut *fmt,
|
||||
self.mem.tcx,
|
||||
&mut allocs_to_print,
|
||||
alloc,
|
||||
)?;
|
||||
}
|
||||
None => {
|
||||
// global alloc
|
||||
match self.mem.tcx.get_global_alloc(id) {
|
||||
Some(GlobalAlloc::Memory(alloc)) => {
|
||||
write!(fmt, " (unchanged global, ")?;
|
||||
write_allocation_track_relocs(
|
||||
&mut *fmt,
|
||||
self.mem.tcx,
|
||||
&mut allocs_to_print,
|
||||
alloc,
|
||||
)?;
|
||||
}
|
||||
Some(GlobalAlloc::Function(func)) => {
|
||||
write!(fmt, " (fn: {})", func)?;
|
||||
}
|
||||
Some(GlobalAlloc::Static(did)) => {
|
||||
write!(fmt, " (static: {})", self.mem.tcx.def_path_str(did))?;
|
||||
}
|
||||
None => {
|
||||
write!(fmt, " (deallocated)")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
writeln!(fmt)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Reading and writing.
|
||||
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
||||
/// Reads the given number of bytes from memory. Returns them as a slice.
|
||||
|
@ -648,7 +648,7 @@ where
|
||||
place_ty = self.place_projection(place_ty, &elem)?
|
||||
}
|
||||
|
||||
self.dump_place(place_ty.place);
|
||||
trace!("{:?}", self.dump_place(place_ty.place));
|
||||
// Sanity-check the type we ended up with.
|
||||
debug_assert!(mir_assign_valid_types(
|
||||
*self.tcx,
|
||||
|
@ -271,7 +271,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
}
|
||||
|
||||
self.dump_place(*dest);
|
||||
trace!("{:?}", self.dump_place(*dest));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -596,7 +596,7 @@ pub fn write_allocations<'tcx>(
|
||||
todo.push(id);
|
||||
}
|
||||
}
|
||||
write_allocation(tcx, alloc, w)
|
||||
write!(w, "{}", display_allocation(tcx, alloc))
|
||||
};
|
||||
write!(w, "\n{}", id)?;
|
||||
match tcx.get_global_alloc(id) {
|
||||
@ -648,24 +648,36 @@ pub fn write_allocations<'tcx>(
|
||||
/// After the hex dump, an ascii dump follows, replacing all unprintable characters (control
|
||||
/// characters or characters whose value is larger than 127) with a `.`
|
||||
/// This also prints relocations adequately.
|
||||
pub fn write_allocation<Tag: Copy + Debug, Extra>(
|
||||
pub fn display_allocation<Tag: Copy + Debug, Extra>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
alloc: &Allocation<Tag, Extra>,
|
||||
w: &mut dyn Write,
|
||||
) -> io::Result<()> {
|
||||
write!(w, "size: {}, align: {})", alloc.size.bytes(), alloc.align.bytes())?;
|
||||
if alloc.size == Size::ZERO {
|
||||
// We are done.
|
||||
return write!(w, " {{}}");
|
||||
}
|
||||
// Write allocation bytes.
|
||||
writeln!(w, " {{")?;
|
||||
write_allocation_bytes(tcx, alloc, w, " ")?;
|
||||
write!(w, "}}")?;
|
||||
Ok(())
|
||||
alloc: &'a Allocation<Tag, Extra>,
|
||||
) -> RenderAllocation<'a, 'tcx, Tag, Extra> {
|
||||
RenderAllocation { tcx, alloc }
|
||||
}
|
||||
|
||||
fn write_allocation_endline(w: &mut dyn Write, ascii: &str) -> io::Result<()> {
|
||||
#[doc(hidden)]
|
||||
pub struct RenderAllocation<'a, 'tcx, Tag, Extra> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
alloc: &'a Allocation<Tag, Extra>,
|
||||
}
|
||||
|
||||
impl<Tag: Copy + Debug, Extra> std::fmt::Display for RenderAllocation<'a, 'tcx, Tag, Extra> {
|
||||
fn fmt(&self, w: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let RenderAllocation { tcx, alloc } = *self;
|
||||
write!(w, "size: {}, align: {})", alloc.size.bytes(), alloc.align.bytes())?;
|
||||
if alloc.size == Size::ZERO {
|
||||
// We are done.
|
||||
return write!(w, " {{}}");
|
||||
}
|
||||
// Write allocation bytes.
|
||||
writeln!(w, " {{")?;
|
||||
write_allocation_bytes(tcx, alloc, w, " ")?;
|
||||
write!(w, "}}")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_allocation_endline(w: &mut dyn std::fmt::Write, ascii: &str) -> std::fmt::Result {
|
||||
for _ in 0..(BYTES_PER_LINE - ascii.chars().count()) {
|
||||
write!(w, " ")?;
|
||||
}
|
||||
@ -677,12 +689,12 @@ const BYTES_PER_LINE: usize = 16;
|
||||
|
||||
/// Prints the line start address and returns the new line start address.
|
||||
fn write_allocation_newline(
|
||||
w: &mut dyn Write,
|
||||
w: &mut dyn std::fmt::Write,
|
||||
mut line_start: Size,
|
||||
ascii: &str,
|
||||
pos_width: usize,
|
||||
prefix: &str,
|
||||
) -> io::Result<Size> {
|
||||
) -> Result<Size, std::fmt::Error> {
|
||||
write_allocation_endline(w, ascii)?;
|
||||
line_start += Size::from_bytes(BYTES_PER_LINE);
|
||||
write!(w, "{}0x{:02$x} │ ", prefix, line_start.bytes(), pos_width)?;
|
||||
@ -695,9 +707,9 @@ fn write_allocation_newline(
|
||||
fn write_allocation_bytes<Tag: Copy + Debug, Extra>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
alloc: &Allocation<Tag, Extra>,
|
||||
w: &mut dyn Write,
|
||||
w: &mut dyn std::fmt::Write,
|
||||
prefix: &str,
|
||||
) -> io::Result<()> {
|
||||
) -> std::fmt::Result {
|
||||
let num_lines = alloc.size.bytes_usize().saturating_sub(BYTES_PER_LINE);
|
||||
// Number of chars needed to represent all line numbers.
|
||||
let pos_width = format!("{:x}", alloc.size.bytes()).len();
|
||||
|
Loading…
Reference in New Issue
Block a user