about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/miri/README.md2
-rw-r--r--src/tools/miri/src/bin/miri.rs12
-rw-r--r--src/tools/miri/src/eval.rs3
-rw-r--r--src/tools/miri/src/intptrcast.rs4
-rw-r--r--src/tools/miri/src/lib.rs2
-rw-r--r--src/tools/miri/src/machine.rs37
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs8
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs4
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/page_size.rs13
-rw-r--r--src/tools/miri/tests/pass-dep/page_size_override.rs7
11 files changed, 78 insertions, 16 deletions
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index dac0a9820b9..909e5bd510d 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -399,6 +399,8 @@ to Miri failing to detect cases of undefined behavior in a program.
 * `-Zmiri-track-weak-memory-loads` shows a backtrace when weak memory emulation returns an outdated
   value from a load. This can help diagnose problems that disappear under
   `-Zmiri-disable-weak-memory-emulation`.
+* `-Zmiri-force-page-size=<num>` overrides the default page size for an architecture, in multiples of 1k.
+  `4` is default for most targets. This value should always be a power of 2 and nonzero.
 
 [function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
 
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index fce95b987f7..8c01748613c 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -512,6 +512,18 @@ fn main() {
             };
 
             miri_config.num_cpus = num_cpus;
+        } else if let Some(param) = arg.strip_prefix("-Zmiri-force-page-size=") {
+            let page_size = match param.parse::<u64>() {
+                Ok(i) =>
+                    if i.is_power_of_two() {
+                        i * 1024
+                    } else {
+                        show_error!("-Zmiri-force-page-size requires a power of 2: {}", i)
+                    },
+                Err(err) => show_error!("-Zmiri-force-page-size requires a `u64`: {}", err),
+            };
+
+            miri_config.page_size = Some(page_size);
         } else {
             // Forward to rustc.
             rustc_args.push(arg);
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 7b4973f3b9d..9d1574b3188 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -143,6 +143,8 @@ pub struct MiriConfig {
     pub gc_interval: u32,
     /// The number of CPUs to be reported by miri.
     pub num_cpus: u32,
+    /// Requires Miri to emulate pages of a certain size
+    pub page_size: Option<u64>,
 }
 
 impl Default for MiriConfig {
@@ -176,6 +178,7 @@ impl Default for MiriConfig {
             external_so_file: None,
             gc_interval: 10_000,
             num_cpus: 1,
+            page_size: None,
         }
     }
 }
diff --git a/src/tools/miri/src/intptrcast.rs b/src/tools/miri/src/intptrcast.rs
index c26828b11e0..618cf9df7f3 100644
--- a/src/tools/miri/src/intptrcast.rs
+++ b/src/tools/miri/src/intptrcast.rs
@@ -51,12 +51,12 @@ impl VisitTags for GlobalStateInner {
 }
 
 impl GlobalStateInner {
-    pub fn new(config: &MiriConfig) -> Self {
+    pub fn new(config: &MiriConfig, stack_addr: u64) -> Self {
         GlobalStateInner {
             int_to_ptr_map: Vec::default(),
             base_addr: FxHashMap::default(),
             exposed: FxHashSet::default(),
-            next_base_addr: STACK_ADDR,
+            next_base_addr: stack_addr,
             provenance_mode: config.provenance_mode,
         }
     }
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 42519797976..d65bd10e6ff 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -107,7 +107,7 @@ pub use crate::helpers::EvalContextExt as _;
 pub use crate::intptrcast::ProvenanceMode;
 pub use crate::machine::{
     AllocExtra, FrameExtra, MiriInterpCx, MiriInterpCxExt, MiriMachine, MiriMemoryKind,
-    PrimitiveLayouts, Provenance, ProvenanceExtra, PAGE_SIZE, STACK_ADDR, STACK_SIZE,
+    PrimitiveLayouts, Provenance, ProvenanceExtra,
 };
 pub use crate::mono_hash_map::MonoHashMap;
 pub use crate::operator::EvalContextExt as _;
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 5d43df9cf1f..72f71db34b6 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -31,11 +31,6 @@ use crate::{
     *,
 };
 
-// Some global facts about the emulated machine.
-pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture
-pub const STACK_ADDR: u64 = 32 * PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations
-pub const STACK_SIZE: u64 = 16 * PAGE_SIZE; // whatever
-
 /// Extra data stored with each stack frame
 pub struct FrameExtra<'tcx> {
     /// Extra data for Stacked Borrows.
@@ -469,6 +464,10 @@ pub struct MiriMachine<'mir, 'tcx> {
     pub(crate) since_gc: u32,
     /// The number of CPUs to be reported by miri.
     pub(crate) num_cpus: u32,
+    /// Determines Miri's page size and associated values
+    pub(crate) page_size: u64,
+    pub(crate) stack_addr: u64,
+    pub(crate) stack_size: u64,
 }
 
 impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
@@ -482,11 +481,31 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
         let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
         let borrow_tracker = config.borrow_tracker.map(|bt| bt.instanciate_global_state(config));
         let data_race = config.data_race_detector.then(|| data_race::GlobalState::new(config));
+        let page_size = if let Some(page_size) = config.page_size {
+            page_size
+        } else {
+            let target = &layout_cx.tcx.sess.target;
+            match target.arch.as_ref() {
+                "wasm32" | "wasm64" => 64 * 1024, // https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances
+                "aarch64" =>
+                    if target.options.vendor.as_ref() == "apple" {
+                        // No "definitive" source, but see:
+                        // https://www.wwdcnotes.com/notes/wwdc20/10214/
+                        // https://github.com/ziglang/zig/issues/11308 etc.
+                        16 * 1024
+                    } else {
+                        4 * 1024
+                    },
+                _ => 4 * 1024,
+            }
+        };
+        let stack_addr = page_size * 32;
+        let stack_size = page_size * 16;
         MiriMachine {
             tcx: layout_cx.tcx,
             borrow_tracker,
             data_race,
-            intptrcast: RefCell::new(intptrcast::GlobalStateInner::new(config)),
+            intptrcast: RefCell::new(intptrcast::GlobalStateInner::new(config, stack_addr)),
             // `env_vars` depends on a full interpreter so we cannot properly initialize it yet.
             env_vars: EnvVars::default(),
             main_fn_ret_place: None,
@@ -548,6 +567,9 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
             gc_interval: config.gc_interval,
             since_gc: 0,
             num_cpus: config.num_cpus,
+            page_size,
+            stack_addr,
+            stack_size,
         }
     }
 
@@ -692,6 +714,9 @@ impl VisitTags for MiriMachine<'_, '_> {
             gc_interval: _,
             since_gc: _,
             num_cpus: _,
+            page_size: _,
+            stack_addr: _,
+            stack_size: _,
         } = self;
 
         threads.visit_tags(visit);
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index d746f9df90a..e851d6d5139 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -234,7 +234,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 // FIXME: Which of these are POSIX, and which are GNU/Linux?
                 // At least the names seem to all also exist on macOS.
                 let sysconfs: &[(&str, fn(&MiriInterpCx<'_, '_>) -> Scalar<Provenance>)] = &[
-                    ("_SC_PAGESIZE", |this| Scalar::from_int(PAGE_SIZE, this.pointer_size())),
+                    ("_SC_PAGESIZE", |this| Scalar::from_int(this.machine.page_size, this.pointer_size())),
                     ("_SC_NPROCESSORS_CONF", |this| Scalar::from_int(this.machine.num_cpus, this.pointer_size())),
                     ("_SC_NPROCESSORS_ONLN", |this| Scalar::from_int(this.machine.num_cpus, this.pointer_size())),
                     // 512 seems to be a reasonable default. The value is not critical, in
@@ -496,7 +496,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let [_attr, guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let guard_size = this.deref_operand(guard_size)?;
                 let guard_size_layout = this.libc_ty_layout("size_t")?;
-                this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), &guard_size.into())?;
+                this.write_scalar(Scalar::from_uint(this.machine.page_size, guard_size_layout.size), &guard_size.into())?;
 
                 // Return success (`0`).
                 this.write_null(dest)?;
@@ -525,11 +525,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let size_place = this.deref_operand(size_place)?;
 
                 this.write_scalar(
-                    Scalar::from_uint(STACK_ADDR, this.pointer_size()),
+                    Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
                     &addr_place.into(),
                 )?;
                 this.write_scalar(
-                    Scalar::from_uint(STACK_SIZE, this.pointer_size()),
+                    Scalar::from_uint(this.machine.stack_size, this.pointer_size()),
                     &size_place.into(),
                 )?;
 
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index 221dc39697f..282bfc8024f 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -162,13 +162,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             "pthread_get_stackaddr_np" => {
                 let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 this.read_scalar(thread)?.to_machine_usize(this)?;
-                let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size());
+                let stack_addr = Scalar::from_uint(this.machine.stack_addr, this.pointer_size());
                 this.write_scalar(stack_addr, dest)?;
             }
             "pthread_get_stacksize_np" => {
                 let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 this.read_scalar(thread)?.to_machine_usize(this)?;
-                let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size());
+                let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size());
                 this.write_scalar(stack_size, dest)?;
             }
 
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index e16749c986b..05ce81b71a4 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -158,7 +158,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 // Set page size.
                 let page_size = system_info.offset(field_offsets[2], dword_layout, &this.tcx)?;
                 this.write_scalar(
-                    Scalar::from_int(PAGE_SIZE, dword_layout.size),
+                    Scalar::from_int(this.machine.page_size, dword_layout.size),
                     &page_size.into(),
                 )?;
                 // Set number of processors.
diff --git a/src/tools/miri/tests/pass-dep/page_size.rs b/src/tools/miri/tests/pass-dep/page_size.rs
index cdcabf33338..fb060317538 100644
--- a/src/tools/miri/tests/pass-dep/page_size.rs
+++ b/src/tools/miri/tests/pass-dep/page_size.rs
@@ -3,4 +3,17 @@ fn main() {
 
     // In particular, this checks that it is not 0.
     assert!(page_size.is_power_of_two(), "page size not a power of two: {}", page_size);
+    // Most architectures have 4k pages by default
+    #[cfg(not(any(
+        target_arch = "wasm32",
+        target_arch = "wasm64",
+        all(target_arch = "aarch64", target_vendor = "apple")
+    )))]
+    assert!(page_size == 4 * 1024, "non-4k default page size: {}", page_size);
+    // ... except aarch64-apple with 16k
+    #[cfg(all(target_arch = "aarch64", target_vendor = "apple"))]
+    assert!(page_size == 16 * 1024, "aarch64 apple reports non-16k page size: {}", page_size);
+    // ... and wasm with 64k
+    #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
+    assert!(page_size == 64 * 1024, "wasm reports non-64k page size: {}", page_size);
 }
diff --git a/src/tools/miri/tests/pass-dep/page_size_override.rs b/src/tools/miri/tests/pass-dep/page_size_override.rs
new file mode 100644
index 00000000000..68858f38759
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/page_size_override.rs
@@ -0,0 +1,7 @@
+//@compile-flags: -Zmiri-force-page-size=8
+
+fn main() {
+    let page_size = page_size::get();
+
+    assert!(page_size == 8 * 1024, "8k page size override not respected: {}", page_size);
+}