Skip to content

Commit 42b70f1

Browse files
authored
Merge branch 'master' into exit
2 parents 6a6c0cd + 1c07cd5 commit 42b70f1

File tree

8 files changed

+217
-117
lines changed

8 files changed

+217
-117
lines changed

src/fn_call.rs

Lines changed: 142 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,86 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
5050
Ok(Some(this.load_mir(instance.def)?))
5151
}
5252

53+
fn malloc(
54+
&mut self,
55+
size: u64,
56+
zero_init: bool,
57+
) -> Scalar<Tag> {
58+
let this = self.eval_context_mut();
59+
let tcx = &{this.tcx.tcx};
60+
if size == 0 {
61+
Scalar::from_int(0, this.pointer_size())
62+
} else {
63+
let align = this.tcx.data_layout.pointer_align.abi;
64+
let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into());
65+
if zero_init {
66+
// We just allocated this, the access cannot fail
67+
this.memory_mut()
68+
.get_mut(ptr.alloc_id).unwrap()
69+
.write_repeat(tcx, ptr, 0, Size::from_bytes(size)).unwrap();
70+
}
71+
Scalar::Ptr(ptr)
72+
}
73+
}
74+
75+
fn free(
76+
&mut self,
77+
ptr: Scalar<Tag>,
78+
) -> EvalResult<'tcx> {
79+
let this = self.eval_context_mut();
80+
if !ptr.is_null_ptr(this) {
81+
this.memory_mut().deallocate(
82+
ptr.to_ptr()?,
83+
None,
84+
MiriMemoryKind::C.into(),
85+
)?;
86+
}
87+
Ok(())
88+
}
89+
90+
fn realloc(
91+
&mut self,
92+
old_ptr: Scalar<Tag>,
93+
new_size: u64,
94+
) -> EvalResult<'tcx, Scalar<Tag>> {
95+
let this = self.eval_context_mut();
96+
let align = this.tcx.data_layout.pointer_align.abi;
97+
if old_ptr.is_null_ptr(this) {
98+
if new_size == 0 {
99+
Ok(Scalar::from_int(0, this.pointer_size()))
100+
} else {
101+
let new_ptr = this.memory_mut().allocate(
102+
Size::from_bytes(new_size),
103+
align,
104+
MiriMemoryKind::C.into()
105+
);
106+
Ok(Scalar::Ptr(new_ptr))
107+
}
108+
} else {
109+
let old_ptr = old_ptr.to_ptr()?;
110+
let memory = this.memory_mut();
111+
let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64);
112+
if new_size == 0 {
113+
memory.deallocate(
114+
old_ptr,
115+
Some((old_size, align)),
116+
MiriMemoryKind::C.into(),
117+
)?;
118+
Ok(Scalar::from_int(0, this.pointer_size()))
119+
} else {
120+
let new_ptr = memory.reallocate(
121+
old_ptr,
122+
old_size,
123+
align,
124+
Size::from_bytes(new_size),
125+
align,
126+
MiriMemoryKind::C.into(),
127+
)?;
128+
Ok(Scalar::Ptr(new_ptr))
129+
}
130+
}
131+
}
132+
53133
/// Emulates calling a foreign item, failing if the item is not supported.
54134
/// This function will handle `goto_block` if needed.
55135
fn emulate_foreign_item(
@@ -95,28 +175,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
95175
match link_name {
96176
"malloc" => {
97177
let size = this.read_scalar(args[0])?.to_usize(this)?;
98-
if size == 0 {
99-
this.write_null(dest)?;
100-
} else {
101-
let align = this.tcx.data_layout.pointer_align.abi;
102-
let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into());
103-
this.write_scalar(Scalar::Ptr(ptr), dest)?;
104-
}
178+
let res = this.malloc(size, /*zero_init:*/ false);
179+
this.write_scalar(res, dest)?;
105180
}
106181
"calloc" => {
107182
let items = this.read_scalar(args[0])?.to_usize(this)?;
108183
let len = this.read_scalar(args[1])?.to_usize(this)?;
109-
let bytes = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?;
110-
111-
if bytes == 0 {
112-
this.write_null(dest)?;
113-
} else {
114-
let size = Size::from_bytes(bytes);
115-
let align = this.tcx.data_layout.pointer_align.abi;
116-
let ptr = this.memory_mut().allocate(size, align, MiriMemoryKind::C.into());
117-
this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, size)?;
118-
this.write_scalar(Scalar::Ptr(ptr), dest)?;
119-
}
184+
let size = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?;
185+
let res = this.malloc(size, /*zero_init:*/ true);
186+
this.write_scalar(res, dest)?;
120187
}
121188
"posix_memalign" => {
122189
let ret = this.deref_operand(args[0])?;
@@ -144,55 +211,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
144211
}
145212
this.write_null(dest)?;
146213
}
147-
148214
"free" => {
149215
let ptr = this.read_scalar(args[0])?.not_undef()?;
150-
if !ptr.is_null_ptr(this) {
151-
this.memory_mut().deallocate(
152-
ptr.to_ptr()?,
153-
None,
154-
MiriMemoryKind::C.into(),
155-
)?;
156-
}
216+
this.free(ptr)?;
157217
}
158218
"realloc" => {
159219
let old_ptr = this.read_scalar(args[0])?.not_undef()?;
160220
let new_size = this.read_scalar(args[1])?.to_usize(this)?;
161-
let align = this.tcx.data_layout.pointer_align.abi;
162-
if old_ptr.is_null_ptr(this) {
163-
if new_size == 0 {
164-
this.write_null(dest)?;
165-
} else {
166-
let new_ptr = this.memory_mut().allocate(
167-
Size::from_bytes(new_size),
168-
align,
169-
MiriMemoryKind::C.into()
170-
);
171-
this.write_scalar(Scalar::Ptr(new_ptr), dest)?;
172-
}
173-
} else {
174-
let old_ptr = old_ptr.to_ptr()?;
175-
let memory = this.memory_mut();
176-
let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64);
177-
if new_size == 0 {
178-
memory.deallocate(
179-
old_ptr,
180-
Some((old_size, align)),
181-
MiriMemoryKind::C.into(),
182-
)?;
183-
this.write_null(dest)?;
184-
} else {
185-
let new_ptr = memory.reallocate(
186-
old_ptr,
187-
old_size,
188-
align,
189-
Size::from_bytes(new_size),
190-
align,
191-
MiriMemoryKind::C.into(),
192-
)?;
193-
this.write_scalar(Scalar::Ptr(new_ptr), dest)?;
194-
}
195-
}
221+
let res = this.realloc(old_ptr, new_size)?;
222+
this.write_scalar(res, dest)?;
196223
}
197224

198225
"__rust_alloc" => {
@@ -279,19 +306,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
279306
// is called if a `HashMap` is created the regular way (e.g. HashMap<K, V>).
280307
match this.read_scalar(args[0])?.to_usize(this)? {
281308
id if id == sys_getrandom => {
282-
let ptr = this.read_scalar(args[1])?.to_ptr()?;
309+
let ptr = this.read_scalar(args[1])?.not_undef()?;
283310
let len = this.read_scalar(args[2])?.to_usize(this)?;
284311

285312
// The only supported flags are GRND_RANDOM and GRND_NONBLOCK,
286313
// neither of which have any effect on our current PRNG
287314
let _flags = this.read_scalar(args[3])?.to_i32()?;
288315

289-
if len > 0 {
290-
let data = gen_random(this, len as usize)?;
291-
this.memory_mut().get_mut(ptr.alloc_id)?
292-
.write_bytes(tcx, ptr, &data)?;
293-
}
294-
316+
gen_random(this, len as usize, ptr)?;
295317
this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?;
296318
}
297319
id => {
@@ -693,8 +715,43 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
693715
"_NSGetArgv" => {
694716
this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?;
695717
},
718+
"SecRandomCopyBytes" => {
719+
let len = this.read_scalar(args[1])?.to_usize(this)?;
720+
let ptr = this.read_scalar(args[2])?.not_undef()?;
721+
gen_random(this, len as usize, ptr)?;
722+
this.write_null(dest)?;
723+
}
696724

697725
// Windows API stubs.
726+
// HANDLE = isize
727+
// DWORD = ULONG = u32
728+
"GetProcessHeap" => {
729+
// Just fake a HANDLE
730+
this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?;
731+
}
732+
"HeapAlloc" => {
733+
let _handle = this.read_scalar(args[0])?.to_isize(this)?;
734+
let flags = this.read_scalar(args[1])?.to_u32()?;
735+
let size = this.read_scalar(args[2])?.to_usize(this)?;
736+
let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY
737+
let res = this.malloc(size, zero_init);
738+
this.write_scalar(res, dest)?;
739+
}
740+
"HeapFree" => {
741+
let _handle = this.read_scalar(args[0])?.to_isize(this)?;
742+
let _flags = this.read_scalar(args[1])?.to_u32()?;
743+
let ptr = this.read_scalar(args[2])?.not_undef()?;
744+
this.free(ptr)?;
745+
}
746+
"HeapReAlloc" => {
747+
let _handle = this.read_scalar(args[0])?.to_isize(this)?;
748+
let _flags = this.read_scalar(args[1])?.to_u32()?;
749+
let ptr = this.read_scalar(args[2])?.not_undef()?;
750+
let size = this.read_scalar(args[3])?.to_usize(this)?;
751+
let res = this.realloc(ptr, size)?;
752+
this.write_scalar(res, dest)?;
753+
}
754+
698755
"SetLastError" => {
699756
let err = this.read_scalar(args[0])?.to_u32()?;
700757
this.machine.last_error = err;
@@ -818,15 +875,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
818875
}
819876
// The actual name of 'RtlGenRandom'
820877
"SystemFunction036" => {
821-
let ptr = this.read_scalar(args[0])?.to_ptr()?;
878+
let ptr = this.read_scalar(args[0])?.not_undef()?;
822879
let len = this.read_scalar(args[1])?.to_u32()?;
823-
824-
if len > 0 {
825-
let data = gen_random(this, len as usize)?;
826-
this.memory_mut().get_mut(ptr.alloc_id)?
827-
.write_bytes(tcx, ptr, &data)?;
828-
}
829-
880+
gen_random(this, len as usize, ptr)?;
830881
this.write_scalar(Scalar::from_bool(true), dest)?;
831882
}
832883

@@ -867,21 +918,30 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
867918
fn gen_random<'a, 'mir, 'tcx>(
868919
this: &mut MiriEvalContext<'a, 'mir, 'tcx>,
869920
len: usize,
870-
) -> Result<Vec<u8>, EvalError<'tcx>> {
921+
dest: Scalar<Tag>,
922+
) -> EvalResult<'tcx> {
923+
if len == 0 {
924+
// Nothing to do
925+
return Ok(());
926+
}
927+
let ptr = dest.to_ptr()?;
871928

872-
match &mut this.machine.rng {
929+
let data = match &mut this.machine.rng {
873930
Some(rng) => {
874931
let mut data = vec![0; len];
875932
rng.fill_bytes(&mut data);
876-
Ok(data)
933+
data
877934
}
878935
None => {
879-
err!(Unimplemented(
936+
return err!(Unimplemented(
880937
"miri does not support gathering system entropy in deterministic mode!
881938
Use '-Zmiri-seed=<seed>' to enable random number generation.
882939
WARNING: Miri does *not* generate cryptographically secure entropy -
883940
do not use Miri to run any program that needs secure random number generation".to_owned(),
884-
))
941+
));
885942
}
886-
}
943+
};
944+
let tcx = &{this.tcx.tcx};
945+
this.memory_mut().get_mut(ptr.alloc_id)?
946+
.write_bytes(tcx, ptr, &data)
887947
}

test-cargo-miri/run-test.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@
55
and the working directory to contain the cargo-miri-test project.
66
'''
77

8-
import sys, subprocess
8+
import sys, subprocess, os
99

1010
def fail(msg):
1111
print("TEST FAIL: {}".format(msg))
1212
sys.exit(1)
1313

14+
def cargo_miri(cmd):
15+
args = ["cargo", "miri", cmd, "-q"]
16+
if 'MIRI_TEST_TARGET' in os.environ:
17+
args += ["--target", os.environ['MIRI_TEST_TARGET']]
18+
return args
19+
1420
def test(name, cmd, stdout_ref, stderr_ref):
1521
print("==> Testing `{}` <==".format(name))
1622
## Call `cargo miri`, capture all output
@@ -36,20 +42,29 @@ def test(name, cmd, stdout_ref, stderr_ref):
3642
fail("stderr does not match reference")
3743

3844
def test_cargo_miri_run():
39-
test("cargo miri run", ["cargo", "miri", "run", "-q"], "stdout.ref", "stderr.ref")
45+
test("cargo miri run",
46+
cargo_miri("run"),
47+
"stdout.ref", "stderr.ref"
48+
)
4049
test("cargo miri run (with arguments)",
41-
["cargo", "miri", "run", "-q", "--", "--", "hello world", '"hello world"'],
50+
cargo_miri("run") + ["--", "--", "hello world", '"hello world"'],
4251
"stdout.ref", "stderr.ref2"
4352
)
4453

4554
def test_cargo_miri_test():
46-
test("cargo miri test", ["cargo", "miri", "test", "-q", "--", "-Zmiri-seed=feed"], "test.stdout.ref", "test.stderr.ref")
55+
test("cargo miri test",
56+
cargo_miri("test") + ["--", "-Zmiri-seed=feed"],
57+
"test.stdout.ref", "test.stderr.ref"
58+
)
4759
test("cargo miri test (with filter)",
48-
["cargo", "miri", "test", "-q", "--", "--", "impl"],
60+
cargo_miri("test") + ["--", "--", "impl"],
4961
"test.stdout.ref2", "test.stderr.ref"
5062
)
5163

64+
os.chdir(os.path.dirname(os.path.realpath(__file__)))
65+
5266
test_cargo_miri_run()
5367
test_cargo_miri_test()
68+
5469
print("TEST SUCCESSFUL!")
5570
sys.exit(0)

test-cargo-miri/tests/test.rs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
#![allow(unused_imports)] // FIXME for macOS
2-
3-
extern crate rand;
4-
51
use rand::{SeedableRng, FromEntropy, Rng, rngs::SmallRng};
62

73
#[test]
@@ -21,17 +17,13 @@ fn fixed_rng() {
2117

2218
#[test]
2319
fn entropy_rng() {
24-
#[cfg(not(target_os="macos"))] // FIXME entropy does not work on macOS
25-
// (Not disabling the entire test as that would change the output.)
26-
{
27-
// Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite)
28-
let mut rng = SmallRng::from_entropy();
29-
let _val = rng.gen::<i32>();
20+
// Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite)
21+
let mut rng = SmallRng::from_entropy();
22+
let _val = rng.gen::<i32>();
3023

31-
// Also try per-thread RNG.
32-
let mut rng = rand::thread_rng();
33-
let _val = rng.gen::<i32>();
34-
}
24+
// Also try per-thread RNG.
25+
let mut rng = rand::thread_rng();
26+
let _val = rng.gen::<i32>();
3527
}
3628

3729
// A test that won't work on miri

tests/compiletest.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ fn get_host() -> String {
101101
}
102102

103103
fn get_target() -> String {
104-
std::env::var("MIRI_COMPILETEST_TARGET").unwrap_or_else(|_| get_host())
104+
std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host())
105105
}
106106

107107
fn run_pass_miri(opt: bool) {

0 commit comments

Comments
 (0)