Skip to content

Commit

Permalink
Merge pull request #2685 from cfallin/fix-multi-trap-metadata
Browse files Browse the repository at this point in the history
Fix incomplete trap metadata due to multiple traps at one address.
  • Loading branch information
cfallin authored Feb 25, 2021
2 parents 0cc4a3d + 40db4de commit ebbe626
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 17 deletions.
2 changes: 1 addition & 1 deletion cranelift/codegen/src/isa/x64/inst/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ fn emit_std_enc_mem(

let srcloc = state.cur_srcloc();
let can_trap = mem_e.can_trap();
if srcloc != SourceLoc::default() && can_trap {
if can_trap {
sink.add_trap(srcloc, TrapCode::HeapOutOfBounds);
}

Expand Down
5 changes: 4 additions & 1 deletion cranelift/codegen/src/isa/x64/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5113,7 +5113,10 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
));
ctx.emit(Inst::checked_div_or_rem_seq(kind, size, divisor_copy, tmp));
} else {
let divisor = input_to_reg_mem(ctx, inputs[1]);
// We don't want more than one trap record for a single instruction,
// so let's not allow the "mem" case (load-op merging) here; force
// divisor into a register instead.
let divisor = RegMem::reg(put_input_in_reg(ctx, inputs[1]));

// Fill in the high parts:
if kind.is_signed() {
Expand Down
118 changes: 103 additions & 15 deletions cranelift/codegen/src/machinst/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1314,26 +1314,25 @@ impl MachBufferFinalized {
let mut next_trap = 0;
let mut next_call_site = 0;
for (idx, byte) in self.data.iter().enumerate() {
if next_reloc < self.relocs.len() {
while next_reloc < self.relocs.len()
&& self.relocs[next_reloc].offset == idx as CodeOffset
{
let reloc = &self.relocs[next_reloc];
if reloc.offset == idx as CodeOffset {
sink.reloc_external(reloc.srcloc, reloc.kind, &reloc.name, reloc.addend);
next_reloc += 1;
}
sink.reloc_external(reloc.srcloc, reloc.kind, &reloc.name, reloc.addend);
next_reloc += 1;
}
if next_trap < self.traps.len() {
while next_trap < self.traps.len() && self.traps[next_trap].offset == idx as CodeOffset
{
let trap = &self.traps[next_trap];
if trap.offset == idx as CodeOffset {
sink.trap(trap.code, trap.srcloc);
next_trap += 1;
}
sink.trap(trap.code, trap.srcloc);
next_trap += 1;
}
if next_call_site < self.call_sites.len() {
while next_call_site < self.call_sites.len()
&& self.call_sites[next_call_site].ret_addr == idx as CodeOffset
{
let call_site = &self.call_sites[next_call_site];
if call_site.ret_addr == idx as CodeOffset {
sink.add_call_site(call_site.opcode, call_site.srcloc);
next_call_site += 1;
}
sink.add_call_site(call_site.opcode, call_site.srcloc);
next_call_site += 1;
}
sink.put1(*byte);
}
Expand Down Expand Up @@ -1468,11 +1467,14 @@ impl MachBranch {
#[cfg(all(test, feature = "arm64"))]
mod test {
use super::*;
use crate::ir::{ConstantOffset, Function, JumpTable, Value};
use crate::isa::aarch64::inst::xreg;
use crate::isa::aarch64::inst::{BranchTarget, CondBrKind, EmitInfo, Inst};
use crate::isa::TargetIsa;
use crate::machinst::MachInstEmit;
use crate::settings;
use std::default::Default;
use std::vec::Vec;

fn label(n: u32) -> MachLabel {
MachLabel::from_block(n)
Expand Down Expand Up @@ -1819,4 +1821,90 @@ mod test {

assert_eq!(&golden_data[..], &buf.data[..]);
}

#[test]
fn metadata_records() {
let mut buf = MachBuffer::<Inst>::new();

buf.reserve_labels_for_blocks(1);

buf.bind_label(label(0));
buf.put1(1);
buf.add_trap(SourceLoc::default(), TrapCode::HeapOutOfBounds);
buf.put1(2);
buf.add_trap(SourceLoc::default(), TrapCode::IntegerOverflow);
buf.add_trap(SourceLoc::default(), TrapCode::IntegerDivisionByZero);
buf.add_call_site(SourceLoc::default(), Opcode::Call);
buf.add_reloc(
SourceLoc::default(),
Reloc::Abs4,
&ExternalName::user(0, 0),
0,
);
buf.put1(3);
buf.add_reloc(
SourceLoc::default(),
Reloc::Abs8,
&ExternalName::user(1, 1),
1,
);
buf.put1(4);

let buf = buf.finish();

#[derive(Default)]
struct TestCodeSink {
offset: CodeOffset,
traps: Vec<(CodeOffset, TrapCode)>,
callsites: Vec<(CodeOffset, Opcode)>,
relocs: Vec<(CodeOffset, Reloc)>,
}
impl CodeSink for TestCodeSink {
fn offset(&self) -> CodeOffset {
self.offset
}
fn put1(&mut self, _: u8) {
self.offset += 1;
}
fn put2(&mut self, _: u16) {
self.offset += 2;
}
fn put4(&mut self, _: u32) {
self.offset += 4;
}
fn put8(&mut self, _: u64) {
self.offset += 8;
}
fn reloc_external(&mut self, _: SourceLoc, r: Reloc, _: &ExternalName, _: Addend) {
self.relocs.push((self.offset, r));
}
fn reloc_constant(&mut self, _: Reloc, _: ConstantOffset) {}
fn reloc_jt(&mut self, _: Reloc, _: JumpTable) {}
fn trap(&mut self, t: TrapCode, _: SourceLoc) {
self.traps.push((self.offset, t));
}
fn begin_jumptables(&mut self) {}
fn begin_rodata(&mut self) {}
fn end_codegen(&mut self) {}
fn add_stack_map(&mut self, _: &[Value], _: &Function, _: &dyn TargetIsa) {}
fn add_call_site(&mut self, op: Opcode, _: SourceLoc) {
self.callsites.push((self.offset, op));
}
}

let mut sink = TestCodeSink::default();
buf.emit(&mut sink);

assert_eq!(sink.offset, 4);
assert_eq!(
sink.traps,
vec![
(1, TrapCode::HeapOutOfBounds),
(2, TrapCode::IntegerOverflow),
(2, TrapCode::IntegerDivisionByZero)
]
);
assert_eq!(sink.callsites, vec![(2, Opcode::Call),]);
assert_eq!(sink.relocs, vec![(2, Reloc::Abs4), (3, Reloc::Abs8)]);
}
}

0 comments on commit ebbe626

Please sign in to comment.