1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
| #![no_std]
#![no_main]
extern crate alloc;
#[macro_use]
#[path = "ulib.rs"]
mod ulib;
use alloc::vec;
use ulib::*;
static mut GLOBAL: [u8; 65536] = [0; 65536];
fn global() -> &'static mut [u8; 65536] {
unsafe { &mut *core::ptr::addr_of_mut!(GLOBAL) }
}
fn all(buf: &[u8], value: u8) -> bool {
buf.iter().all(|&b| b == value)
}
fn main() -> i64 {
let mut c = Checks::new("cowtest");
global().fill(1);
let mut heap = vec![2u8; 100_000];
let mut stack = [3u8; 2000];
let pid = fork();
if pid == 0 {
let before = all(global(), 1) && all(&heap, 2) && all(&stack, 3);
global().fill(0xc1);
heap.fill(0xc2);
stack.fill(0xc3);
let after = all(global(), 0xc1) && all(&heap, 0xc2) && all(core::hint::black_box(&stack), 0xc3);
exit(if before && after { 0 } else { 1 });
}
c.check(wait(pid) == 0, "the child starts with the parent's data and can change its copy");
c.check(all(global(), 1), "the child's writes to global data stay in the child");
c.check(all(&heap, 2), "... and to the heap");
c.check(all(core::hint::black_box(&stack), 3), "... and to the stack");
let (r, w) = pipe().unwrap_or((-1, -1));
let pid = fork();
if pid == 0 {
close(w);
let mut b = [0u8];
read(r, &mut b); exit(if all(global(), 1) && all(&heap, 2) { 0 } else { 1 });
}
close(r);
global().fill(0x77);
heap.fill(0x77);
write(w, b"!");
close(w);
c.check(wait(pid) == 0, "the parent's writes after fork stay in the parent");
c.check(all(global(), 0x77), "and the parent sees its own writes");
let pid = fork();
if pid == 0 {
let pid2 = fork();
if pid2 == 0 {
global()[0] = 3;
exit(if global()[1] == 0x77 { 0 } else { 1 });
}
global()[0] = 2;
let code = wait(pid2);
exit(if code == 0 && global()[0] == 2 { 0 } else { 1 });
}
c.check(wait(pid) == 0 && global()[0] == 0x77, "three generations: each keeps its own copy");
let shared = mmap(0, 8192, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
let private = mmap(0, 8192, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
c.check(shared > 0 && private > 0, "mmap shared + private anonymous memory");
let (sp, pp) = (shared as *mut u8, private as *mut u8);
unsafe {
sp.write_volatile(10);
pp.write_volatile(10);
}
let pid = fork();
if pid == 0 {
unsafe {
sp.write_volatile(42);
sp.add(4096).write_volatile(43); pp.write_volatile(42);
}
exit(0);
}
wait(pid);
let (s0, s1, p0) = unsafe { (sp.read_volatile(), sp.add(4096).read_volatile(), pp.read_volatile()) };
c.check(s0 == 42 && s1 == 43, "MAP_SHARED: the child's writes show up in the parent");
c.check(p0 == 10, "MAP_PRIVATE: they don't");
c.done()
}
|