Eryk Sun added the comment: Background Discussion
The Windows 10 console uses the condrv.sys device driver, which is set up as follows in the NT namespace: C:\>odir \ -r -n con;con*$;cond* Directory of \ Device ConDrv <Device> Driver condrv <Driver> GLOBAL?? CON -> \Device\ConDrv\Console CONIN$ -> \Device\ConDrv\CurrentIn CONOUT$ -> \Device\ConDrv\CurrentOut Previously the base console API used an NT LPC port to communicate with the attached console process (i.e. an instance of conhost.exe). There wasn't a real console device. Instead, opening "CON", "CONIN$", or "CONOUT$" was special cased to call OpenConsoleW (undocumented). With the new console device driver, opening the DOS "CON" device gets translated to the NT path "\Device\ConDrv\Console", i.e. it opens the file named "Console" on the ConDrv device. Opening the Console file returns a handle for a regular kernel File object. To that end, you may have noticed that console handles in Windows 10 are no longer tagged for routing by setting the lower two bits (e.g. 3, 7, 11, etc). For example: >>> kernel32.GetStdHandle(STD_INPUT_HANDLE) 32 >>> kernel32.DebugBreak() (e1c.e20): Break instruction exception - code 80000003 (first chance) KERNELBASE!DebugBreak+0x2: 00007ffa`60280262 cc int 3 0:000> !handle 32 Handle 32 Type File Previously, all operations on console handles were internally routed to special console functions, such as ReadFile => ReadConsoleA. Thus with the old LPC-based console, a ReadFile basically has the behavior of ReadConsoleA (with the addition of special casing input lines that start with Ctrl+Z). The new design scraps a lot of the special-cased code. For example, reading from a console handle in Windows 10 uses a regular NtReadFile system call. So the error it sets, if any at all, depends on translating the NTSTATUS code that's returned by NtReadFile. Let's see what status the console sets here: C:\Temp>cdb -xi ld python ccbug.py [...] ntdll!LdrpDoDebuggerBreak+0x30: 00007ffb`170de260 cc int 3 0:000> g 3.5.1 (v3.5.1:37a07cee5969, Dec 6 2015, 01:54:25) [MSC v.1900 64 bit (AMD64)] calling DebugBreak... (8d0.62c): Break instruction exception - code 80000003 (first chance) KERNELBASE!DebugBreak+0x2: 00007ffb`13f40262 cc int 3 0:000> bp ntdll!NtReadFile 0:000> g Breakpoint 0 hit ntdll!NtReadFile: 00007ffb`170b35d0 4c8bd1 mov r10,rcx 0:000> pt ntdll!NtReadFile+0xa: 00007ffb`170b35da c3 ret 0:000> r rax rax=0000000000000101 The console weirdly returns a success code, STATUS_ALERTED (0x101, "the delay completed because the thread was alerted"), which is why ReadFile doesn't set an error. STATUS_ALERTED is normally returned when an NT wait function gets alerted by NtAlertThread (note that this is not the same as getting alerted by an asynchronous procedure call). For example: tid = threading.get_ident() h = kernel32.OpenThread(MAXIMUM_ALLOWED, 0, tid) t = threading.Timer(5, ntdll.NtAlertThread, (h,)) delay = LARGE_INTEGER(10 * -10**7) # 10 seconds t.start() r = ntdll.NtDelayExecution(True, byref(delay)) >>> hex(r) '0x101' NtAlertThread is rarely used because WinAPI wait functions (e.g. SleepEx) automatically restart a wait when the underlying NT wait returns STATUS_ALERTED. The ReadConsole implementation has always translated STATUS_ALERTED to ERROR_OPERATION_ABORTED. This still exists in the Windows 10 implementation of ReadConsole. However, the correct error status for this case is STATUS_CANCELLED (0xC0000120, "the I/O request was cancelled"): >>> ntdll.RtlNtStatusToDosError(0xC0000120) 995 Whoever reimplemented the console IPC using a device driver should have updated the console to return STATUS_CANCELLED when an I/O operation is interrupted by Ctrl+C or Ctrl+Break. Then nothing would need to be special cased. ---------- _______________________________________ Python tracker <rep...@bugs.python.org> <http://bugs.python.org/issue18597> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com