Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/base/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ RUN rm src/*.rs
COPY --from=build-orchestrator /playground/.cargo/bin/worker /playground/.cargo/bin/worker
COPY --from=wasm-tools /playground/.cargo/bin/wasm-tools /playground/.cargo/bin
COPY --chown=playground cargo-wasm /playground/.cargo/bin
# `cargo-miri-playground` is vestigial and can be removed after a while
COPY --chown=playground cargo-miri-playground /playground/.cargo/bin

ENTRYPOINT ["/playground/tools/entrypoint.sh"]
66 changes: 60 additions & 6 deletions compiler/base/orchestrator/src/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ use crate::{
DropErrorDetailsExt, TaskAbortExt as _,
};

macro_rules! kvs {
($($k:expr => $v:expr),+$(,)?) => {
[
$((Into::into($k), Into::into($v)),)+
].into_iter()
};
}

pub mod limits;

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -393,7 +401,7 @@ impl LowerRequest for ExecuteRequest {

let mut envs = HashMap::new();
if self.backtrace {
envs.insert("RUST_BACKTRACE".to_owned(), "1".to_owned());
envs.extend(kvs!("RUST_BACKTRACE" => "1"));
}

ExecuteCommandRequest {
Expand Down Expand Up @@ -522,7 +530,7 @@ impl LowerRequest for CompileRequest {
}
let mut envs = HashMap::new();
if self.backtrace {
envs.insert("RUST_BACKTRACE".to_owned(), "1".to_owned());
envs.extend(kvs!("RUST_BACKTRACE" => "1"));
}

ExecuteCommandRequest {
Expand Down Expand Up @@ -660,6 +668,7 @@ pub struct MiriRequest {
pub channel: Channel,
pub crate_type: CrateType,
pub edition: Edition,
pub tests: bool,
pub aliasing_model: AliasingModel,
pub code: String,
}
Expand All @@ -680,12 +689,25 @@ impl LowerRequest for MiriRequest {
miriflags.push("-Zmiri-tree-borrows");
}

miriflags.push("-Zmiri-disable-isolation");

let miriflags = miriflags.join(" ");

let subcommand = if self.tests { "test" } else { "run" };

ExecuteCommandRequest {
cmd: "cargo".to_owned(),
args: vec!["miri-playground".to_owned()],
envs: HashMap::from_iter([("MIRIFLAGS".to_owned(), miriflags)]),
args: ["miri", subcommand].map(Into::into).into(),
envs: kvs! {
"MIRIFLAGS" => miriflags,
// Be sure that `cargo miri` will not build a new
// sysroot. Creating a sysroot takes a while and Miri
// will build one by default if it's missing. If
// `MIRI_SYSROOT` is set and the sysroot is missing,
// it will error instead.
"MIRI_SYSROOT" => "/playground/.cache/miri",
}
.collect(),
cwd: None,
}
}
Expand Down Expand Up @@ -1802,6 +1824,8 @@ impl Container {
.await
.context(AcquirePermitSnafu)?;

trace!(?execute_cargo, "starting cargo task");

let (stdin_tx, mut stdin_rx) = mpsc::channel(8);
let (stdout_tx, stdout_rx) = mpsc::channel(8);
let (stderr_tx, stderr_rx) = mpsc::channel(8);
Expand Down Expand Up @@ -3954,15 +3978,15 @@ mod tests {
channel: Channel::Nightly,
crate_type: CrateType::Binary,
edition: Edition::Rust2021,
tests: false,
aliasing_model: AliasingModel::Stacked,
code: String::new(),
};

#[tokio::test]
#[snafu::report]
async fn miri() -> Result<()> {
// cargo-miri-playground only exists inside the container
let coordinator = new_coordinator_docker();
let coordinator = new_coordinator();

let req = MiriRequest {
code: r#"
Expand All @@ -3987,6 +4011,36 @@ mod tests {
Ok(())
}

#[tokio::test]
#[snafu::report]
async fn miri_tests() -> Result<()> {
let coordinator = new_coordinator();

let req = MiriRequest {
tests: true,
code: r#"
#[test]
fn oops() {
unsafe { core::mem::MaybeUninit::<u8>::uninit().assume_init() };
}
"#
.into(),
..ARBITRARY_MIRI_REQUEST
};

let response = coordinator.miri(req).with_timeout().await.unwrap();

assert!(!response.success, "stderr: {}", response.stderr);

assert_contains!(response.stderr, "Undefined Behavior");
assert_contains!(response.stderr, "using uninitialized data");
assert_contains!(response.stderr, "operation requires initialized memory");

coordinator.shutdown().await?;

Ok(())
}

const ARBITRARY_MACRO_EXPANSION_REQUEST: MacroExpansionRequest = MacroExpansionRequest {
channel: Channel::Nightly,
crate_type: CrateType::Library(LibraryType::Cdylib),
Expand Down
5 changes: 4 additions & 1 deletion ui/frontend/ToolsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ const ToolsMenu: React.FC<ToolsMenuProps> = props => {
const nightlyVersion = useAppSelector(selectors.nightlyVersionText);
const nightlyVersionDetails = useAppSelector(selectors.nightlyVersionDetailsText);

const miriRunningTests = useAppSelector(selectors.runAsTest);
const miriText = miriRunningTests ? "these tests" : "this program";

const dispatch = useAppDispatch();
const clippy = useCallback(() => {
dispatch(performClippy());
Expand Down Expand Up @@ -62,7 +65,7 @@ const ToolsMenu: React.FC<ToolsMenuProps> = props => {
name="Miri"
onClick={miri}>
<div>
Execute this program in the Miri interpreter to detect certain
Execute {miriText} in the Miri interpreter to detect certain
cases of undefined behavior (like out-of-bounds memory access).
</div>
<MenuAside>{miriVersion} ({miriVersionDetails})</MenuAside>
Expand Down
1 change: 1 addition & 0 deletions ui/frontend/reducers/output/miri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface State {
interface MiriRequestBody {
code: string;
edition: string;
tests: boolean;
aliasingModel: AliasingModel;
}

Expand Down
5 changes: 3 additions & 2 deletions ui/frontend/selectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,10 @@ export const formatRequestSelector = createSelector(

export const miriRequestSelector = createSelector(
editionSelector,
codeSelector,
runAsTest,
aliasingModelSelector,
(edition, code, aliasingModel) => ({ edition, code, aliasingModel }),
codeSelector,
(edition, tests, aliasingModel, code, ) => ({ edition, tests, aliasingModel, code }),
);

export const macroExpansionRequestSelector = createSelector(
Expand Down
3 changes: 2 additions & 1 deletion ui/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ impl HasLabelsCore for coordinator::MiriRequest {
channel,
crate_type,
edition,
tests,
aliasing_model: _,
code: _,
} = *self;
Expand All @@ -371,7 +372,7 @@ impl HasLabelsCore for coordinator::MiriRequest {
mode: None,
edition: Some(Some(edition)),
crate_type: Some(crate_type),
tests: None,
tests: Some(tests),
backtrace: None,
}
}
Expand Down
2 changes: 2 additions & 0 deletions ui/src/public_http_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ pub(crate) struct MiriRequest {
pub(crate) code: String,
#[serde(default)]
pub(crate) edition: String,
#[serde(default)]
pub(crate) tests: bool,
#[serde(default, rename = "aliasingModel")]
pub(crate) aliasing_model: Option<String>,
}
Expand Down
2 changes: 2 additions & 0 deletions ui/src/server_axum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,7 @@ pub(crate) mod api_orchestrator_integration_impls {
let api::MiriRequest {
code,
edition,
tests,
aliasing_model,
} = other;

Expand All @@ -1300,6 +1301,7 @@ pub(crate) mod api_orchestrator_integration_impls {
channel: Channel::Nightly, // TODO: use what user has submitted
crate_type: CrateType::Binary, // TODO: use what user has submitted
edition: parse_edition(&edition)?,
tests,
aliasing_model,
code,
})
Expand Down
Loading