This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author eryksun
Recipients eryksun, paul.moore, steve.dower, tim.golden, zach.ware
Date 2017-05-02.17:46:07
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1493747167.63.0.66545140377.issue30237@psf.upfronthosting.co.za>
In-reply-to
Content
When ReadConsole is canceled by CancelSynchronousIo [1], for some reason the call still succeeds. It's probably related to the hack that maps STATUS_ALERTED to ERROR_OPERATION_ABORTED when a console read is interrupted by Ctrl+C.

The problem is that, when canceled, ReadConsole doesn't update the value of lpNumberOfCharsRead. Thus in read_console_w in Modules/_io/winconsoleio.c, the value of `n` is a random number that gets added to `readlen`, which is subsequently used to index into `buf`. The problem is the same for `n_read` in _PyOS_WindowsConsoleReadline.

For example, in 3.6:

    import sys, ctypes, threading
    kernel32 = ctypes.WinDLL('kernel32')
    hMain = kernel32.OpenThread(1, 0, kernel32.GetCurrentThreadId())
    t = threading.Timer(30, kernel32.CancelSynchronousIo, (hMain,))
    t.start()
    sys.stdin.readline()


    Breakpoint 0 hit
    KERNELBASE!ReadConsoleW:
    00007ffc`fb558200 4053            push    rbx
    0:000> pt
    KERNELBASE!GetImmersiveColorTypeFromName+0x49d2:
    00007ffc`fb5d2672 c3              ret
    0:000> r rax
    rax=0000000000000001
    0:000> ?? @$teb->LastErrorValue == 995
    bool true

    0:000> gu
    python36!read_console_w+0x8b:
    00000000`6e43a483 85c0            test    eax,eax
    0:000> ?? n
    unsigned long 0xefdc39e8
    0:000> g
    (1154.11fc): Access violation - code c0000005 (first chance)
    First chance exceptions are reported before any exception handling.
    This exception may be expected and handled.
    python36!read_console_w+0x11f:
    00000000`6e43a517 66833a0a        cmp     word ptr [rdx],0Ah
                                            ds:000001e8`cfb72c7e=????

If the value of `n` is initialized to (DWORD)-1, then checking for a failed or canceled call could be implemented as follows:

    if (!res || (n == (DWORD)-1 && GetLastError() ==
        ERROR_OPERATION_ABORTED)) {
        err = GetLastError();
        break;
    }

[1]: https://msdn.microsoft.com/en-us/library/ms684958
History
Date User Action Args
2017-05-02 17:46:07eryksunsetrecipients: + eryksun, paul.moore, tim.golden, zach.ware, steve.dower
2017-05-02 17:46:07eryksunsetmessageid: <1493747167.63.0.66545140377.issue30237@psf.upfronthosting.co.za>
2017-05-02 17:46:07eryksunlinkissue30237 messages
2017-05-02 17:46:07eryksuncreate