Skip to content

Commit ec897f9

Browse files
committed
don't allow runtime-aligning of memory
1 parent 613d15c commit ec897f9

File tree

7 files changed

+79
-87
lines changed

7 files changed

+79
-87
lines changed

src/interpreter/mod.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -535,11 +535,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
535535
};
536536

537537
let src = self.eval_operand(operand)?;
538-
src.check_align(elem_align)?;
539-
dest.check_align(elem_align)?;
540538
for i in 0..length {
541539
let elem_dest = dest.offset((i * elem_size) as isize);
542-
self.memory.copy(src, elem_dest, elem_size)?;
540+
self.memory.copy(src, elem_dest, elem_size, elem_align)?;
543541
}
544542
}
545543

@@ -603,17 +601,17 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
603601
let src = self.eval_operand(operand)?;
604602
let src_ty = self.operand_ty(operand);
605603
// FIXME(solson): Wrong for almost everything.
606-
// FIXME: check alignment
607604
warn!("misc cast from {:?} to {:?}", src_ty, dest_ty);
608605
let dest_size = self.type_size(dest_ty);
609606
let src_size = self.type_size(src_ty);
607+
let dest_align = self.type_align(dest_ty);
610608

611609
// Hack to support fat pointer -> thin pointer casts to keep tests for
612610
// other things passing for now.
613611
let is_fat_ptr_cast = pointee_type(src_ty).map_or(false, |ty| !self.type_is_sized(ty));
614612

615613
if dest_size == src_size || is_fat_ptr_cast {
616-
self.memory.copy(src, dest, dest_size)?;
614+
self.memory.copy(src, dest, dest_size, dest_align)?;
617615
} else {
618616
return Err(EvalError::Unimplemented(format!("can't handle cast: {:?}", rvalue)));
619617
}
@@ -858,9 +856,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
858856
fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> {
859857
let size = self.type_size(ty);
860858
let align = self.type_align(ty);
861-
src.check_align(align)?;
862-
dest.check_align(align)?;
863-
self.memory.copy(src, dest, size)?;
859+
self.memory.copy(src, dest, size, align)?;
864860
Ok(())
865861
}
866862

src/interpreter/terminator.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,11 +291,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
291291
let elem_size = self.type_size(elem_ty);
292292
let elem_align = self.type_align(elem_ty);
293293
let src = self.memory.read_ptr(args_ptrs[0])?;
294-
src.check_align(elem_align)?;
295294
let dest = self.memory.read_ptr(args_ptrs[1])?;
296-
dest.check_align(elem_align)?;
297295
let count = self.memory.read_isize(args_ptrs[2])?;
298-
self.memory.copy(src, dest, count as usize * elem_size)?;
296+
self.memory.copy(src, dest, count as usize * elem_size, elem_align)?;
299297
}
300298

301299
"discriminant_value" => {

src/memory.rs

Lines changed: 70 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -51,25 +51,6 @@ impl Pointer {
5151
offset: 0,
5252
}
5353
}
54-
pub fn is_aligned_to(&self, align: usize) -> bool {
55-
self.offset % align == 0
56-
}
57-
pub fn check_align(&self, align: usize) -> EvalResult<'static, ()> {
58-
if self.is_aligned_to(align) {
59-
Ok(())
60-
} else {
61-
let mut best = self.offset;
62-
let mut i = 1;
63-
while best > 0 && (best & 1 == 0) {
64-
best >>= 1;
65-
i <<= 1;
66-
}
67-
Err(EvalError::AlignmentCheckFailed {
68-
required: align,
69-
has: i,
70-
})
71-
}
72-
}
7354
}
7455

7556
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
@@ -118,11 +99,11 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
11899
bytes: Vec::new(),
119100
relocations: BTreeMap::new(),
120101
undef_mask: UndefMask::new(0),
121-
align: 0,
102+
align: 1,
122103
};
123104
mem.alloc_map.insert(ZST_ALLOC_ID, alloc);
124105
// check that additional zst allocs work
125-
debug_assert!(mem.allocate(0, 0).unwrap().points_to_zst());
106+
debug_assert!(mem.allocate(0, 1).unwrap().points_to_zst());
126107
debug_assert!(mem.get(ZST_ALLOC_ID).is_ok());
127108
mem
128109
}
@@ -155,40 +136,38 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
155136
}
156137

157138
pub fn allocate(&mut self, size: usize, align: usize) -> EvalResult<'tcx, Pointer> {
139+
assert!(align != 0);
158140
if size == 0 {
159141
return Ok(Pointer::zst_ptr());
160142
}
161-
// make sure we can offset the result pointer by the worst possible alignment
162-
// this allows cheaply checking for alignment directly in the pointer
163-
let least_aligned_size = size + align;
164143
if self.memory_size - self.memory_usage < size {
165144
return Err(EvalError::OutOfMemory {
166-
allocation_size: least_aligned_size,
145+
allocation_size: size,
167146
memory_size: self.memory_size,
168147
memory_usage: self.memory_usage,
169148
});
170149
}
171150
self.memory_usage += size;
172151
let alloc = Allocation {
173-
bytes: vec![0; least_aligned_size],
152+
bytes: vec![0; size],
174153
relocations: BTreeMap::new(),
175-
undef_mask: UndefMask::new(least_aligned_size),
154+
undef_mask: UndefMask::new(size),
176155
align: align,
177156
};
178157
let id = self.next_id;
179158
self.next_id.0 += 1;
180159
self.alloc_map.insert(id, alloc);
181160
Ok(Pointer {
182161
alloc_id: id,
183-
// offset by the alignment, so larger accesses will fail
184-
offset: align,
162+
offset: 0,
185163
})
186164
}
187165

188166
// TODO(solson): Track which allocations were returned from __rust_allocate and report an error
189167
// when reallocating/deallocating any others.
190168
pub fn reallocate(&mut self, ptr: Pointer, new_size: usize, align: usize) -> EvalResult<'tcx, Pointer> {
191-
if ptr.offset != self.get(ptr.alloc_id)?.align {
169+
// TODO(solson): Report error about non-__rust_allocate'd pointer.
170+
if ptr.offset != 0 {
192171
// TODO(solson): Report error about non-__rust_allocate'd pointer.
193172
return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset)));
194173
}
@@ -197,27 +176,26 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
197176
}
198177

199178
let size = self.get(ptr.alloc_id)?.bytes.len();
200-
let least_aligned_size = new_size + align;
201179

202-
if least_aligned_size > size {
203-
let amount = least_aligned_size - size;
180+
if new_size > size {
181+
let amount = new_size - size;
204182
self.memory_usage += amount;
205183
let alloc = self.get_mut(ptr.alloc_id)?;
206184
alloc.bytes.extend(iter::repeat(0).take(amount));
207185
alloc.undef_mask.grow(amount, false);
208-
} else if size > least_aligned_size {
186+
} else if size > new_size {
209187
// it's possible to cause miri to use arbitrary amounts of memory that aren't detectable
210188
// through the memory_usage value, by allocating a lot and reallocating to zero
211-
self.memory_usage -= size - least_aligned_size;
212-
self.clear_relocations(ptr.offset(least_aligned_size as isize), size - least_aligned_size)?;
189+
self.memory_usage -= size - new_size;
190+
self.clear_relocations(ptr.offset(new_size as isize), size - new_size)?;
213191
let alloc = self.get_mut(ptr.alloc_id)?;
214-
alloc.bytes.truncate(least_aligned_size);
215-
alloc.undef_mask.truncate(least_aligned_size);
192+
alloc.bytes.truncate(new_size);
193+
alloc.undef_mask.truncate(new_size);
216194
}
217195

218196
Ok(Pointer {
219197
alloc_id: ptr.alloc_id,
220-
offset: align,
198+
offset: 0,
221199
})
222200
}
223201

@@ -226,7 +204,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
226204
if ptr.points_to_zst() {
227205
return Ok(());
228206
}
229-
if ptr.offset != self.get(ptr.alloc_id)?.align {
207+
if ptr.offset != 0 {
230208
// TODO(solson): Report error about non-__rust_allocate'd pointer.
231209
return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset)));
232210
}
@@ -251,6 +229,24 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
251229
pub fn endianess(&self) -> layout::Endian {
252230
self.layout.endian
253231
}
232+
233+
pub fn check_align(&self, ptr: Pointer, align: usize) -> EvalResult<'tcx, ()> {
234+
let alloc = self.get(ptr.alloc_id)?;
235+
if alloc.align < align {
236+
return Err(EvalError::AlignmentCheckFailed {
237+
has: alloc.align,
238+
required: align,
239+
});
240+
}
241+
if ptr.offset % align == 0 {
242+
Ok(())
243+
} else {
244+
Err(EvalError::AlignmentCheckFailed {
245+
has: ptr.offset % align,
246+
required: align,
247+
})
248+
}
249+
}
254250
}
255251

256252
/// Allocation accessors
@@ -368,15 +364,17 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
368364
Ok(&mut alloc.bytes[ptr.offset..ptr.offset + size])
369365
}
370366

371-
fn get_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &[u8]> {
367+
fn get_bytes(&self, ptr: Pointer, size: usize, align: usize) -> EvalResult<'tcx, &[u8]> {
368+
self.check_align(ptr, align)?;
372369
if self.relocations(ptr, size)?.count() != 0 {
373370
return Err(EvalError::ReadPointerAsBytes);
374371
}
375372
self.check_defined(ptr, size)?;
376373
self.get_bytes_unchecked(ptr, size)
377374
}
378375

379-
fn get_bytes_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &mut [u8]> {
376+
fn get_bytes_mut(&mut self, ptr: Pointer, size: usize, align: usize) -> EvalResult<'tcx, &mut [u8]> {
377+
self.check_align(ptr, align)?;
380378
self.clear_relocations(ptr, size)?;
381379
self.mark_definedness(ptr, size, true)?;
382380
self.get_bytes_unchecked_mut(ptr, size)
@@ -385,11 +383,11 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
385383

386384
/// Reading and writing
387385
impl<'a, 'tcx> Memory<'a, 'tcx> {
388-
pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<'tcx, ()> {
386+
pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize, align: usize) -> EvalResult<'tcx, ()> {
389387
self.check_relocation_edges(src, size)?;
390388

391389
let src_bytes = self.get_bytes_unchecked_mut(src, size)?.as_mut_ptr();
392-
let dest_bytes = self.get_bytes_mut(dest, size)?.as_mut_ptr();
390+
let dest_bytes = self.get_bytes_mut(dest, size, align)?.as_mut_ptr();
393391

394392
// SAFE: The above indexing would have panicked if there weren't at least `size` bytes
395393
// behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and
@@ -409,17 +407,17 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
409407
}
410408

411409
pub fn read_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &[u8]> {
412-
self.get_bytes(ptr, size)
410+
self.get_bytes(ptr, size, 1)
413411
}
414412

415413
pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<'tcx, ()> {
416-
let bytes = self.get_bytes_mut(ptr, src.len())?;
414+
let bytes = self.get_bytes_mut(ptr, src.len(), 1)?;
417415
bytes.clone_from_slice(src);
418416
Ok(())
419417
}
420418

421419
pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: usize) -> EvalResult<'tcx, ()> {
422-
let bytes = self.get_bytes_mut(ptr, count)?;
420+
let bytes = self.get_bytes_mut(ptr, count, 1)?;
423421
for b in bytes { *b = val; }
424422
Ok(())
425423
}
@@ -465,8 +463,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
465463
}
466464

467465
pub fn read_bool(&self, ptr: Pointer) -> EvalResult<'tcx, bool> {
468-
ptr.check_align(self.layout.i1_align.abi() as usize)?;
469-
let bytes = self.get_bytes(ptr, 1)?;
466+
let bytes = self.get_bytes(ptr, 1, self.layout.i1_align.abi() as usize)?;
470467
match bytes[0] {
471468
0 => Ok(false),
472469
1 => Ok(true),
@@ -475,42 +472,43 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
475472
}
476473

477474
pub fn write_bool(&mut self, ptr: Pointer, b: bool) -> EvalResult<'tcx, ()> {
478-
ptr.check_align(self.layout.i1_align.abi() as usize)?;
479-
self.get_bytes_mut(ptr, 1).map(|bytes| bytes[0] = b as u8)
475+
let align = self.layout.i1_align.abi() as usize;
476+
self.get_bytes_mut(ptr, 1, align)
477+
.map(|bytes| bytes[0] = b as u8)
480478
}
481479

482-
fn check_int_align(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, ()> {
480+
fn int_align(&self, size: usize) -> EvalResult<'tcx, usize> {
483481
match size {
484-
1 => ptr.check_align(self.layout.i8_align.abi() as usize),
485-
2 => ptr.check_align(self.layout.i16_align.abi() as usize),
486-
4 => ptr.check_align(self.layout.i32_align.abi() as usize),
487-
8 => ptr.check_align(self.layout.i64_align.abi() as usize),
482+
1 => Ok(self.layout.i8_align.abi() as usize),
483+
2 => Ok(self.layout.i16_align.abi() as usize),
484+
4 => Ok(self.layout.i32_align.abi() as usize),
485+
8 => Ok(self.layout.i64_align.abi() as usize),
488486
_ => panic!("bad integer size"),
489487
}
490488
}
491489

492490
pub fn read_int(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, i64> {
493-
self.check_int_align(ptr, size)?;
494-
self.get_bytes(ptr, size).map(|b| read_target_int(self.endianess(), b).unwrap())
491+
let align = self.int_align(size)?;
492+
self.get_bytes(ptr, size, align).map(|b| read_target_int(self.endianess(), b).unwrap())
495493
}
496494

497495
pub fn write_int(&mut self, ptr: Pointer, n: i64, size: usize) -> EvalResult<'tcx, ()> {
498-
self.check_int_align(ptr, size)?;
496+
let align = self.int_align(size)?;
499497
let endianess = self.endianess();
500-
let b = self.get_bytes_mut(ptr, size)?;
498+
let b = self.get_bytes_mut(ptr, size, align)?;
501499
write_target_int(endianess, b, n).unwrap();
502500
Ok(())
503501
}
504502

505503
pub fn read_uint(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, u64> {
506-
self.check_int_align(ptr, size)?;
507-
self.get_bytes(ptr, size).map(|b| read_target_uint(self.endianess(), b).unwrap())
504+
let align = self.int_align(size)?;
505+
self.get_bytes(ptr, size, align).map(|b| read_target_uint(self.endianess(), b).unwrap())
508506
}
509507

510508
pub fn write_uint(&mut self, ptr: Pointer, n: u64, size: usize) -> EvalResult<'tcx, ()> {
511-
self.check_int_align(ptr, size)?;
509+
let align = self.int_align(size)?;
512510
let endianess = self.endianess();
513-
let b = self.get_bytes_mut(ptr, size)?;
511+
let b = self.get_bytes_mut(ptr, size, align)?;
514512
write_target_uint(endianess, b, n).unwrap();
515513
Ok(())
516514
}
@@ -534,29 +532,29 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
534532
}
535533

536534
pub fn write_f32(&mut self, ptr: Pointer, f: f32) -> EvalResult<'tcx, ()> {
537-
ptr.check_align(self.layout.f32_align.abi() as usize)?;
538535
let endianess = self.endianess();
539-
let b = self.get_bytes_mut(ptr, 4)?;
536+
let align = self.layout.f32_align.abi() as usize;
537+
let b = self.get_bytes_mut(ptr, 4, align)?;
540538
write_target_f32(endianess, b, f).unwrap();
541539
Ok(())
542540
}
543541

544542
pub fn write_f64(&mut self, ptr: Pointer, f: f64) -> EvalResult<'tcx, ()> {
545-
ptr.check_align(self.layout.f64_align.abi() as usize)?;
546543
let endianess = self.endianess();
547-
let b = self.get_bytes_mut(ptr, 8)?;
544+
let align = self.layout.f64_align.abi() as usize;
545+
let b = self.get_bytes_mut(ptr, 8, align)?;
548546
write_target_f64(endianess, b, f).unwrap();
549547
Ok(())
550548
}
551549

552550
pub fn read_f32(&self, ptr: Pointer) -> EvalResult<'tcx, f32> {
553-
ptr.check_align(self.layout.f32_align.abi() as usize)?;
554-
self.get_bytes(ptr, 4).map(|b| read_target_f32(self.endianess(), b).unwrap())
551+
self.get_bytes(ptr, 4, self.layout.f32_align.abi() as usize)
552+
.map(|b| read_target_f32(self.endianess(), b).unwrap())
555553
}
556554

557555
pub fn read_f64(&self, ptr: Pointer) -> EvalResult<'tcx, f64> {
558-
ptr.check_align(self.layout.f64_align.abi() as usize)?;
559-
self.get_bytes(ptr, 8).map(|b| read_target_f64(self.endianess(), b).unwrap())
556+
self.get_bytes(ptr, 8, self.layout.f64_align.abi() as usize)
557+
.map(|b| read_target_f64(self.endianess(), b).unwrap())
560558
}
561559
}
562560

tests/compile-fail/oom.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ fn bar() {
66
assert_eq!(x, 6);
77
}
88

9-
fn main() { //~ ERROR tried to allocate 8 more bytes, but only 0 bytes are free of the 0 byte memory
9+
fn main() { //~ ERROR tried to allocate 4 more bytes, but only 0 bytes are free of the 0 byte memory
1010
bar();
1111
}

tests/compile-fail/oom2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
fn bar(i: i32) {
55
if i < 1000 {
6-
bar(i + 1) //~ ERROR tried to allocate 8 more bytes, but only 1 bytes are free of the 1000 byte memory
6+
bar(i + 1) //~ ERROR tried to allocate 4 more bytes, but only 1 bytes are free of the 1000 byte memory
77
//~^NOTE inside call to bar
88
//~|NOTE inside call to bar
99
//~|NOTE inside call to bar

0 commit comments

Comments
 (0)