console-rs/console

read_key goes into an endless loop and eventually exhausts file handles

mitsuhiko opened this issue · 2 comments

Minimal repo case:

use console::Term;

fn main() {
    eprintln!("Press any key to exist");
    Term::stderr().read_key().unwrap();
}

If this script is compiled and run with a close stdin (cat | target/debug/repro) it will fail with

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 24, kind: Uncategorized, message: "Too many open files" }'

The issue is that read_single_key has a condition where it will call back into itself recursively.

Refs astral-sh/rye#184

The broken logic seems to be read_single_char or other poll uses. Changing it into a basic libc::read makes it work

fn read_single_char(fd: i32) -> io::Result<Option<char>> {
    let mut buf = [0u8; 20];
    let read = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void, 20) };
    return if read < 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(Some(buf[0] as char))
    };
}

read_single_char is non blocking in console at the moment. The blocking part is in the None condition of the read_single_char result and I presume this does not correctly block.

I'm guessing that this entire polling business does not really work.

This probably broke via #74 or an earlier version of it.