Skip to content

Commit e82693f

Browse files
committed
Merge branch 'master' into rustup
2 parents ba47d73 + 2a4c4ad commit e82693f

20 files changed

+175
-92
lines changed

.appveyor.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ install:
2929
- rustc --version
3030

3131
build_script:
32-
- set RUST_TEST_NOCAPTURE=1
33-
- set RUST_BACKTRACE=1
3432
- set RUSTFLAGS=-C debug-assertions
3533
# Build and install miri
3634
- cargo build --release --all-features --all-targets
@@ -40,6 +38,8 @@ build_script:
4038
- set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache\HOST
4139

4240
test_script:
41+
- set RUST_TEST_NOCAPTURE=1
42+
- set RUST_BACKTRACE=1
4343
# Test miri
4444
- cargo test --release --all-features
4545
# Test cargo integration

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ Definite bugs found:
333333
* [Futures turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/56319)
334334
* [`str` turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/58200)
335335
* [`rand` performing unaligned reads](https://github.com/rust-random/rand/issues/779)
336+
* [The Unix allocator calling `posix_memalign` in an invalid way](https://github.com/rust-lang/rust/issues/62251)
336337

337338
Violations of Stacked Borrows found that are likely bugs (but Stacked Borrows is currently just an experiment):
338339

src/intptrcast.rs

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
1-
use std::cell::{Cell, RefCell};
1+
use std::cell::RefCell;
2+
use std::collections::{HashMap, hash_map::Entry};
3+
use std::cmp::max;
24

35
use rand::Rng;
46

5-
use rustc::mir::interpret::{AllocId, Pointer, InterpResult};
6-
use rustc_mir::interpret::Memory;
7+
use rustc_mir::interpret::{AllocId, Pointer, InterpResult, Memory, AllocCheck};
78
use rustc_target::abi::Size;
89

9-
use crate::stacked_borrows::Tag;
10-
use crate::Evaluator;
10+
use crate::{Evaluator, Tag, STACK_ADDR};
1111

1212
pub type MemoryExtra = RefCell<GlobalState>;
1313

14-
#[derive(Clone, Debug, Default)]
15-
pub struct AllocExtra {
16-
base_addr: Cell<Option<u64>>
17-
}
18-
1914
#[derive(Clone, Debug)]
2015
pub struct GlobalState {
2116
/// This is used as a map between the address of each allocation and its `AllocId`.
2217
/// It is always sorted
2318
pub int_to_ptr_map: Vec<(u64, AllocId)>,
19+
/// The base address for each allocation. We cannot put that into
20+
/// `AllocExtra` because function pointers also have a base address, and
21+
/// they do not have an `AllocExtra`.
22+
/// This is the inverse of `int_to_ptr_map`.
23+
pub base_addr: HashMap<AllocId, u64>,
2424
/// This is used as a memory address when a new pointer is casted to an integer. It
2525
/// is always larger than any address that was previously made part of a block.
2626
pub next_base_addr: u64,
2727
}
2828

2929
impl Default for GlobalState {
30-
// FIXME: Query the page size in the future
3130
fn default() -> Self {
3231
GlobalState {
3332
int_to_ptr_map: Vec::default(),
34-
next_base_addr: 2u64.pow(16)
33+
base_addr: HashMap::default(),
34+
next_base_addr: STACK_ADDR,
3535
}
3636
}
3737
}
@@ -73,13 +73,13 @@ impl<'mir, 'tcx> GlobalState {
7373
memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>,
7474
) -> InterpResult<'tcx, u64> {
7575
let mut global_state = memory.extra.intptrcast.borrow_mut();
76+
let global_state = &mut *global_state;
7677

77-
let alloc = memory.get(ptr.alloc_id)?;
78-
let align = alloc.align.bytes();
78+
let (size, align) = memory.get_size_and_align(ptr.alloc_id, AllocCheck::Live)?;
7979

80-
let base_addr = match alloc.extra.intptrcast.base_addr.get() {
81-
Some(base_addr) => base_addr,
82-
None => {
80+
let base_addr = match global_state.base_addr.entry(ptr.alloc_id) {
81+
Entry::Occupied(entry) => *entry.get(),
82+
Entry::Vacant(entry) => {
8383
// This allocation does not have a base address yet, pick one.
8484
// Leave some space to the previous allocation, to give it some chance to be less aligned.
8585
let slack = {
@@ -88,11 +88,16 @@ impl<'mir, 'tcx> GlobalState {
8888
rng.gen_range(0, 16)
8989
};
9090
// From next_base_addr + slack, round up to adjust for alignment.
91-
let base_addr = Self::align_addr(global_state.next_base_addr + slack, align);
92-
alloc.extra.intptrcast.base_addr.set(Some(base_addr));
93-
94-
// Remember next base address.
95-
global_state.next_base_addr = base_addr + alloc.bytes.len() as u64;
91+
let base_addr = Self::align_addr(global_state.next_base_addr + slack, align.bytes());
92+
entry.insert(base_addr);
93+
trace!(
94+
"Assigning base address {:#x} to allocation {:?} (slack: {}, align: {})",
95+
base_addr, ptr.alloc_id, slack, align.bytes(),
96+
);
97+
98+
// Remember next base address. If this allocation is zero-sized, leave a gap
99+
// of at least 1 to avoid two allocations having the same base address.
100+
global_state.next_base_addr = base_addr + max(size.bytes(), 1);
96101
// Given that `next_base_addr` increases in each allocation, pushing the
97102
// corresponding tuple keeps `int_to_ptr_map` sorted
98103
global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id));
@@ -101,7 +106,7 @@ impl<'mir, 'tcx> GlobalState {
101106
}
102107
};
103108

104-
debug_assert_eq!(base_addr % align, 0); // sanity check
109+
debug_assert_eq!(base_addr % align.bytes(), 0); // sanity check
105110
Ok(base_addr + ptr.offset.bytes())
106111
}
107112

src/lib.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ extern crate rustc_data_structures;
1212
extern crate rustc_mir;
1313
extern crate rustc_target;
1414

15-
mod fn_call;
15+
mod shims;
1616
mod operator;
17-
mod intrinsic;
1817
mod helpers;
1918
mod tls;
2019
mod range_map;
@@ -29,15 +28,18 @@ pub use rustc_mir::interpret::*;
2928
// Resolve ambiguity.
3029
pub use rustc_mir::interpret::{self, AllocMap, PlaceTy};
3130

32-
pub use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt;
31+
pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt;
32+
pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt;
3333
pub use crate::operator::EvalContextExt as OperatorEvalContextExt;
34-
pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt;
3534
pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData};
3635
pub use crate::range_map::RangeMap;
3736
pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt};
3837
pub use crate::mono_hash_map::MonoHashMap;
3938
pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item};
40-
pub use crate::machine::{MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt};
39+
pub use crate::machine::{
40+
PAGE_SIZE, STACK_ADDR, NUM_CPUS,
41+
MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt,
42+
};
4143
pub use crate::eval::{eval_main, create_ecx, MiriConfig};
4244

4345
/// Insert rustc arguments at the beginning of the argument list that Miri wants to be

src/machine.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ use rustc::mir;
1616

1717
use crate::*;
1818

19+
// Some global facts about the emulated machine.
20+
pub const PAGE_SIZE: u64 = 4*1024; // FIXME: adjust to target architecture
21+
pub const STACK_ADDR: u64 = 16*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations
22+
pub const NUM_CPUS: u64 = 1;
23+
1924
/// Extra memory kinds
2025
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2126
pub enum MiriMemoryKind {
@@ -40,7 +45,6 @@ impl Into<MemoryKind<MiriMemoryKind>> for MiriMemoryKind {
4045
#[derive(Debug, Clone)]
4146
pub struct AllocExtra {
4247
pub stacked_borrows: stacked_borrows::AllocExtra,
43-
pub intptrcast: intptrcast::AllocExtra,
4448
}
4549

4650
/// Extra global memory data
@@ -275,7 +279,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
275279
mutability: alloc.mutability,
276280
extra: AllocExtra {
277281
stacked_borrows: stacks,
278-
intptrcast: Default::default(),
279282
},
280283
};
281284
(Cow::Owned(alloc), base_tag)

src/fn_call.rs renamed to src/shims/foreign_items.rs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
5151
Ok(Some(this.load_mir(instance.def)?))
5252
}
5353

54+
/// Returns the minimum alignment for the target architecture.
55+
fn min_align(&self) -> Align {
56+
let this = self.eval_context_ref();
57+
// List taken from `libstd/sys_common/alloc.rs`.
58+
let min_align = match this.tcx.tcx.sess.target.target.arch.as_str() {
59+
"x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8,
60+
"x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16,
61+
arch => bug!("Unsupported target architecture: {}", arch),
62+
};
63+
Align::from_bytes(min_align).unwrap()
64+
}
65+
5466
fn malloc(
5567
&mut self,
5668
size: u64,
@@ -61,7 +73,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
6173
if size == 0 {
6274
Scalar::from_int(0, this.pointer_size())
6375
} else {
64-
let align = this.tcx.data_layout.pointer_align.abi;
76+
let align = this.min_align();
6577
let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into());
6678
if zero_init {
6779
// We just allocated this, the access cannot fail
@@ -94,7 +106,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
94106
new_size: u64,
95107
) -> InterpResult<'tcx, Scalar<Tag>> {
96108
let this = self.eval_context_mut();
97-
let align = this.tcx.data_layout.pointer_align.abi;
109+
let align = this.min_align();
98110
if old_ptr.is_null_ptr(this) {
99111
if new_size == 0 {
100112
Ok(Scalar::from_int(0, this.pointer_size()))
@@ -191,12 +203,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
191203
if !align.is_power_of_two() {
192204
return err!(HeapAllocNonPowerOfTwoAlignment(align));
193205
}
206+
/*
207+
FIXME: This check is disabled because rustc violates it.
208+
See <https://github.com/rust-lang/rust/issues/62251>.
194209
if align < this.pointer_size().bytes() {
195210
return err!(MachineError(format!(
196211
"posix_memalign: alignment must be at least the size of a pointer, but is {}",
197212
align,
198213
)));
199214
}
215+
*/
200216
if size == 0 {
201217
this.write_null(ret.into())?;
202218
} else {
@@ -622,11 +638,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
622638
let name = this.read_scalar(args[0])?.to_i32()?;
623639

624640
trace!("sysconf() called with name {}", name);
625-
// Cache the sysconf integers via Miri's global cache.
641+
// TODO: Cache the sysconf integers via Miri's global cache.
626642
let paths = &[
627-
(&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)),
643+
(&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)),
628644
(&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)),
629-
(&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(1, dest.layout.size)),
645+
(&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(NUM_CPUS, dest.layout.size)),
630646
];
631647
let mut result = None;
632648
for &(path, path_value) in paths {
@@ -648,6 +664,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
648664
}
649665
}
650666

667+
"sched_getaffinity" => {
668+
// Return an error; `num_cpus` then falls back to `sysconf`.
669+
this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?;
670+
}
671+
651672
"isatty" => {
652673
this.write_null(dest)?;
653674
}
@@ -722,14 +743,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
722743
// Second argument is where we are supposed to write the stack size.
723744
let ptr = this.deref_operand(args[1])?;
724745
// Just any address.
725-
let stack_addr = Scalar::from_int(0x80000, args[1].layout.size);
746+
let stack_addr = Scalar::from_uint(STACK_ADDR, args[1].layout.size);
726747
this.write_scalar(stack_addr, ptr.into())?;
727748
// Return success (`0`).
728749
this.write_null(dest)?;
729750
}
730751
"pthread_get_stackaddr_np" => {
731752
// Just any address.
732-
let stack_addr = Scalar::from_int(0x80000, dest.layout.size);
753+
let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size);
733754
this.write_scalar(stack_addr, dest)?;
734755
}
735756

@@ -838,14 +859,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
838859
// Initialize with `0`.
839860
this.memory_mut().get_mut(system_info_ptr.alloc_id)?
840861
.write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?;
841-
// Set number of processors to `1`.
862+
// Set number of processors.
842863
let dword_size = Size::from_bytes(4);
843864
let offset = 2*dword_size + 3*tcx.pointer_size();
844865
this.memory_mut().get_mut(system_info_ptr.alloc_id)?
845866
.write_scalar(
846867
tcx,
847868
system_info_ptr.offset(offset, tcx)?,
848-
Scalar::from_int(1, dword_size).into(),
869+
Scalar::from_int(NUM_CPUS, dword_size).into(),
849870
dword_size,
850871
)?;
851872
}
File renamed without changes.

src/shims/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod foreign_items;
2+
pub mod intrinsics;

test-cargo-miri/Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test-cargo-miri/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ byteorder = "1.0"
99

1010
[dev-dependencies]
1111
rand = { version = "0.7", features = ["small_rng"] }
12+
num_cpus = "1.10.1"

0 commit comments

Comments
 (0)