diff --git a/src/lTerm.ml b/src/lTerm.ml index 32770d6..9df007a 100644 --- a/src/lTerm.ml +++ b/src/lTerm.ml @@ -210,16 +210,24 @@ let create term.input_stream <- Lwt_stream.from (fun () -> Lwt_io.read_char_opt term.ic); (* Setup initial size and size updater. *) if term.outgoing_is_a_tty then begin - let check_size () = - let size = get_size_from_fd term.outgoing_fd in - if size <> term.size then begin - term.size <- size; - Lwt_condition.signal term.notify (LTerm_event.Resize size) - end - in - term.size <- get_size_from_fd term.outgoing_fd; - term.last_reported_size <- term.size; - term.event <- E.map check_size resize_event + try + let check_size () = + try + let size = get_size_from_fd term.outgoing_fd in + if size <> term.size then begin + term.size <- size; + Lwt_condition.signal term.notify (LTerm_event.Resize size) + end + with Unix.Unix_error _ -> () + in + term.size <- get_size_from_fd term.outgoing_fd; + term.last_reported_size <- term.size; + term.event <- E.map check_size resize_event + with Unix.Unix_error _ -> + (* If we can't get the terminal size (e.g. on Windows when the + handle passes isatty but is not a real console), fall back to + treating it as a non-tty. *) + term.outgoing_is_a_tty <- false end; return term) Lwt.fail diff --git a/src/lTerm_term_stubs.c b/src/lTerm_term_stubs.c index 002c36d..20901b3 100644 --- a/src/lTerm_term_stubs.c +++ b/src/lTerm_term_stubs.c @@ -23,10 +23,22 @@ CAMLprim value lt_term_get_size_from_fd(value fd) { + HANDLE h = Handle_val(fd); CONSOLE_SCREEN_BUFFER_INFO info; + DWORD mode; value result; - if (!GetConsoleScreenBufferInfo(Handle_val(fd), &info)) { + /* Validate that the handle is a usable console handle before calling + GetConsoleScreenBufferInfo. On some Windows environments (e.g. GitHub + Actions runners using ConPTY), _isatty() may return true for handles + that are not real console screen buffers, causing + GetConsoleScreenBufferInfo to crash with an access violation. */ + if (h == INVALID_HANDLE_VALUE || h == NULL || !GetConsoleMode(h, &mode)) { + win32_maperr(ERROR_INVALID_HANDLE); + uerror("GetConsoleScreenBufferInfo", Nothing); + } + + if (!GetConsoleScreenBufferInfo(h, &info)) { win32_maperr(GetLastError()); uerror("GetConsoleScreenBufferInfo", Nothing); } @@ -39,21 +51,28 @@ CAMLprim value lt_term_get_size_from_fd(value fd) CAMLprim value lt_term_set_size_from_fd(value fd, value val_size) { + HANDLE h = Handle_val(fd); CONSOLE_SCREEN_BUFFER_INFO info; SMALL_RECT rect; + DWORD mode; + + /* Validate that the handle is a usable console handle. */ + if (h == INVALID_HANDLE_VALUE || h == NULL || !GetConsoleMode(h, &mode)) { + win32_maperr(ERROR_INVALID_HANDLE); + uerror("SetConsoleWindowInfo", Nothing); + } - if (!GetConsoleScreenBufferInfo(Handle_val(fd), &info)) { + if (!GetConsoleScreenBufferInfo(h, &info)) { win32_maperr(GetLastError()); uerror("GetConsoleScreenBufferInfo", Nothing); } - rect; rect.Top = info.srWindow.Top; rect.Left = info.srWindow.Left; rect.Bottom = rect.Top + Int_val(Field(val_size, 0)) - 1; rect.Right = rect.Left + Int_val(Field(val_size, 1)) - 1; - if (!SetConsoleWindowInfo(Handle_val(fd), TRUE, &rect)) { + if (!SetConsoleWindowInfo(h, TRUE, &rect)) { win32_maperr(GetLastError()); uerror("SetConsoleWindowInfo", Nothing); }