fix read/1 on non-TTY stdin blocking until newline #3262

This commit is contained in:
no382001
2026-03-31 14:40:20 +02:00
parent 79a9b950cb
commit c065b52778
3 changed files with 34 additions and 5 deletions

View File

@@ -23,7 +23,7 @@ use std::fmt::Debug;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::hash::Hash; use std::hash::Hash;
use std::io; use std::io;
use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write}; use std::io::{Cursor, ErrorKind, IsTerminal, Read, Seek, SeekFrom, Write};
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
use std::net::{Shutdown, TcpStream}; use std::net::{Shutdown, TcpStream};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
@@ -657,10 +657,27 @@ impl Stream {
#[inline] #[inline]
pub fn stdin(arena: &mut Arena, add_history: bool) -> Stream { pub fn stdin(arena: &mut Arena, add_history: bool) -> Stream {
if std::io::stdin().is_terminal() {
Stream::Readline(arena_alloc!( Stream::Readline(arena_alloc!(
StreamLayout::new(ReadlineStream::new("", add_history)), StreamLayout::new(ReadlineStream::new("", add_history)),
arena arena
)) ))
} else {
#[cfg(unix)]
{
use std::os::unix::io::{FromRawFd, RawFd};
// dup fd 0 so the File can be owned (and closed later) without
// closing the real stdin.
let fd = unsafe { libc::dup(0 as RawFd) };
let file = unsafe { File::from_raw_fd(fd) };
return Stream::from_file_as_input(atom!("user_input"), file, arena);
}
#[allow(unreachable_code)]
Stream::Readline(arena_alloc!(
StreamLayout::new(ReadlineStream::new("", add_history)),
arena
))
}
} }
pub fn from_tag(tag: ArenaHeaderTag, ptr: UntypedArenaPtr) -> Self { pub fn from_tag(tag: ArenaHeaderTag, ptr: UntypedArenaPtr) -> Self {

4
tests-pl/issue3262.pl Normal file
View File

@@ -0,0 +1,4 @@
:- initialization(main).
main :-
read(Term),
write(Term).

View File

@@ -1,4 +1,5 @@
use crate::helper::load_module_test; use crate::helper::load_module_test;
use crate::helper::load_module_test_with_input;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use crate::helper::load_module_test_with_tokio_runtime; use crate::helper::load_module_test_with_tokio_runtime;
use serial_test::serial; use serial_test::serial;
@@ -148,6 +149,13 @@ fn issue_rename_file() {
load_module_test("tests-pl/issue_rename_file.pl", "file_renamed"); load_module_test("tests-pl/issue_rename_file.pl", "file_renamed");
} }
// issue #3262: read/1 on non-TTY stdin should resolve without requiring a newline
#[test]
#[cfg_attr(miri, ignore = "unsupported operation when isolation is enabled")]
fn issue3262_read_from_stdin_no_newline() {
load_module_test_with_input("tests-pl/issue3262.pl", "hello.", "hello");
}
#[test] #[test]
#[cfg(feature = "http")] #[cfg(feature = "http")]
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]