Auto merge of #2158 - rust-lang:gesundheit, r=RalfJung

Avoid error patterns matching themselves

fixes #2156
fixes https://github.com/rust-lang/miri/issues/2155

this will be obsolete the moment I extract that data from json diagnostics instead of just regexing the stderr.
This commit is contained in:
bors 2022-05-30 07:52:48 +00:00
commit 065ff89e33
18 changed files with 428 additions and 20 deletions

5
miri
View file

@ -133,8 +133,9 @@ test|test-debug|bless|bless-debug)
;;
esac
# Then test, and let caller control flags.
# Only in root project as `cargo-miri` has no tests.
exec cargo test $CARGO_BUILD_FLAGS "$@"
# Only in root project and ui_test as `cargo-miri` has no tests.
cargo test $CARGO_BUILD_FLAGS "$@"
cargo test $CARGO_BUILD_FLAGS --manifest-path ui_test/Cargo.toml "$@"
;;
run|run-debug)
# Scan for "--target" to set the "MIRI_TEST_TARGET" env var so

View file

@ -9,5 +9,5 @@ fn main() {
let mut data = [0u16; 8];
let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16;
// Even copying 0 elements to something unaligned should error
unsafe { copy_nonoverlapping(&data[5], ptr, 0); } //~ ERROR accessing memory with alignment ALIGN, but alignment ALIGN is required
unsafe { copy_nonoverlapping(&data[5], ptr, 0); } //~ ERROR accessing memory with alignment 1, but alignment 2 is required
}

View file

@ -3,6 +3,6 @@ static X: usize = 5;
#[allow(mutable_transmutes)]
fn main() {
let _x = unsafe {
std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to ALLOC which is read-only
std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to alloc1 which is read-only
};
}

View file

@ -16,6 +16,6 @@ fn main() {
// Overwrite the data part of `ptr` so it points to `buf`.
unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); }
// Re-borrow that. This should be UB.
let _ptr = &*ptr; //~ERROR alignment ALIGN is required
let _ptr = &*ptr; //~ERROR alignment 256 is required
}
}

View file

@ -12,6 +12,6 @@ fn main() {
// Manually make sure the pointer is properly aligned.
let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 };
let u16_ptr = base_addr_aligned as *mut u16;
unsafe { *u16_ptr = 2; } //~ERROR memory with alignment ALIGN, but alignment ALIGN is required
unsafe { *u16_ptr = 2; } //~ERROR memory with alignment 1, but alignment 2 is required
println!("{:?}", x);
}

View file

@ -16,6 +16,6 @@ fn main() {
y: 99,
};
let p = &foo.x;
let i = *p; //~ERROR alignment ALIGN is required
let i = *p; //~ERROR alignment 4 is required
}
}

View file

@ -6,6 +6,6 @@ fn main() {
let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error.
let x = &x[0] as *const _ as *const u32;
// This must fail because alignment is violated: the allocation's base is not sufficiently aligned.
let _x = unsafe { *x }; //~ERROR memory with alignment ALIGN, but alignment ALIGN is required
let _x = unsafe { *x }; //~ERROR memory with alignment 2, but alignment 4 is required
}
}

View file

@ -8,5 +8,5 @@ fn main() {
let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32;
// This must fail because alignment is violated: the offset is not sufficiently aligned.
// Also make the offset not a power of 2, that used to ICE.
let _x = unsafe { *x }; //~ERROR memory with alignment ALIGN, but alignment ALIGN is required
let _x = unsafe { *x }; //~ERROR memory with alignment 1, but alignment 4 is required
}

View file

@ -8,6 +8,6 @@ fn main() {
let x = &x[0] as *const _ as *const u32;
// This must fail because alignment is violated: the allocation's base is not sufficiently aligned.
// The deref is UB even if we just put the result into a raw pointer.
let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR memory with alignment ALIGN, but alignment ALIGN is required
let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required
}
}

View file

@ -7,6 +7,6 @@ fn main() {
let x = i as u8;
let x = &x as *const _ as *const [u32; 0];
// This must fail because alignment is violated. Test specifically for loading ZST.
let _x = unsafe { *x }; //~ERROR alignment ALIGN is required
let _x = unsafe { *x }; //~ERROR alignment 4 is required
}
}

View file

@ -3,5 +3,5 @@
use std::mem;
fn main() {
let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated)
let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated)
}

View file

@ -1,6 +1,6 @@
fn main() {
assert!(std::char::from_u32(-1_i32 as u32).is_none());
let _val = match unsafe { std::mem::transmute::<i32, char>(-1) } { //~ ERROR encountered $HEX, but expected a valid unicode scalar value
let _val = match unsafe { std::mem::transmute::<i32, char>(-1) } { //~ ERROR encountered 0xffffffff, but expected a valid unicode scalar value
'a' => {true},
'b' => {false},
_ => {true},

View file

@ -47,6 +47,8 @@ fn run_tests(mode: Mode, path: &str, target: Option<String>) {
(true, true) => panic!("cannot use MIRI_BLESS and MIRI_SKIP_UI_CHECKS at the same time"),
};
let path_filter = std::env::args().skip(1).next();
let config = Config {
args: flags,
target,
@ -54,6 +56,7 @@ fn run_tests(mode: Mode, path: &str, target: Option<String>) {
stdout_filters: STDOUT.clone(),
root_dir: PathBuf::from(path),
mode,
path_filter,
program: miri_path(),
output_conflict_handling,
};

304
ui_test/Cargo.lock generated Normal file
View file

@ -0,0 +1,304 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "colored"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
dependencies = [
"atty",
"lazy_static",
"winapi",
]
[[package]]
name = "crossbeam"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845"
dependencies = [
"cfg-if",
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-epoch",
"crossbeam-queue",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"lazy_static",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-queue"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
dependencies = [
"cfg-if",
"lazy_static",
]
[[package]]
name = "ctor"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "diff"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "output_vt100"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
dependencies = [
"winapi",
]
[[package]]
name = "pretty_assertions"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563"
dependencies = [
"ansi_term",
"ctor",
"diff",
"output_vt100",
]
[[package]]
name = "proc-macro2"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "semver"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd"
[[package]]
name = "syn"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "ui_test"
version = "0.1.0"
dependencies = [
"colored",
"crossbeam",
"lazy_static",
"pretty_assertions",
"regex",
"rustc_version",
]
[[package]]
name = "unicode-ident"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View file

@ -2,11 +2,14 @@ use std::path::Path;
use regex::Regex;
#[cfg(test)]
mod tests;
/// This crate supports various magic comments that get parsed as file-specific
/// configuration values. This struct parses them all in one go and then they
/// get processed by their respective use sites.
#[derive(Default)]
pub struct Comments {
#[derive(Default, Debug)]
pub(crate) struct Comments {
/// List of revision names to execute. Can only be speicified once
pub revisions: Option<Vec<String>>,
/// Don't run this test if any of these filters apply
@ -26,16 +29,23 @@ pub struct Comments {
pub error_matches: Vec<ErrorMatch>,
}
pub struct ErrorMatch {
#[derive(Debug)]
pub(crate) struct ErrorMatch {
pub matched: String,
pub revision: Option<String>,
pub definition_line: usize,
}
impl Comments {
pub fn parse(path: &Path) -> Self {
let mut this = Self::default();
pub(crate) fn parse_file(path: &Path) -> Self {
let content = std::fs::read_to_string(path).unwrap();
Self::parse(path, &content)
}
/// Parse comments in `content`.
/// `path` is only used to emit diagnostics if parsing fails.
pub(crate) fn parse(path: &Path, content: &str) -> Self {
let mut this = Self::default();
let error_pattern_regex =
Regex::new(r"//(\[(?P<revision>[^\]]+)\])?~[|^]*\s*(ERROR|HELP|WARN)?:?(?P<text>.*)")
.unwrap();

View file

@ -0,0 +1,22 @@
use std::path::Path;
use super::Comments;
#[test]
fn parse_simple_comment() {
let s = r"
use std::mem;
fn main() {
let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated)
}
";
let comments = Comments::parse(Path::new("<dummy>"), s);
println!("parsed comments: {:#?}", comments);
assert_eq!(comments.error_matches[0].definition_line, 4);
assert_eq!(comments.error_matches[0].revision, None);
assert_eq!(
comments.error_matches[0].matched,
"encountered a dangling reference (address $HEX is unallocated)"
);
}

View file

@ -12,6 +12,8 @@ use regex::Regex;
use crate::comments::Comments;
mod comments;
#[cfg(test)]
mod tests;
#[derive(Debug)]
pub struct Config {
@ -28,6 +30,8 @@ pub struct Config {
pub mode: Mode,
pub program: PathBuf,
pub output_conflict_handling: OutputConflictHandling,
/// Only run tests with this string in their path/name
pub path_filter: Option<String>,
}
#[derive(Debug)]
@ -73,7 +77,18 @@ pub fn run_tests(config: Config) {
if !path.extension().map(|ext| ext == "rs").unwrap_or(false) {
continue;
}
let comments = Comments::parse(&path);
if let Some(path_filter) = &config.path_filter {
if !path.display().to_string().contains(path_filter) {
ignored.fetch_add(1, Ordering::Relaxed);
eprintln!(
"{} .. {}",
path.display(),
"ignored (command line filter)".yellow()
);
continue;
}
}
let comments = Comments::parse_file(&path);
// Ignore file if only/ignore rules do (not) apply
if ignore_file(&comments, &target) {
ignored.fetch_add(1, Ordering::Relaxed);
@ -129,7 +144,7 @@ pub fn run_tests(config: Config) {
eprintln!("`{pattern}` {} in stderr output", "not found".red());
eprintln!(
"expected because of pattern here: {}:{definition_line}",
path.display()
path.display().to_string().bold()
);
dump_stderr = Some(stderr.clone())
}
@ -257,6 +272,9 @@ fn check_annotations(
comments: &Comments,
) {
let unnormalized_stderr = std::str::from_utf8(unnormalized_stderr).unwrap();
// erase annotations from the stderr so they don't match themselves
let annotations = Regex::new(r"\s*//~.*").unwrap();
let unnormalized_stderr = annotations.replace(unnormalized_stderr, "");
let mut found_annotation = false;
if let Some((ref error_pattern, definition_line)) = comments.error_pattern {
if !unnormalized_stderr.contains(error_pattern) {

50
ui_test/src/tests.rs Normal file
View file

@ -0,0 +1,50 @@
use std::path::{Path, PathBuf};
use super::{check_annotations, Comments, Config, Error, Mode, OutputConflictHandling};
fn config() -> Config {
Config {
args: vec![],
target: None,
stderr_filters: vec![],
stdout_filters: vec![],
root_dir: PathBuf::from("."),
mode: Mode::Fail,
path_filter: None,
program: PathBuf::from("cake"),
output_conflict_handling: OutputConflictHandling::Error,
}
}
#[test]
fn issue_2156() {
let s = r"
use std::mem;
fn main() {
let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated)
}
";
let comments = Comments::parse(Path::new("<dummy>"), s);
let mut errors = vec![];
let config = config();
let unnormalized_stderr = r"
error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)
--> tests/compile-fail/validity/dangling_ref1.rs:6:29
|
LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated)
| ^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x10 is unallocated)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: inside `main` at tests/compile-fail/validity/dangling_ref1.rs:6:29
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error
";
check_annotations(unnormalized_stderr.as_bytes(), &mut errors, &config, "", &comments);
match &errors[..] {
[Error::PatternNotFound { .. }] => {}
_ => panic!("{:#?}", errors),
}
}