rust-lang / miri

An interpreter for Rust's mid-level intermediate representation
Apache License 2.0
4.16k stars 318 forks source link

terminal APIs not supported: can't call foreign function `ioctl` on OS `linux` #3719

Open CramBL opened 4 days ago

CramBL commented 4 days ago

I just learned about miri, and I'm trying to use it in a project and I cannot get it to run basically anything, I get errors in very basic "tests". e.g. this one.

#[cfg(test)]
mod tests {
    use crate::evaluate_compression::compression_result::color_grade_0_to_100_green_blue_white_yellow_red;
    use comfy_table::*;

    #[test]
    fn tune_color_grade_0_to_100_green_blue_white_yellow_red() {
        let mut table = Table::new();
        let mut cells = vec![];
        for x in 0..=100 {
            let c =
                comfy_table::Cell::new(x).fg(color_grade_0_to_100_green_blue_white_yellow_red(x));
            cells.push(c);

            if cells.len() == 26 {
                table.add_row(cells);
                cells = vec![];
            }
        }
        table.add_row(cells);
        println!("{table}");
    }
}

The color_grade_0_to_100_green_blue_white_yellow_red function looks like below (bad code :clown_face: )


pub fn color_grade_0_to_100_green_blue_white_yellow_red(val: u8) -> comfy_table::Color {
    debug_assert!(val <= 100);

    if val <= 50 {
        // Transition from green to cyan to blue to white at 50%
        let (r, g, b) = match val {
            0..=34 => {
                // Green to Cyan
                let r = 0;
                let g = 255;
                let b = (val as f32 * 6.2) as u8; // 0 to 255
                (r, g, b)
            }
            35..=50 => {
                // Cyan to Blue to White
                let r = ((val - 25) as f32 * 10.2) as u8; // 0 to 255
                let g = 255;
                let b = 255;
                (r, g, b)
            }
            _ => unreachable!(),
        };
        comfy_table::Color::Rgb { r, g, b }
    } else if val <= 80 {
        // Transition from white at 50% to yellow at 80%
        let r = 255;
        let g = 255;
        let b = 255 - ((val - 50) as f32 * 8.5) as u8; // 255 to 0
        comfy_table::Color::Rgb { r, g, b }
    } else {
        // Transition from yellow at 80% to red at 100%
        let r = 255;
        let g = 255 - ((val - 80) as f32 * 12.75) as u8; // 255 to 0
        let b = 0;
        comfy_table::Color::Rgb { r, g, b }
    }
}

And I get this result from MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-backtrace=full" cargo +nightly miri test tune_color_grade.

MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-backtrace=full" cargo +nightly miri test tune_color_grade
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.06s
     Running unittests src/main.rs (target/miri/x86_64-unknown-linux-gnu/debug/deps/qft-e789802002b6f8c2)

running 1 test
test evaluate_compression::compression_result::tests::tune_color_grade_0_to_100_green_blue_white_yellow_red ... error: unsupported operation: can't call foreign function `ioctl` on OS `linux`
   --> /home/marcbk/.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossterm-0.27.0/src/terminal/sys/unix.rs:55:34
    |
55  |     if wrap_with_result(unsafe { ioctl(fd, TIOCGWINSZ.into(), &mut size) }).is_ok() {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function `ioctl` on OS `linux`
    |
    = help: if this is a basic API commonly used on this target, please report an issue with Miri
    = help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases
    = note: BACKTRACE on thread `evaluate_compre`:
    = note: inside `crossterm::terminal::sys::unix::window_size` at /home/marcbk/.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossterm-0.27.0/src/terminal/sys/unix.rs:55:34: 55:73
    = note: inside `crossterm::terminal::sys::unix::size` at /home/marcbk/.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossterm-0.27.0/src/terminal/sys/unix.rs:64:30: 64:43
    = note: inside `crossterm::terminal::size` at /home/marcbk/.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossterm-0.27.0/src/terminal.rs:137:5: 137:16
    = note: inside `comfy_table::Table::width` at /home/marcbk/.cargo/registry/src/index.crates.io-6f17d22bba15001f/comfy-table-7.1.1/src/table.rs:274:37: 274:53
    = note: inside `comfy_table::utils::arrangement::arrange_content` at /home/marcbk/.cargo/registry/src/index.crates.io-6f17d22bba15001f/comfy-table-7.1.1/src/utils/arrangement/mod.rs:17:23: 17:36
    = note: inside `comfy_table::utils::build_table` at /home/marcbk/.cargo/registry/src/index.crates.io-6f17d22bba15001f/comfy-table-7.1.1/src/utils/mod.rs:51:24: 51:46
    = note: inside `comfy_table::Table::lines` at /home/marcbk/.cargo/registry/src/index.crates.io-6f17d22bba15001f/comfy-table-7.1.1/src/table.rs:95:9: 95:26
    = note: inside `<comfy_table::Table as std::fmt::Display>::fmt` at /home/marcbk/.cargo/registry/src/index.crates.io-6f17d22bba15001f/comfy-table-7.1.1/src/table.rs:47:25: 47:37
    = note: inside `core::fmt::rt::Argument::<'_>::fmt` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/fmt/rt.rs:165:63: 165:82
    = note: inside `std::fmt::write` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/fmt/mod.rs:1168:21: 1168:44
    = note: inside `<std::vec::Vec<u8> as std::io::Write>::write_fmt` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/io/mod.rs:1835:15: 1835:43
    = note: inside closure at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/io/stdio.rs:1129:25: 1129:84
    = note: inside `std::option::Option::<std::sync::Arc<std::sync::Mutex<std::vec::Vec<u8>>>>::map::<(), {closure@std::io::stdio::print_to_buffer_if_capture_used::{closure#0}::{closure#0}}>` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:1103:29: 1103:33
    = note: inside closure at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/io/stdio.rs:1128:13: 1131:15
    = note: inside `std::thread::LocalKey::<std::cell::Cell<std::option::Option<std::sync::Arc<std::sync::Mutex<std::vec::Vec<u8>>>>>>::try_with::<{closure@std::io::stdio::print_to_buffer_if_capture_used::{closure#0}}, std::option::Option<()>>` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:283:12: 283:27
    = note: inside `std::io::stdio::print_to_buffer_if_capture_used` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/io/stdio.rs:1124:12: 1132:11
    = note: inside `std::io::stdio::print_to::<std::io::Stdout>` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/io/stdio.rs:1112:8: 1112:45
    = note: inside `std::io::_print` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/io/stdio.rs:1227:5: 1227:37
note: inside `evaluate_compression::compression_result::tests::tune_color_grade_0_to_100_green_blue_white_yellow_red`
   --> src/evaluate_compression/compression_result.rs:432:9
    |
432 |         println!("{table}");
    |         ^^^^^^^^^^^^^^^^^^^
note: inside closure
   --> src/evaluate_compression/compression_result.rs:418:63
    |
417 |     #[test]
    |     ------- in this procedural macro expansion
418 |     fn tune_color_grade_0_to_100_green_blue_white_yellow_red() {
    |                                                               ^
    = note: inside `<{closure@src/evaluate_compression/compression_result.rs:418:5: 433:6} as std::ops::FnOnce<()>>::call_once - shim` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5: 250:71
    = note: inside `<fn() -> std::result::Result<(), std::string::String> as std::ops::FnOnce<()>>::call_once - shim(fn() -> std::result::Result<(), std::string::String>)` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5: 250:71
    = note: inside `test::__rust_begin_short_backtrace::<std::result::Result<(), std::string::String>, fn() -> std::result::Result<(), std::string::String>>` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/test/src/lib.rs:625:18: 625:21
    = note: inside `test::types::RunnableTest::run` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/test/src/types.rs:146:40: 146:71
    = note: inside closure at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/test/src/lib.rs:648:60: 648:79
    = note: inside `<std::panic::AssertUnwindSafe<{closure@test::run_test_in_process::{closure#0}}> as std::ops::FnOnce<()>>::call_once` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panic/unwind_safe.rs:272:9: 272:19
    = note: inside `std::panicking::r#try::do_call::<std::panic::AssertUnwindSafe<{closure@test::run_test_in_process::{closure#0}}>, std::result::Result<(), std::string::String>>` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:553:40: 553:43
    = note: inside `std::panicking::r#try::<std::result::Result<(), std::string::String>, std::panic::AssertUnwindSafe<{closure@test::run_test_in_process::{closure#0}}>>` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:517:19: 517:88
    = note: inside `std::panic::catch_unwind::<std::panic::AssertUnwindSafe<{closure@test::run_test_in_process::{closure#0}}>, std::result::Result<(), std::string::String>>` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:350:14: 350:33
    = note: inside `test::run_test_in_process` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/test/src/lib.rs:648:27: 648:81
    = note: inside closure at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/test/src/lib.rs:569:43: 577:18
    = note: inside closure at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/test/src/lib.rs:599:41: 599:83
    = note: inside `std::sys::backtrace::__rust_begin_short_backtrace::<{closure@test::run_test::{closure#1}}, ()>` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/backtrace.rs:155:18: 155:21
    = note: inside closure at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/mod.rs:542:17: 542:71
    = note: inside `<std::panic::AssertUnwindSafe<{closure@std::thread::Builder::spawn_unchecked_<'_, '_, {closure@test::run_test::{closure#1}}, ()>::{closure#2}::{closure#0}}> as std::ops::FnOnce<()>>::call_once` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panic/unwind_safe.rs:272:9: 272:19
    = note: inside `std::panicking::r#try::do_call::<std::panic::AssertUnwindSafe<{closure@std::thread::Builder::spawn_unchecked_<'_, '_, {closure@test::run_test::{closure#1}}, ()>::{closure#2}::{closure#0}}>, ()>` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:553:40: 553:43
    = note: inside `std::panicking::r#try::<(), std::panic::AssertUnwindSafe<{closure@std::thread::Builder::spawn_unchecked_<'_, '_, {closure@test::run_test::{closure#1}}, ()>::{closure#2}::{closure#0}}>>` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:517:19: 517:88
    = note: inside `std::panic::catch_unwind::<std::panic::AssertUnwindSafe<{closure@std::thread::Builder::spawn_unchecked_<'_, '_, {closure@test::run_test::{closure#1}}, ()>::{closure#2}::{closure#0}}>, ()>` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:350:14: 350:33
    = note: inside closure at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/mod.rs:541:30: 543:16
    = note: inside `<{closure@std::thread::Builder::spawn_unchecked_<'_, '_, {closure@test::run_test::{closure#1}}, ()>::{closure#2}} as std::ops::FnOnce<()>>::call_once - shim(vtable)` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5: 250:71
    = note: inside `<std::boxed::Box<dyn std::ops::FnOnce()> as std::ops::FnOnce<()>>::call_once` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/boxed.rs:2064:9: 2064:52
    = note: inside `<std::boxed::Box<std::boxed::Box<dyn std::ops::FnOnce()>> as std::ops::FnOnce<()>>::call_once` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/boxed.rs:2064:9: 2064:52
    = note: inside `std::sys::pal::unix::thread::Thread::new::thread_start` at /home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/pal/unix/thread.rs:108:17: 108:64
    = note: this error originates in the macro `println` which comes from the expansion of the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 1 previous error

error: test failed, to rerun pass `--bin qft`

Caused by:
  process didn't exit successfully: `/home/marcbk/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner /home/marcbk/repos/quick-file-transfer/target/miri/x86_64-unknown-linux-gnu/debug/deps/qft-e789802002b6f8c2 tune_color_grade` (exit status: 1)
note: test exited abnormally; to see the full output pass --nocapture to the harness.

I was not expect all these issues since I run this project with cargo hack test --feature-powerset on linux/windows/macos with no issues.

I must be doing something wrong?

cgettys-microsoft commented 4 days ago

Pretty sure this duplicates #743.

There are a lot of syscalls, and a lot of platforms. E.g. Linux alone has something like 500: a list. And a lot of sys calls have many, many flags and options.

Not all syscalls are emulated / supported by Miri yet. Even when a sys call is supported in part, that doesn't mean every combination of flags / arguments is implemented either. Keep in mind Miri tries to emulate sys calls for all host architectures, it doesn't assume the host is the same OS or architecture. Also keep in mind that Miri is not just blindly passing the data through - it is checking for UB and API misuse, including in the arguments to syscalls.

I don't want to put words in the maintainers' mouths, but from what I've personally seen, they are friendly and welcome contributions :).

saethlin commented 4 days ago

Someone should look into whether it's reasonable to shim all libc APIs for implementing a TUI. There are a handful beyond this one ioctl. For example, being able to get the current window size is unlikely to be useful without being able to put the terminal into raw mode.

It's not clear to me if these APIs can be implemented portably.

cgettys-microsoft commented 4 days ago

Yeah, I'm not sure these can be done portably either. Not sure what the Miri stance is on non-portable syscalls - to me, that seems like a second dimension beyond the "basic" isolation (i.e. some stuff like basic file system stuff breaks isolation, but may still be portable / emulatable).