Skip to content

Commit 1511023

Browse files
authored
Merge pull request rust-lang#237 from RalfJung/reallocate
Update for allcator API, simplify reallocate
2 parents b8bd42e + 1cbf5e8 commit 1511023

11 files changed

+138
-138
lines changed

src/memory.rs

Lines changed: 9 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
223223

224224
// TODO(solson): Track which allocations were returned from __rust_allocate and report an error
225225
// when reallocating/deallocating any others.
226-
pub fn reallocate(&mut self, ptr: Pointer, old_size: u64, new_size: u64, align: u64) -> EvalResult<'tcx, Pointer> {
227-
assert!(align.is_power_of_two());
226+
pub fn reallocate(&mut self, ptr: Pointer, old_size: u64, old_align: u64, new_size: u64, new_align: u64) -> EvalResult<'tcx, Pointer> {
227+
use std::cmp::min;
228+
228229
// TODO(solson): Report error about non-__rust_allocate'd pointer.
229230
if ptr.offset != 0 || self.get(ptr.alloc_id).is_err() {
230231
return Err(EvalError::ReallocateNonBasePtr);
@@ -233,39 +234,12 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
233234
return Err(EvalError::ReallocatedStaticMemory);
234235
}
235236

236-
let size = self.get(ptr.alloc_id)?.bytes.len() as u64;
237-
let real_align = self.get(ptr.alloc_id)?.align;
238-
if size != old_size || real_align != align {
239-
return Err(EvalError::IncorrectAllocationInformation);
240-
}
241-
242-
if new_size > size {
243-
let amount = new_size - size;
244-
self.memory_usage += amount;
245-
let alloc = self.get_mut(ptr.alloc_id)?;
246-
assert_eq!(amount as usize as u64, amount);
247-
alloc.bytes.extend(iter::repeat(0).take(amount as usize));
248-
alloc.undef_mask.grow(amount, false);
249-
} else if size > new_size {
250-
self.memory_usage -= size - new_size;
251-
self.clear_relocations(ptr.offset(new_size, self.layout)?, size - new_size)?;
252-
let alloc = self.get_mut(ptr.alloc_id)?;
253-
// `as usize` is fine here, since it is smaller than `size`, which came from a usize
254-
alloc.bytes.truncate(new_size as usize);
255-
alloc.bytes.shrink_to_fit();
256-
alloc.undef_mask.truncate(new_size);
257-
}
258-
259-
// Change allocation ID. We do this after the above to be able to re-use methods like `clear_relocations`.
260-
let id = {
261-
let alloc = self.alloc_map.remove(&ptr.alloc_id).expect("We already used this pointer above");
262-
let id = self.next_id;
263-
self.next_id.0 += 1;
264-
self.alloc_map.insert(id, alloc);
265-
id
266-
};
237+
// For simplicities' sake, we implement reallocate as "alloc, copy, dealloc"
238+
let new_ptr = self.allocate(new_size, new_align)?;
239+
self.copy(PrimVal::Ptr(ptr), PrimVal::Ptr(new_ptr), min(old_size, new_size), min(old_align, new_align), /*nonoverlapping*/true)?;
240+
self.deallocate(ptr, Some((old_size, old_align)))?;
267241

268-
Ok(Pointer::new(id, 0))
242+
Ok(new_ptr)
269243
}
270244

271245
// TODO(solson): See comment on `reallocate`.
@@ -689,6 +663,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
689663

690664
pub fn copy(&mut self, src: PrimVal, dest: PrimVal, size: u64, align: u64, nonoverlapping: bool) -> EvalResult<'tcx> {
691665
if size == 0 {
666+
// TODO: Should we check for alignment here? (Also see write_bytes intrinsic)
692667
return Ok(());
693668
}
694669
let src = src.to_ptr()?;
@@ -1138,14 +1113,6 @@ impl UndefMask {
11381113
self.len += amount;
11391114
self.set_range_inbounds(start, start + amount, new_state);
11401115
}
1141-
1142-
fn truncate(&mut self, length: u64) {
1143-
self.len = length;
1144-
let truncate = self.len / BLOCK_SIZE + 1;
1145-
assert_eq!(truncate as usize as u64, truncate);
1146-
self.blocks.truncate(truncate as usize);
1147-
self.blocks.shrink_to_fit();
1148-
}
11491116
}
11501117

11511118
fn bit_index(bits: u64) -> (usize, usize) {

src/terminator/intrinsic.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
463463
let ptr = arg_vals[0].read_ptr(&self.memory)?;
464464
let count = self.value_to_primval(arg_vals[2], usize)?.to_u64()?;
465465
if count > 0 {
466+
// TODO: Should we, at least, validate the alignment? (Also see memory::copy)
466467
self.memory.check_align(ptr, ty_align, size * count)?;
467468
self.memory.write_repeat(ptr, val_byte, size * count)?;
468469
}

src/terminator/mod.rs

Lines changed: 91 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -520,37 +520,111 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
520520
sig: ty::FnSig<'tcx>,
521521
path: String,
522522
) -> EvalResult<'tcx> {
523+
// In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early.
524+
match &path[..] {
525+
"std::panicking::rust_panic_with_hook" |
526+
"std::rt::begin_panic_fmt" => return Err(EvalError::Panic),
527+
_ => {},
528+
}
529+
530+
let dest_ty = sig.output();
531+
let (dest, dest_block) = destination.ok_or_else(|| EvalError::NoMirFor(path.clone()))?;
532+
523533
if sig.abi == Abi::C {
524534
// An external C function
525-
let ty = sig.output();
526-
let (ret, target) = destination.unwrap();
527-
self.call_c_abi(instance.def_id(), arg_operands, ret, ty, target)?;
535+
// TODO: That functions actually has a similar preamble to what follows here. May make sense to
536+
// unify these two mechanisms for "hooking into missing functions".
537+
self.call_c_abi(instance.def_id(), arg_operands, dest, dest_ty, dest_block)?;
528538
return Ok(());
529539
}
540+
541+
let args_res: EvalResult<Vec<Value>> = arg_operands.iter()
542+
.map(|arg| self.eval_operand(arg))
543+
.collect();
544+
let args = args_res?;
545+
546+
let usize = self.tcx.types.usize;
530547

531-
// A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies).
532-
// Still, we can make many things mostly work by "emulating" or ignoring some functions.
533548
match &path[..] {
549+
// Allocators are magic. They have no MIR, even when the rest of libstd does.
550+
"alloc::heap::::__rust_alloc" => {
551+
let size = self.value_to_primval(args[0], usize)?.to_u64()?;
552+
let align = self.value_to_primval(args[1], usize)?.to_u64()?;
553+
if size == 0 {
554+
return Err(EvalError::HeapAllocZeroBytes);
555+
}
556+
if !align.is_power_of_two() {
557+
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
558+
}
559+
let ptr = self.memory.allocate(size, align)?;
560+
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
561+
}
562+
"alloc::heap::::__rust_alloc_zeroed" => {
563+
let size = self.value_to_primval(args[0], usize)?.to_u64()?;
564+
let align = self.value_to_primval(args[1], usize)?.to_u64()?;
565+
if size == 0 {
566+
return Err(EvalError::HeapAllocZeroBytes);
567+
}
568+
if !align.is_power_of_two() {
569+
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
570+
}
571+
let ptr = self.memory.allocate(size, align)?;
572+
self.memory.write_repeat(PrimVal::Ptr(ptr), 0, size)?;
573+
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
574+
}
575+
"alloc::heap::::__rust_dealloc" => {
576+
let ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
577+
let old_size = self.value_to_primval(args[1], usize)?.to_u64()?;
578+
let align = self.value_to_primval(args[2], usize)?.to_u64()?;
579+
if old_size == 0 {
580+
return Err(EvalError::HeapAllocZeroBytes);
581+
}
582+
if !align.is_power_of_two() {
583+
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
584+
}
585+
self.memory.deallocate(ptr, Some((old_size, align)))?;
586+
}
587+
"alloc::heap::::__rust_realloc" => {
588+
let ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
589+
let old_size = self.value_to_primval(args[1], usize)?.to_u64()?;
590+
let old_align = self.value_to_primval(args[2], usize)?.to_u64()?;
591+
let new_size = self.value_to_primval(args[3], usize)?.to_u64()?;
592+
let new_align = self.value_to_primval(args[4], usize)?.to_u64()?;
593+
if old_size == 0 || new_size == 0 {
594+
return Err(EvalError::HeapAllocZeroBytes);
595+
}
596+
if !old_align.is_power_of_two() {
597+
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(old_align));
598+
}
599+
if !new_align.is_power_of_two() {
600+
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(new_align));
601+
}
602+
let new_ptr = self.memory.reallocate(ptr, old_size, old_align, new_size, new_align)?;
603+
self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?;
604+
}
605+
606+
// A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies).
607+
// Still, we can make many things mostly work by "emulating" or ignoring some functions.
534608
"std::io::_print" => {
535609
trace!("Ignoring output. To run programs that print, make sure you have a libstd with full MIR.");
536-
self.goto_block(destination.unwrap().1);
537-
Ok(())
538-
},
539-
"std::thread::Builder::new" => Err(EvalError::Unimplemented("miri does not support threading".to_owned())),
540-
"std::env::args" => Err(EvalError::Unimplemented("miri does not support program arguments".to_owned())),
541-
"std::panicking::rust_panic_with_hook" |
542-
"std::rt::begin_panic_fmt" => Err(EvalError::Panic),
610+
}
611+
"std::thread::Builder::new" => return Err(EvalError::Unimplemented("miri does not support threading".to_owned())),
612+
"std::env::args" => return Err(EvalError::Unimplemented("miri does not support program arguments".to_owned())),
543613
"std::panicking::panicking" |
544614
"std::rt::panicking" => {
545-
let (lval, block) = destination.expect("std::rt::panicking does not diverge");
546615
// we abort on panic -> `std::rt::panicking` always returns false
547616
let bool = self.tcx.types.bool;
548-
self.write_primval(lval, PrimVal::from_bool(false), bool)?;
549-
self.goto_block(block);
550-
Ok(())
617+
self.write_primval(dest, PrimVal::from_bool(false), bool)?;
551618
}
552-
_ => Err(EvalError::NoMirFor(path)),
619+
_ => return Err(EvalError::NoMirFor(path)),
553620
}
621+
622+
// Since we pushed no stack frame, the main loop will act
623+
// as if the call just completed and it's returning to the
624+
// current frame.
625+
self.dump_local(dest);
626+
self.goto_block(dest_block);
627+
return Ok(());
554628
}
555629

556630
fn call_c_abi(
@@ -609,61 +683,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
609683
return Err(EvalError::Unimplemented(format!("miri does not support dynamically loading libraries (requested symbol: {})", symbol_name)));
610684
}
611685

612-
"__rust_allocate" => {
613-
let size = self.value_to_primval(args[0], usize)?.to_u64()?;
614-
let align = self.value_to_primval(args[1], usize)?.to_u64()?;
615-
if size == 0 {
616-
return Err(EvalError::HeapAllocZeroBytes);
617-
}
618-
if !align.is_power_of_two() {
619-
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
620-
}
621-
let ptr = self.memory.allocate(size, align)?;
622-
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
623-
}
624-
625-
"__rust_allocate_zeroed" => {
626-
let size = self.value_to_primval(args[0], usize)?.to_u64()?;
627-
let align = self.value_to_primval(args[1], usize)?.to_u64()?;
628-
if size == 0 {
629-
return Err(EvalError::HeapAllocZeroBytes);
630-
}
631-
if !align.is_power_of_two() {
632-
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
633-
}
634-
let ptr = self.memory.allocate(size, align)?;
635-
self.memory.write_repeat(PrimVal::Ptr(ptr), 0, size)?;
636-
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
637-
}
638-
639-
"__rust_deallocate" => {
640-
let ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
641-
let old_size = self.value_to_primval(args[1], usize)?.to_u64()?;
642-
let align = self.value_to_primval(args[2], usize)?.to_u64()?;
643-
if old_size == 0 {
644-
return Err(EvalError::HeapAllocZeroBytes);
645-
}
646-
if !align.is_power_of_two() {
647-
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
648-
}
649-
self.memory.deallocate(ptr, Some((old_size, align)))?;
650-
},
651-
652-
"__rust_reallocate" => {
653-
let ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
654-
let old_size = self.value_to_primval(args[1], usize)?.to_u64()?;
655-
let size = self.value_to_primval(args[2], usize)?.to_u64()?;
656-
let align = self.value_to_primval(args[3], usize)?.to_u64()?;
657-
if old_size == 0 || size == 0 {
658-
return Err(EvalError::HeapAllocZeroBytes);
659-
}
660-
if !align.is_power_of_two() {
661-
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
662-
}
663-
let new_ptr = self.memory.reallocate(ptr, old_size, size, align)?;
664-
self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?;
665-
}
666-
667686
"__rust_maybe_catch_panic" => {
668687
// fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32
669688
// We abort on panic, so not much is going on here, but we still have to call the closure
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
#![feature(alloc, heap_api)]
1+
#![feature(alloc, allocator_api)]
22

33
extern crate alloc;
44

5+
use alloc::heap::Heap;
6+
use alloc::allocator::*;
7+
58
// error-pattern: tried to deallocate or reallocate using incorrect alignment or size
69

710
use alloc::heap::*;
811
fn main() {
912
unsafe {
10-
let x = allocate(1, 1);
11-
deallocate(x, 1, 2);
13+
let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
14+
Heap.dealloc(x, Layout::from_size_align_unchecked(1, 2));
1215
}
1316
}
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
#![feature(alloc, heap_api)]
1+
#![feature(alloc, allocator_api)]
22

33
extern crate alloc;
44

5+
use alloc::heap::Heap;
6+
use alloc::allocator::*;
7+
58
// error-pattern: tried to deallocate or reallocate using incorrect alignment or size
69

710
use alloc::heap::*;
811
fn main() {
912
unsafe {
10-
let x = allocate(1, 1);
11-
deallocate(x, 1, 2);
13+
let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
14+
Heap.dealloc(x, Layout::from_size_align_unchecked(2, 1));
1215
}
1316
}
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
#![feature(alloc, heap_api)]
1+
#![feature(alloc, allocator_api)]
22

33
extern crate alloc;
44

5+
use alloc::heap::Heap;
6+
use alloc::allocator::*;
7+
58
// error-pattern: tried to deallocate with a pointer not to the beginning of an existing object
69

710
use alloc::heap::*;
811
fn main() {
912
unsafe {
10-
let x = allocate(1, 1);
11-
deallocate(x, 1, 1);
12-
deallocate(x, 1, 1);
13+
let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
14+
Heap.dealloc(x, Layout::from_size_align_unchecked(1, 1));
15+
Heap.dealloc(x, Layout::from_size_align_unchecked(1, 1));
1316
}
1417
}
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
#![feature(alloc, heap_api)]
1+
#![feature(alloc, allocator_api)]
22

33
extern crate alloc;
44

5+
use alloc::heap::Heap;
6+
use alloc::allocator::*;
7+
58
// error-pattern: tried to deallocate or reallocate using incorrect alignment or size
69

710
use alloc::heap::*;
811
fn main() {
912
unsafe {
10-
let x = allocate(1, 1);
11-
let _y = reallocate(x, 1, 1, 2);
13+
let x = Heap.alloc(Layout::from_size_align_unchecked(1, 2)).unwrap();
14+
let _y = Heap.realloc(x, Layout::from_size_align_unchecked(1, 1), Layout::from_size_align_unchecked(1, 2)).unwrap();
1215
}
1316
}
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
#![feature(alloc, heap_api)]
1+
#![feature(alloc, allocator_api)]
22

33
extern crate alloc;
44

5+
use alloc::heap::Heap;
6+
use alloc::allocator::*;
7+
58
// error-pattern: tried to deallocate or reallocate using incorrect alignment or size
69

710
use alloc::heap::*;
811
fn main() {
912
unsafe {
10-
let x = allocate(1, 1);
11-
let _y = reallocate(x, 2, 1, 1);
13+
let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
14+
let _y = Heap.realloc(x, Layout::from_size_align_unchecked(2, 1), Layout::from_size_align_unchecked(1, 1)).unwrap();
1215
}
1316
}
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
#![feature(alloc, heap_api)]
1+
#![feature(alloc, allocator_api)]
22

33
extern crate alloc;
44

5-
use alloc::heap::*;
5+
use alloc::heap::Heap;
6+
use alloc::allocator::*;
7+
68
fn main() {
79
unsafe {
8-
let x = allocate(1, 1);
9-
let _y = reallocate(x, 1, 1, 1);
10+
let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
11+
let _y = Heap.realloc(x, Layout::from_size_align_unchecked(1, 1), Layout::from_size_align_unchecked(1, 1)).unwrap();
1012
let _z = *x; //~ ERROR: dangling pointer was dereferenced
1113
}
1214
}

0 commit comments

Comments
 (0)