Skip to content

Commit 7c4f574

Browse files
Allow user to specify aliasing model for Miri
Co-authored-by: Jake Goulding <[email protected]>
1 parent 7c63473 commit 7c4f574

File tree

11 files changed

+154
-31
lines changed

11 files changed

+154
-31
lines changed

compiler/base/cargo-miri-playground

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
set -eu
44

55
export MIRI_SYSROOT=~/.cache/miri
6-
export MIRIFLAGS="-Zmiri-disable-isolation"
6+
export MIRIFLAGS="${MIRIFLAGS:-} -Zmiri-disable-isolation"
77
exec cargo miri run

compiler/base/orchestrator/src/coordinator.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,12 @@ pub enum Channel {
239239
Nightly,
240240
}
241241

242+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
243+
pub enum AliasingModel {
244+
Stacked,
245+
Tree,
246+
}
247+
242248
impl Channel {
243249
#[cfg(test)]
244250
pub(crate) const ALL: [Self; 3] = [Self::Stable, Self::Beta, Self::Nightly];
@@ -654,6 +660,7 @@ pub struct MiriRequest {
654660
pub channel: Channel,
655661
pub crate_type: CrateType,
656662
pub edition: Edition,
663+
pub aliasing_model: AliasingModel,
657664
pub code: String,
658665
}
659666

@@ -667,10 +674,18 @@ impl LowerRequest for MiriRequest {
667674
}
668675

669676
fn execute_cargo_request(&self) -> ExecuteCommandRequest {
677+
let mut miriflags = Vec::new();
678+
679+
if matches!(self.aliasing_model, AliasingModel::Tree) {
680+
miriflags.push("-Zmiri-tree-borrows");
681+
}
682+
683+
let miriflags = miriflags.join(" ");
684+
670685
ExecuteCommandRequest {
671686
cmd: "cargo".to_owned(),
672687
args: vec!["miri-playground".to_owned()],
673-
envs: Default::default(),
688+
envs: HashMap::from_iter([("MIRIFLAGS".to_owned(), miriflags)]),
674689
cwd: None,
675690
}
676691
}
@@ -3939,6 +3954,7 @@ mod tests {
39393954
channel: Channel::Nightly,
39403955
crate_type: CrateType::Binary,
39413956
edition: Edition::Rust2021,
3957+
aliasing_model: AliasingModel::Stacked,
39423958
code: String::new(),
39433959
};
39443960

tests/spec/features/tools_spec.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,30 @@ def code_with_undefined_behavior
5454
EOF
5555
end
5656

57+
scenario "configure Miri for tree borrows" do
58+
editor.set code_valid_under_tree_borrows_but_not_stacked_borrows
59+
in_advanced_options_menu { choose("tree") }
60+
in_tools_menu { click_on("Miri") }
61+
62+
within(:output, :stdout) do
63+
expect(page).to have_content %r{[1, 2]}, wait: 10
64+
end
65+
66+
within(:output, :stderr) do
67+
expect(page).to_not have_content %r{Undefined Behavior}
68+
end
69+
end
70+
71+
def code_valid_under_tree_borrows_but_not_stacked_borrows
72+
<<~EOF
73+
fn main() {
74+
let val = [1u8, 2];
75+
let ptr = &val[0] as *const u8;
76+
let _val = unsafe { *ptr.add(1) };
77+
}
78+
EOF
79+
end
80+
5781
scenario "expand macros with the nightly compiler" do
5882
editor.set code_that_uses_macros
5983
in_tools_menu { click_on("Expand macros") }

ui/frontend/AdvancedOptionsMenu.tsx

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,29 @@
11
import React, { useCallback } from 'react';
22

33
import { Either as EitherConfig, Select as SelectConfig } from './ConfigElement';
4+
import MenuAside from './MenuAside';
45
import MenuGroup from './MenuGroup';
56
import { useAppDispatch, useAppSelector } from './hooks';
67
import * as config from './reducers/configuration';
78
import * as selectors from './selectors';
8-
import { Backtrace, Edition } from './types';
9+
import { AliasingModel, Backtrace, Edition } from './types';
10+
11+
const MIRI_TREE_BORROWS_URL = 'https://github.com/rust-lang/miri#user-content--zmiri-tree-borrows';
12+
13+
const TreeBorrowAside: React.FC = () => (
14+
<MenuAside>
15+
Code that is accepted by <a href={MIRI_TREE_BORROWS_URL}>Tree Borrows</a> may be declared
16+
undefined behavior in the future.
17+
</MenuAside>
18+
);
919

1020
const AdvancedOptionsMenu: React.FC = () => {
1121
const isEditionDefault = useAppSelector(selectors.isEditionDefault);
1222
const edition = useAppSelector((state) => state.configuration.edition);
1323
const isBacktraceDefault = useAppSelector(selectors.isBacktraceDefault);
1424
const backtrace = useAppSelector((state) => state.configuration.backtrace);
25+
const isAliasingModelDefault = useAppSelector(selectors.isAliasingModelDefault);
26+
const aliasingModel = useAppSelector((state) => state.configuration.aliasingModel);
1527

1628
const dispatch = useAppDispatch();
1729

@@ -20,33 +32,52 @@ const AdvancedOptionsMenu: React.FC = () => {
2032
(b: Backtrace) => dispatch(config.changeBacktrace(b)),
2133
[dispatch],
2234
);
35+
const changeAliasingModel = useCallback(
36+
(b: AliasingModel) => dispatch(config.changeAliasingModel(b)),
37+
[dispatch],
38+
);
2339

2440
return (
25-
<MenuGroup title="Advanced options">
26-
<SelectConfig
27-
name="Edition"
28-
value={edition}
29-
isDefault={isEditionDefault}
30-
onChange={changeEdition}
31-
>
32-
<option value={Edition.Rust2015}>2015</option>
33-
<option value={Edition.Rust2018}>2018</option>
34-
<option value={Edition.Rust2021}>2021</option>
35-
<option value={Edition.Rust2024}>2024</option>
36-
</SelectConfig>
37-
38-
<EitherConfig
39-
id="backtrace"
40-
name="Backtrace"
41-
a={Backtrace.Enabled}
42-
b={Backtrace.Disabled}
43-
aLabel="On"
44-
bLabel="Off"
45-
value={backtrace}
46-
isDefault={isBacktraceDefault}
47-
onChange={changeBacktrace}
48-
/>
49-
</MenuGroup>
41+
<>
42+
<MenuGroup title="Advanced options">
43+
<SelectConfig
44+
name="Edition"
45+
value={edition}
46+
isDefault={isEditionDefault}
47+
onChange={changeEdition}
48+
>
49+
<option value={Edition.Rust2015}>2015</option>
50+
<option value={Edition.Rust2018}>2018</option>
51+
<option value={Edition.Rust2021}>2021</option>
52+
<option value={Edition.Rust2024}>2024</option>
53+
</SelectConfig>
54+
55+
<EitherConfig
56+
id="backtrace"
57+
name="Backtrace"
58+
a={Backtrace.Enabled}
59+
b={Backtrace.Disabled}
60+
aLabel="On"
61+
bLabel="Off"
62+
value={backtrace}
63+
isDefault={isBacktraceDefault}
64+
onChange={changeBacktrace}
65+
/>
66+
</MenuGroup>
67+
68+
<MenuGroup title="Miri">
69+
<EitherConfig
70+
id="aliasingModel"
71+
name="Aliasing model"
72+
a={AliasingModel.Stacked}
73+
b={AliasingModel.Tree}
74+
value={aliasingModel}
75+
isDefault={isAliasingModelDefault}
76+
onChange={changeAliasingModel}
77+
aside={<TreeBorrowAside />}
78+
/>
79+
</MenuGroup>
80+
</>
5081
);
5182
};
5283

ui/frontend/reducers/configuration.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
22

33
import {
4+
AliasingModel,
45
AssemblyFlavor,
56
Backtrace,
67
Channel,
@@ -36,6 +37,7 @@ interface State {
3637
mode: Mode;
3738
edition: Edition;
3839
backtrace: Backtrace;
40+
aliasingModel: AliasingModel;
3941
}
4042

4143
const initialState: State = {
@@ -58,6 +60,7 @@ const initialState: State = {
5860
mode: Mode.Debug,
5961
edition: Edition.Rust2024,
6062
backtrace: Backtrace.Disabled,
63+
aliasingModel: AliasingModel.Stacked,
6164
};
6265

6366
const slice = createSlice({
@@ -76,6 +79,10 @@ const slice = createSlice({
7679
state.backtrace = action.payload;
7780
},
7881

82+
changeAliasingModel: (state, action: PayloadAction<AliasingModel>) => {
83+
state.aliasingModel = action.payload;
84+
},
85+
7986
changeChannel: (state, action: PayloadAction<Channel>) => {
8087
state.channel = action.payload;
8188
},
@@ -146,6 +153,7 @@ export const {
146153
changeAceTheme,
147154
changeAssemblyFlavor,
148155
changeBacktrace,
156+
changeAliasingModel,
149157
changeChannel,
150158
changeDemangleAssembly,
151159
changeEdition,

ui/frontend/reducers/output/miri.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as z from 'zod';
44
import { jsonPost, routes } from '../../api';
55
import { State as RootState } from '../../reducers';
66
import { miriRequestSelector } from '../../selectors';
7+
import { AliasingModel } from '../../types';
78

89
const sliceName = 'output/miri';
910

@@ -21,6 +22,7 @@ interface State {
2122
interface MiriRequestBody {
2223
code: string;
2324
edition: string;
25+
aliasingModel: AliasingModel;
2426
}
2527

2628
const MiriResponseBody = z.object({

ui/frontend/selectors/index.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
Backtrace,
77
Channel,
88
Edition,
9+
AliasingModel,
910
Focus,
1011
Orientation,
1112
PrimaryActionAuto,
@@ -147,6 +148,7 @@ export const rustfmtVersionDetailsText = createSelector(getRustfmt, versionDetai
147148
export const miriVersionDetailsText = createSelector(getMiri, versionDetails);
148149

149150
const editionSelector = (state: State) => state.configuration.edition;
151+
export const aliasingModelSelector = (state: State) => state.configuration.aliasingModel;
150152

151153
export const isNightlyChannel = createSelector(
152154
channelSelector,
@@ -181,8 +183,13 @@ export const isBacktraceDefault = (state: State) => (
181183

182184
export const getBacktraceSet = createSelector(isBacktraceDefault, (b) => !b);
183185

186+
export const isAliasingModelDefault = createSelector(
187+
aliasingModelSelector,
188+
aliasingModel => aliasingModel == AliasingModel.Stacked,
189+
);
190+
184191
export const getAdvancedOptionsSet = createSelector(
185-
isEditionDefault, isBacktraceDefault,
192+
isEditionDefault, isBacktraceDefault, isAliasingModelDefault,
186193
(...areDefault) => !areDefault.every(n => n),
187194
);
188195

@@ -391,7 +398,8 @@ export const formatRequestSelector = createSelector(
391398
export const miriRequestSelector = createSelector(
392399
editionSelector,
393400
codeSelector,
394-
(edition, code) => ({ edition, code }),
401+
aliasingModelSelector,
402+
(edition, code, aliasingModel) => ({ edition, code, aliasingModel }),
395403
);
396404

397405
export const macroExpansionRequestSelector = createSelector(

ui/frontend/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ export enum Backtrace {
150150
Enabled = 'enabled',
151151
}
152152

153+
export enum AliasingModel {
154+
Stacked = 'stacked',
155+
Tree = 'tree',
156+
}
157+
153158
export enum Focus {
154159
Clippy = 'clippy',
155160
Miri = 'miri',

ui/src/metrics.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ impl HasLabelsCore for coordinator::MiriRequest {
361361
channel,
362362
crate_type,
363363
edition,
364+
aliasing_model: _,
364365
code: _,
365366
} = *self;
366367

ui/src/public_http_api.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ pub(crate) struct MiriRequest {
103103
pub(crate) code: String,
104104
#[serde(default)]
105105
pub(crate) edition: String,
106+
#[serde(default, rename = "aliasingModel")]
107+
pub(crate) aliasing_model: Option<String>,
106108
}
107109

108110
#[derive(Debug, Clone, Serialize)]

ui/src/server_axum.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1285,12 +1285,22 @@ pub(crate) mod api_orchestrator_integration_impls {
12851285
type Error = ParseMiriRequestError;
12861286

12871287
fn try_from(other: api::MiriRequest) -> std::result::Result<Self, Self::Error> {
1288-
let api::MiriRequest { code, edition } = other;
1288+
let api::MiriRequest {
1289+
code,
1290+
edition,
1291+
aliasing_model,
1292+
} = other;
1293+
1294+
let aliasing_model = match aliasing_model {
1295+
Some(am) => parse_aliasing_model(&am)?,
1296+
None => AliasingModel::Stacked,
1297+
};
12891298

12901299
Ok(MiriRequest {
12911300
channel: Channel::Nightly, // TODO: use what user has submitted
12921301
crate_type: CrateType::Binary, // TODO: use what user has submitted
12931302
edition: parse_edition(&edition)?,
1303+
aliasing_model,
12941304
code,
12951305
})
12961306
}
@@ -1300,6 +1310,8 @@ pub(crate) mod api_orchestrator_integration_impls {
13001310
pub(crate) enum ParseMiriRequestError {
13011311
#[snafu(transparent)]
13021312
Edition { source: ParseEditionError },
1313+
#[snafu(transparent)]
1314+
AliasingMode { source: ParseAliasingModelError },
13031315
}
13041316

13051317
impl From<WithOutput<MiriResponse>> for api::MiriResponse {
@@ -1521,6 +1533,20 @@ pub(crate) mod api_orchestrator_integration_impls {
15211533
value: String,
15221534
}
15231535

1536+
pub(crate) fn parse_aliasing_model(s: &str) -> Result<AliasingModel, ParseAliasingModelError> {
1537+
Ok(match s {
1538+
"stacked" => AliasingModel::Stacked,
1539+
"tree" => AliasingModel::Tree,
1540+
value => return ParseAliasingModelSnafu { value }.fail(),
1541+
})
1542+
}
1543+
1544+
#[derive(Debug, Snafu)]
1545+
#[snafu(display("'{value}' is not a valid aliasing model"))]
1546+
pub(crate) struct ParseAliasingModelError {
1547+
value: String,
1548+
}
1549+
15241550
impl From<gist::Gist> for api::MetaGistResponse {
15251551
fn from(me: gist::Gist) -> Self {
15261552
api::MetaGistResponse {

0 commit comments

Comments
 (0)