From 9c9b572f5b856676e3b65413237e5e81d35981c3 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Mon, 26 Jun 2017 08:33:51 -0400 Subject: [PATCH] Intercept from_size_align(), alloc_zeroed(), and alloc(), allowing base64 example to work without xargo. --- example/standalone/base64.rs | 23 ++++----- src/terminator/mod.rs | 92 +++++++++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 14 deletions(-) diff --git a/example/standalone/base64.rs b/example/standalone/base64.rs index 874d5fd..26416f0 100644 --- a/example/standalone/base64.rs +++ b/example/standalone/base64.rs @@ -1,19 +1,12 @@ -// SEER lets us decode base64, given only an encoder function! - -const BUFFER_LENGTH: usize = 1024; +// Seer lets us decode base64, given only an encoder function! fn main() { use std::io::Read; - let value_to_decode = b"aGVsbG8gd29ybGQh"; - - // We avoid heap allocations because they require liballoc to be compiled with MIR. - // See https://github.com/dwrensha/seer/issues/1 - let mut data = [0u8; BUFFER_LENGTH]; - let input_len = (value_to_decode.len() + 3) / 4 * 3; - std::io::stdin().read_exact(&mut data[..input_len]).unwrap(); + let value_to_decode = "aGVsbG8gd29ybGQh"; + let mut data: Vec = vec![0; (value_to_decode.len() + 3) / 4 * 3]; + std::io::stdin().read_exact(&mut data[..]).unwrap(); - let mut result = [0; BUFFER_LENGTH]; - base64_encode(&data[..input_len], &mut result[..]); + let result = base64_encode(&data[..]); if result.starts_with(value_to_decode) { // This will panic on the input that encodes to `value_to_decode`. panic!("we found it!"); @@ -21,10 +14,13 @@ fn main() { } // copied from rustc_serialize -fn base64_encode(input: &[u8], output: &mut [u8]) { +fn base64_encode(input: &[u8]) -> String { static BYTES: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + let mut result = String::new(); { let len = input.len(); + let output = unsafe { result.as_mut_vec() }; + *output = vec![b'='; (len + 2) / 3 * 4]; let mod_len = len % 3; { let mut s_in = input[..len - mod_len].iter().map(|&x| x as u32); @@ -60,4 +56,5 @@ fn base64_encode(input: &[u8], output: &mut [u8]) { } } } + result } diff --git a/src/terminator/mod.rs b/src/terminator/mod.rs index d93d521..d721fc4 100644 --- a/src/terminator/mod.rs +++ b/src/terminator/mod.rs @@ -558,7 +558,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let dest_ptr = self.force_allocation(lval)?.to_ptr(); // FIXME make this more robust - self.memory.write_uint(dest_ptr, 0, 8)?; // discriminant + self.memory.write_uint(dest_ptr, 0, 8)?; // discriminant = Ok self.memory.write_uint(dest_ptr.offset(8), num_bytes, 8)?; // payload self.goto_block(block); @@ -569,6 +569,96 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { EvalError::Unimplemented( "no abstract implementation for stdin.lock()".into())); } + "alloc::allocator::Layout::from_size_align" => { + let (lval, block) = destination.expect("from_size_align() does not diverge"); + let dest_ptr = self.force_allocation(lval)?.to_ptr(); + + let args_res: EvalResult> = arg_operands.iter() + .map(|arg| self.eval_operand(arg)) + .collect(); + let args = args_res?; + + let usize = self.tcx.types.usize; + let size = self.value_to_primval(args[0], usize)?.to_u128()?; + let align = self.value_to_primval(args[1], usize)?.to_u128()?; + + if !align.is_power_of_two() { + unimplemented!(); + } + + if size as usize > ::std::usize::MAX - (align as usize - 1) { + unimplemented!(); + } + + // FIXME make this more robust + self.memory.write_uint(dest_ptr, 1, 8)?; // discriminant = Some + + // payload + self.memory.write_uint(dest_ptr.offset(8), size, 8)?; + self.memory.write_uint(dest_ptr.offset(16), align, 8)?; + + self.goto_block(block); + return Ok(true); + } + "::alloc_zeroed" => { + let (lval, block) = destination.expect("alloc_zeroed() does not diverge"); + let dest_ptr = self.force_allocation(lval)?.to_ptr(); + + let args_res: EvalResult> = arg_operands.iter() + .map(|arg| self.eval_operand(arg)) + .collect(); + let args = args_res?; + + let (size, align) = match args[1] { + Value::ByRef(ptr) => { + (self.memory.read_uint(ptr, 8)?.to_u64()?, + self.memory.read_uint(ptr.offset(8), 8)?.to_u64()?) + } + Value::ByValPair(_size, _align) => { + unimplemented!() + } + Value::ByVal(_) => unreachable!(), + }; + + let ptr = self.memory.allocate(size, align)?; + self.memory.write_repeat(ptr, 0, size)?; + + self.memory.write_uint(dest_ptr, 0, 8)?; // discriminant = Ok + self.memory.write_ptr(dest_ptr.offset(8), ptr)?; + + self.goto_block(block); + return Ok(true); + } + + "::alloc" => { + let (lval, block) = destination.expect("alloc() does not diverge"); + let dest_ptr = self.force_allocation(lval)?.to_ptr(); + + let args_res: EvalResult> = arg_operands.iter() + .map(|arg| self.eval_operand(arg)) + .collect(); + let args = args_res?; + + let (size, align) = match args[1] { + Value::ByRef(ptr) => { + (self.memory.read_uint(ptr, 8)?.to_u64()?, + self.memory.read_uint(ptr.offset(8), 8)?.to_u64()?) + } + Value::ByValPair(_size, _align) => { + unimplemented!() + } + Value::ByVal(_) => unreachable!(), + }; + + let ptr = self.memory.allocate(size, align)?; + + self.memory.write_uint(dest_ptr, 0, 8)?; // discriminant = Ok + self.memory.write_ptr(dest_ptr.offset(8), ptr)?; + + self.goto_block(block); + return Ok(true); + } + _ => (), } }