Skip to content

Commit 576f556

Browse files
miss-islingtonaisk
andauthored
[3.14] gh-132888: Fix Windows API error checking in pyrepl.windows_console (GH-144248) (#161633)
gh-132888: Fix Windows API error checking in pyrepl.windows_console (GH-144248) (cherry picked from commit 3abc03c) Co-authored-by: AN Long <aisk@users.noreply.github.com>
1 parent aa7b28d commit 576f556

3 files changed

Lines changed: 34 additions & 16 deletions

File tree

‎Lib/_pyrepl/windows_console.py‎

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,11 @@
4646
from .windows_eventqueue import EventQueue
4747

4848
try:
49-
from ctypes import get_last_error, GetLastError, WinDLL, windll, WinError # type: ignore[attr-defined]
49+
from ctypes import get_last_error, WinDLL, windll, WinError # type: ignore[attr-defined]
5050
except:
5151
# Keep MyPy happy off Windows
5252
from ctypes import CDLL as WinDLL, cdll as windll
5353

54-
def GetLastError() -> int:
55-
return 42
56-
5754
def get_last_error() -> int:
5855
return 42
5956

@@ -152,16 +149,18 @@ def __init__(
152149

153150
# Save original console modes so we can recover on cleanup.
154151
original_input_mode = DWORD()
155-
GetConsoleMode(InHandle, original_input_mode)
152+
if not GetConsoleMode(InHandle, original_input_mode):
153+
raise WinError(get_last_error())
156154
trace(f'saved original input mode 0x{original_input_mode.value:x}')
157155
self.__original_input_mode = original_input_mode.value
158156

159-
SetConsoleMode(
157+
if not SetConsoleMode(
160158
OutHandle,
161159
ENABLE_WRAP_AT_EOL_OUTPUT
162160
| ENABLE_PROCESSED_OUTPUT
163161
| ENABLE_VIRTUAL_TERMINAL_PROCESSING,
164-
)
162+
):
163+
raise WinError(get_last_error())
165164

166165
self.screen: list[str] = []
167166
self.width = 80
@@ -311,7 +310,7 @@ def _scroll(
311310
if not ScrollConsoleScreenBuffer(
312311
OutHandle, scroll_rect, None, destination_origin, fill_info
313312
):
314-
raise WinError(GetLastError())
313+
raise WinError(get_last_error())
315314

316315
def _hide_cursor(self):
317316
self.__write("\x1b[?25l")
@@ -345,7 +344,7 @@ def __write(self, text: str) -> None:
345344
def screen_xy(self) -> tuple[int, int]:
346345
info = CONSOLE_SCREEN_BUFFER_INFO()
347346
if not GetConsoleScreenBufferInfo(OutHandle, info):
348-
raise WinError(GetLastError())
347+
raise WinError(get_last_error())
349348
return info.dwCursorPosition.X, info.dwCursorPosition.Y
350349

351350
def _erase_to_end(self) -> None:
@@ -361,15 +360,17 @@ def prepare(self) -> None:
361360
self.__offset = 0
362361

363362
if self.__vt_support:
364-
SetConsoleMode(InHandle, self.__original_input_mode | ENABLE_VIRTUAL_TERMINAL_INPUT)
363+
if not SetConsoleMode(InHandle, self.__original_input_mode | ENABLE_VIRTUAL_TERMINAL_INPUT):
364+
raise WinError(get_last_error())
365365
self._enable_bracketed_paste()
366366

367367
def restore(self) -> None:
368368
if self.__vt_support:
369369
self.__write(ANSIColors.RESET)
370370
# Recover to original mode before running REPL
371371
self._disable_bracketed_paste()
372-
SetConsoleMode(InHandle, self.__original_input_mode)
372+
if not SetConsoleMode(InHandle, self.__original_input_mode):
373+
raise WinError(get_last_error())
373374

374375
def _move_relative(self, x: int, y: int) -> None:
375376
"""Moves relative to the current posxy"""
@@ -406,7 +407,7 @@ def getheightwidth(self) -> tuple[int, int]:
406407
and width of the terminal window in characters."""
407408
info = CONSOLE_SCREEN_BUFFER_INFO()
408409
if not GetConsoleScreenBufferInfo(OutHandle, info):
409-
raise WinError(GetLastError())
410+
raise WinError(get_last_error())
410411
return (
411412
info.srWindow.Bottom - info.srWindow.Top + 1,
412413
info.srWindow.Right - info.srWindow.Left + 1,
@@ -415,15 +416,15 @@ def getheightwidth(self) -> tuple[int, int]:
415416
def _getscrollbacksize(self) -> int:
416417
info = CONSOLE_SCREEN_BUFFER_INFO()
417418
if not GetConsoleScreenBufferInfo(OutHandle, info):
418-
raise WinError(GetLastError())
419+
raise WinError(get_last_error())
419420

420421
return info.srWindow.Bottom # type: ignore[no-any-return]
421422

422423
def _read_input(self) -> INPUT_RECORD | None:
423424
rec = INPUT_RECORD()
424425
read = DWORD()
425426
if not ReadConsoleInput(InHandle, rec, 1, read):
426-
raise WinError(GetLastError())
427+
raise WinError(get_last_error())
427428

428429
return rec
429430

@@ -433,7 +434,7 @@ def _read_input_bulk(
433434
rec = (n * INPUT_RECORD)()
434435
read = DWORD()
435436
if not ReadConsoleInput(InHandle, rec, n, read):
436-
raise WinError(GetLastError())
437+
raise WinError(get_last_error())
437438

438439
return rec, read.value
439440

@@ -536,7 +537,7 @@ def flushoutput(self) -> None:
536537
def forgetinput(self) -> None:
537538
"""Forget all pending, but not yet processed input."""
538539
if not FlushConsoleInputBuffer(InHandle):
539-
raise WinError(GetLastError())
540+
raise WinError(get_last_error())
540541

541542
def getpending(self) -> Event:
542543
"""Return the characters that have been typed but not yet

‎Lib/test/test_pyrepl/test_windows_console.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,21 @@
3131
pass
3232

3333

34+
def _mock_console_init(self, f_in=0, f_out=1, term="", encoding="utf-8"):
35+
"""Mock __init__ to avoid real Windows API calls in headless environments."""
36+
super(WindowsConsole, self).__init__(f_in, f_out, term, encoding)
37+
self.screen = []
38+
self.width = 80
39+
self.height = 25
40+
self._WindowsConsole__offset = 0
41+
self.posxy = (0, 0)
42+
self._WindowsConsole__vt_support = False
43+
self._WindowsConsole_original_input_mode = 0
44+
self.event_queue = wc.EventQueue('utf-8')
45+
46+
3447
@force_not_colorized_test_class
48+
@patch.object(WindowsConsole, '__init__', _mock_console_init)
3549
class WindowsConsoleTests(TestCase):
3650
def console(self, events, **kwargs) -> Console:
3751
console = WindowsConsole()
@@ -390,6 +404,7 @@ def test_reset_on_restore(self):
390404
con.out.write.assert_any_call(ANSIColors.RESET.encode(con.encoding))
391405

392406

407+
@patch.object(WindowsConsole, '__init__', _mock_console_init)
393408
class WindowsConsoleGetEventTests(TestCase):
394409
# Virtual-Key Codes: https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
395410
VK_BACK = 0x08
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix incorrect use of :func:`ctypes.GetLastError` and add missing error
2+
checks for Windows API calls in :mod:`!_pyrepl.windows_console`.

0 commit comments

Comments
 (0)