Skip to content
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

Segfault inside Vec::index_mut call #20

Open
mateon1 opened this issue Oct 23, 2017 · 2 comments
Open

Segfault inside Vec::index_mut call #20

mateon1 opened this issue Oct 23, 2017 · 2 comments

Comments

@mateon1
Copy link

mateon1 commented Oct 23, 2017

I came across this while trying to implement input/output for brainfuck.
I looked at the crash for a bit in rr, it seems that something is calling index_mut without setting registers properly.
rsi = 0x0, which causes a null deref

In short:

Program received signal SIGSEGV, Segmentation fault.
0x00005586bde7eacc in alloc::vec::{{impl}}::index_mut<u8> (self=0x7fff4ff77878, index=...) at /shared/dev/rust/rust-patch/src/liballoc/vec.rs:1627
1627	    fn index_mut(&mut self, index: ops::Range<usize>) -> &mut [T] {
(rr) print *self
$1 = alloc::vec::Vec<u8> {buf: alloc::raw_vec::RawVec<u8, alloc::heap::Heap> {ptr: core::ptr::Unique<u8> {pointer: core::nonzero::NonZero<*const u8> (0x7f0f8621e000 "\000"), _marker: core::marker::PhantomData<u8>}, cap: 256, a: alloc::heap::Heap}, len: 256}
(rr) bt
#0  0x00005586bde7eacc in alloc::vec::{{impl}}::index_mut<u8> (self=0x7fff4ff77878, index=...) at /shared/dev/rust/rust-patch/src/liballoc/vec.rs:1627
#1  0x00007f0f87570de8 in ?? ()
#2  0x00005586be19f250 in panic_loc.C ()
#3  0x00005586bdf4bcc1 in str.j ()
#4  0x000000000001459c in ?? ()
#5  0x00005586be19f250 in panic_loc.C ()
#6  0x00000000000005b0 in ?? ()
#7  0x00007f0f86229040 in ?? ()
#8  0x0000000000000004 in ?? ()
#9  0x0000000000000004 in ?? ()
#10 0x00007f0f8622a200 in ?? ()
#11 0x0000000000000096 in ?? ()
#12 0x0000000000000096 in ?? ()
#13 0x0000000000000000 in ?? ()

So this is definitely crashing on indexing the mem variable.

Here's code that triggers this crash: [Note: I use boxed traits, because the jit!() macro doesn't accept generic functions]

#![feature(plugin, custom_attribute)]
#![plugin(holyjit_plugin)]
#![feature(unboxed_closures)]
#[macro_use] extern crate holyjit_lib as hj;

use std::io;
use std::io::{Read, Write, Cursor};

jit!{ fn eval(jc: hj::JitContext, program: String, input: Box<Read>, output: Box<Write>) -> Result<(), ()> = eval_impl in jc; }
fn eval_impl(_jc: hj::JitContext, program: String, mut input: Box<Read>, mut output: Box<Write>) -> Result<(), ()> {
    let prog = program.as_bytes();
    let mut pc : usize = 0;
    let mut ptr : usize = 0;
    let mut mem : Vec<u8> = Vec::with_capacity(256);
    mem.resize(256, 0);
    loop {
        if pc >= prog.len() {
            return Ok(());
        }
        match *prog.get(pc).unwrap() {
            b'>' => {
                ptr += 1;
                if ptr >= mem.len() {
                    mem.push(0);
                }
            }
            b'<' => { ptr = ptr.saturating_sub(1); }
            b'-' => { mem[ptr] = mem[ptr].wrapping_sub(1); }
            b'+' => { mem[ptr] = mem[ptr].wrapping_add(1); }
            b'.' => { output.write(&mem[ptr .. ptr + 1]).unwrap(); }
            b',' => { input.read_exact(&mut mem[ptr .. ptr + 1]).unwrap(); }
            b'[' => {
                if mem[ptr] == 0 {
                    let mut iter = (pc + 1, 0);
                    loop {
                        iter = match (iter, prog[iter.0]) {
                            ((p, 0), b']') => {
                                pc = p + 1;
                                break;
                            },
                            ((p, d), b'[') => (p + 1, d + 1),
                            ((p, d), b']') => (p + 1, d - 1),
                            ((p, d), _) => (p + 1, d)
                        }
                    }
                    continue; // skip pc increment
                }
            }
            b']' => {
                let mut iter = (pc - 1, 0);
                loop {
                    iter = match (iter, prog[iter.0]) {
                        ((p, 0), b'[') => {
                            pc = p;
                            break;
                        },
                        ((p, d), b'[') => (p - 1, d + 1),
                        ((p, d), b']') => (p - 1, d - 1),
                        ((p, d), _) => (p - 1, d)
                    }
                }
                continue; // skip pc increment
            }
            _ => { panic!("Unknown Symbol"); }
        }
        pc += 1;
    }
}

fn main() {
    let jc : hj::JitContext = Default::default();
    let res = eval(jc, ",[.,]".into(), Box::new(Cursor::new(b"Hello, world!")), Box::new(io::stderr()));
    // let res = eval(jc, "-[>-[>-[>-<-]<-]<-]<-]".into());
    res.unwrap();
}
@mateon1 mateon1 changed the title Segfault after Vec::index_mut call Segfault inside Vec::index_mut call Oct 23, 2017
@nbp
Copy link
Owner

nbp commented Oct 23, 2017

Thanks a lot for this great report :)

Here's code that triggers this crash: [Note: I use boxed traits, because the jit!() macro doesn't accept generic functions]

Yes, this is a problem which is due to the fact that we would have to re-implement the elision for the jit! macro, as it stores the signature of the function in a structure.

I looked at the crash for a bit in rr, it seems that something is calling index_mut without setting registers properly.

At the moment the assembly output is quite similar to the -O0 of LLVM, except for the fact that HolyJit does not yet use the ModRm addressing modes. You should be (almost) able to compare the assembly produced by HolyJit with the result of:

(rr) disas brainfuck::eval_impl

@nbp
Copy link
Owner

nbp commented Oct 23, 2017

Looking at the generated code, it seems that the problem is that instead of giving the Range argument by reference, we give it by value to the index_mut function:

0x7f2fef121dc6  mov    (%rsi),%rdi
0x7f2fef121dc9  movabs $0xfffffffffffffd68,%rsi
0x7f2fef121dd3  add    %rbp,%rsi
0x7f2fef121dd6  mov    (%rsi),%rax
0x7f2fef121dd9  mov    0x8(%rsi),%rcx
0x7f2fef121ddd  mov    %rax,%rsi
0x7f2fef121de0  mov    %rdx,%rax
0x7f2fef121de3  mov    %rcx,%rdx
0x7f2fef121de6  callq  *%rax

The problem is likely located here:

holyjit/plugin/src/trans.rs

Lines 1083 to 1093 in e4ed3be

for arg in args {
let InstSeq(mut arg_insts, arg_reg, arg_ty) =
self.operand(arg).or_else(
report_nyi!("mir::TerminatorKind::Call(args: [.. {:?} ..])", arg))?;
let (_, size) = self.add_type(arg_ty, 0)?;
// 0-size arguments are ignored.
if size != 0 {
insts.append(&mut arg_insts);
args_reg.push(arg_reg);
}
}

@nbp nbp added this to the v0.1.0: Cranelift + LIR milestone Aug 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants