fix(ci): skip mimalloc FFI and disable isolation for Miri (#621)

- Add cfg(not(miri)) guards to mimalloc module, global allocator, and
  allocator-memory-limits code paths so Miri falls back to the default
  system allocator instead of calling unsupported FFI functions.
- Set MIRIFLAGS="-Zmiri-disable-isolation" in the workflow so tests
  that perform file I/O can run under Miri.
- Skip units/parse tests under Miri due to Float-vs-BigInt Number
  representation mismatch with Miri's soft-float emulation.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
Anand Krishnamoorthi
2026-03-11 15:13:51 -05:00
committed by GitHub
parent b8e15f46f3
commit ee3dff9a3d
9 changed files with 34 additions and 19 deletions

View File

@@ -10,6 +10,8 @@ jobs:
miri-test:
name: miri (nightly)
runs-on: ubuntu-latest
env:
MIRIFLAGS: "-Zmiri-disable-isolation"
steps:
- name: Checkout repository
uses: actions/checkout@v4

View File

@@ -1,25 +1,25 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#[cfg(not(any(target_family = "wasm")))]
#[cfg(not(any(target_family = "wasm", miri)))]
pub mod mimalloc;
#[cfg(feature = "allocator-memory-limits")]
#[cfg(not(any(target_family = "wasm")))]
#[cfg(not(any(target_family = "wasm", miri)))]
pub use mimalloc::{
allocation_stats_snapshot, current_thread_allocation_stats, global_allocation_stats_snapshot,
GlobalAllocationStats, ThreadAllocationStats,
};
#[cfg(feature = "allocator-memory-limits")]
#[cfg(not(any(target_family = "wasm")))]
#[cfg(not(any(target_family = "wasm", miri)))]
pub mod limits;
/// Declare a global allocator if the platform supports it.
#[macro_export]
macro_rules! assign_global {
() => {
#[cfg(not(any(target_family = "wasm")))]
#[cfg(not(any(target_family = "wasm", miri)))]
#[global_allocator]
static GLOBAL: mimalloc::mimalloc::Mimalloc = mimalloc::mimalloc::Mimalloc;
};

View File

@@ -402,13 +402,13 @@ impl Interpreter {
self.reset_execution_timer_state();
}
#[cfg(feature = "allocator-memory-limits")]
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
fn memory_check(&mut self) -> Result<()> {
let _ = self; // quiet clippy::unused_self; retained for symmetry with VM path
crate::utils::limits::check_memory_limit_if_needed().map_err(|err| anyhow!(err))
}
#[cfg(not(feature = "allocator-memory-limits"))]
#[cfg(any(miri, not(feature = "allocator-memory-limits")))]
const fn memory_check(&mut self) -> Result<()> {
let _ = self; // quiet clippy::unused_self; retained for symmetry with VM path
Ok(())

View File

@@ -167,7 +167,7 @@ pub use engine::Engine;
pub use lexer::Source;
pub use policy_info::PolicyInfo;
pub use utils::limits::LimitError;
#[cfg(feature = "allocator-memory-limits")]
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
pub use utils::limits::{
check_global_memory_limit, enforce_memory_limit, flush_thread_memory_counters,
global_memory_limit, set_global_memory_limit, set_thread_flush_threshold_override,

View File

@@ -2,7 +2,7 @@
// Licensed under the MIT License.
use crate::rvm::program::Program;
#[cfg(feature = "allocator-memory-limits")]
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
use crate::utils::limits;
use crate::utils::limits::{
fallback_execution_timer_config, monotonic_now, ExecutionTimer, ExecutionTimerConfig,
@@ -11,7 +11,7 @@ use crate::utils::limits::{
use crate::value::Value;
use crate::CompiledPolicy;
use alloc::collections::{btree_map::Entry, BTreeMap, VecDeque};
#[cfg(feature = "allocator-memory-limits")]
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
use alloc::format;
use alloc::string::String;
use alloc::sync::Arc;
@@ -467,7 +467,7 @@ impl RegoVM {
Ok(())
}
#[cfg(feature = "allocator-memory-limits")]
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
pub(super) fn memory_check(&mut self) -> Result<()> {
limits::check_memory_limit_if_needed().map_err(|err| match err {
LimitError::MemoryLimitExceeded { usage, limit } => VmError::MemoryLimitExceeded {
@@ -482,7 +482,7 @@ impl RegoVM {
})
}
#[cfg(not(feature = "allocator-memory-limits"))]
#[cfg(any(miri, not(feature = "allocator-memory-limits")))]
pub(super) fn memory_check(&mut self) -> Result<()> {
Ok(())
}

View File

@@ -620,6 +620,19 @@ fn yaml_test_impl(file: &str) -> Result<()> {
}
}
#[cfg(miri)]
{
// Skip tests with large-exponent Number comparisons that hit a
// Float-vs-BigInt representation mismatch under Miri's soft-float.
let skip = ["units/parse.yaml", "units/parse_bytes.yaml"];
for s in skip {
if file.contains(s) {
std::println!("skipped {file} under miri.");
return Ok(());
}
}
}
std::println!("running {file}");
let v0 = !file.contains("bindings.yaml");

View File

@@ -6,7 +6,7 @@
#![allow(dead_code)]
mod error;
#[cfg(feature = "allocator-memory-limits")]
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
mod memory;
mod time;
@@ -14,7 +14,7 @@ mod time;
pub use error::LimitError;
#[allow(unused_imports)]
#[cfg(feature = "allocator-memory-limits")]
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
pub use memory::{
check_global_memory_limit, enforce_memory_limit, flush_thread_memory_counters,
global_memory_limit, set_global_memory_limit, set_thread_flush_threshold_override,
@@ -34,19 +34,19 @@ pub use time::acquire_limits_test_lock;
#[allow(unused_imports)]
pub use time::{set_time_source, TimeSourceRegistrationError};
#[cfg(feature = "allocator-memory-limits")]
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
#[inline]
pub fn check_memory_limit_if_needed() -> core::result::Result<(), LimitError> {
memory::check_memory_limit_if_needed()
}
#[cfg(not(feature = "allocator-memory-limits"))]
#[cfg(any(miri, not(feature = "allocator-memory-limits")))]
#[inline]
pub const fn enforce_memory_limit() -> core::result::Result<(), LimitError> {
Ok(())
}
#[cfg(not(feature = "allocator-memory-limits"))]
#[cfg(any(miri, not(feature = "allocator-memory-limits")))]
#[inline]
pub const fn check_memory_limit_if_needed() -> core::result::Result<(), LimitError> {
Ok(())

View File

@@ -353,7 +353,7 @@ impl Value {
match serde_json::from_str::<Value>(json) {
Ok(value) => Ok(value),
Err(err) => {
#[cfg(feature = "allocator-memory-limits")]
#[cfg(all(feature = "allocator-memory-limits", not(miri)))]
{
// Re-validate allocator limits when serde parsing fails to surface LimitError.
match crate::utils::limits::check_global_memory_limit() {
@@ -362,7 +362,7 @@ impl Value {
}
}
#[cfg(not(feature = "allocator-memory-limits"))]
#[cfg(any(miri, not(feature = "allocator-memory-limits")))]
{
Err(anyhow!(err))
}

View File

@@ -1,4 +1,4 @@
#![cfg(all(feature = "mimalloc", feature = "allocator-memory-limits"))]
#![cfg(all(feature = "mimalloc", feature = "allocator-memory-limits", not(miri)))]
use std::sync::{Mutex, OnceLock};