mirror of
https://github.com/rust-lang/rust.git
synced 2025-09-28 21:55:31 +00:00

And introduce two new directives for ui tests: * `run-crash` * `run-fail-or-crash` Normally a `run-fail` ui test like tests that panic shall not be terminated by a signal like `SIGABRT`. So begin having that as a hard requirement. Some of our current tests do terminate by a signal/crash however. Introduce and use `run-crash` for those tests. Note that Windows crashes are not handled by signals but by certain high bits set on the process exit code. Example exit code for crash on Windows: `0xc000001d`. Because of this, we define "crash" on all platforms as "not exit with success and not exit with a regular failure code in the range 1..=127". Some tests behave differently on different targets: * Targets without unwind support will abort (crash) instead of exit with failure code 101 after panicking. As a special case, allow crashes for `run-fail` tests for such targets. * Different sanitizer implementations handle detected memory problems differently. Some abort (crash) the process while others exit with failure code 1. Introduce and use `run-fail-or-crash` for such tests.
82 lines
2.3 KiB
Rust
82 lines
2.3 KiB
Rust
//@ run-crash
|
|
//@ only-windows
|
|
|
|
fn main() {
|
|
use std::fs;
|
|
use std::io::prelude::*;
|
|
use std::os::windows::prelude::*;
|
|
use std::ptr;
|
|
use std::sync::Arc;
|
|
use std::thread;
|
|
use std::time::Duration;
|
|
|
|
const FILE_FLAG_OVERLAPPED: u32 = 0x40000000;
|
|
|
|
fn create_pipe_server(path: &str) -> fs::File {
|
|
let mut path0 = path.as_bytes().to_owned();
|
|
path0.push(0);
|
|
extern "system" {
|
|
fn CreateNamedPipeA(
|
|
lpName: *const u8,
|
|
dwOpenMode: u32,
|
|
dwPipeMode: u32,
|
|
nMaxInstances: u32,
|
|
nOutBufferSize: u32,
|
|
nInBufferSize: u32,
|
|
nDefaultTimeOut: u32,
|
|
lpSecurityAttributes: *mut u8,
|
|
) -> RawHandle;
|
|
}
|
|
|
|
unsafe {
|
|
let h = CreateNamedPipeA(path0.as_ptr(), 3, 0, 1, 0, 0, 0, ptr::null_mut());
|
|
assert_ne!(h as isize, -1);
|
|
fs::File::from_raw_handle(h)
|
|
}
|
|
}
|
|
|
|
let path = "\\\\.\\pipe\\repro";
|
|
let mut server = create_pipe_server(path);
|
|
|
|
let client = Arc::new(
|
|
fs::OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).read(true).open(path).unwrap(),
|
|
);
|
|
|
|
let spawn_read = |is_first: bool| {
|
|
thread::spawn({
|
|
let f = client.clone();
|
|
move || {
|
|
let mut buf = [0xcc; 1];
|
|
let mut f = f.as_ref();
|
|
f.read(&mut buf).unwrap();
|
|
if is_first {
|
|
assert_ne!(buf[0], 0xcc);
|
|
} else {
|
|
let b = buf[0]; // capture buf[0]
|
|
thread::sleep(Duration::from_millis(200));
|
|
|
|
// Check the buffer hasn't been written to after read.
|
|
dbg!(buf[0], b);
|
|
assert_eq!(buf[0], b);
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
let t1 = spawn_read(true);
|
|
thread::sleep(Duration::from_millis(20));
|
|
let t2 = spawn_read(false);
|
|
thread::sleep(Duration::from_millis(100));
|
|
let _ = server.write(b"x");
|
|
thread::sleep(Duration::from_millis(100));
|
|
let _ = server.write(b"y");
|
|
|
|
// This is run fail because we need to test for the `abort`.
|
|
// That failing to run is the success case.
|
|
if t1.join().is_err() || t2.join().is_err() {
|
|
return;
|
|
} else {
|
|
panic!("success");
|
|
}
|
|
}
|