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 Simon Depiets, eryksun, paul.moore, steve.dower, tim.golden, zach.ware
Date 2017-12-12.05:30:56
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1513056657.25.0.213398074469.issue32245@psf.upfronthosting.co.za>
In-reply-to
Content
I was able to reproduce this problem in 3.6 in Windows 10 (1709), but only for code paths that call WriteFile, i.e. os.write and legacy standard I/O mode.

Writing to the console will block if there's an active text selection. The operation completes once the user copies the selection to the clipboard (e.g. by pressing enter). In the case of WriteFile, when the blocked call finally completes, the console mistakenly returns the number of internally written UTF-16 bytes. 

This bug is not present with WriteConsoleA, which means there's a simple workaround. _Py_write could detect a console handle and call WriteConsoleA instead of _write. 

The following test executes a write on a separate thread, after a timed delay that allows selecting text beforehand. Text can be selected via Ctrl+A, Shift+Up, or the mouse (the latter requires quick-edit mode or toggling mark mode). 

    import os
    import sys
    import ctypes
    import msvcrt
    import threading

    kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
    fd_stdout = sys.stdout.fileno()
    h_stdout = msvcrt.get_osfhandle(fd_stdout)
    n = ctypes.c_ulong()

    def test_write():
        n.value = os.write(fd_stdout, b'spam\r\n')

    def test_WriteFile():
        kernel32.WriteFile(h_stdout, b'spam\r\n', 6, ctypes.byref(n), None)

    def test_WriteConsoleA():
        kernel32.WriteConsoleA(h_stdout, b'spam\r\n', 6, ctypes.byref(n), None)


For example, given manual text selection after starting the timer:

    >>> threading.Timer(5, test_write).start()
    >>> spam

    >>> n
    c_ulong(12)

    >>> threading.Timer(5, test_WriteFile).start()
    >>> spam

    >>> n
    c_ulong(12)

    >>> threading.Timer(5, test_WriteConsoleA).start()
    >>> spam

    >>> n
    c_ulong(6)

This test could be completely automated by combining SendInput (to set the session control-key state), GetConsoleWindow, and PostMessageW (WM_KEYDOWN, WM_KEYUP).
History
Date User Action Args
2017-12-12 05:30:57eryksunsetrecipients: + eryksun, paul.moore, tim.golden, zach.ware, steve.dower, Simon Depiets
2017-12-12 05:30:57eryksunsetmessageid: <1513056657.25.0.213398074469.issue32245@psf.upfronthosting.co.za>
2017-12-12 05:30:57eryksunlinkissue32245 messages
2017-12-12 05:30:56eryksuncreate