Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Ctrl-C can cause Windows Console IO reads to incorrectly return empty string #130323

Open
Labels
OS-windowstype-bugAn unexpected behavior, bug, or error
@timabroad

Description

@timabroad

Bug report

Bug description:

Many file-like read functions are expected to return non-empty strings/bytes until EOF, eg the docs forio.RawIOBasehere state:

If 0 bytes are returned, and size was not 0, this indicates end of file. If the object is in non-blocking mode and no bytes are available, None is returned.

However, on Windows, when reading from a console, Python will return 0 bytes on Ctrl-C if the default SIGINT handler is replaced with something that doesn't raise an exception, or presumably if you are reading from a thread other than the main thread.

To reproduce:

importsignal,syssignal.signal(signal.SIGINT,lambda*args:print('<SIGINT>',flush=True))foriinrange(10):print(f"INPUT{i} ={sys.stdin.readline()!r}",flush=True)

Then run it in a console with various inputs:

C:\>py script1.pyline0INPUT0 = 'line0\n'line1INPUT1 = 'line1\n'<SIGINT>INPUT2 = ''line3INPUT3 = 'line3\n'line4<SIGINT>INPUT4 = ''line5INPUT5 = 'line5\n'^ZINPUT6 = ''^Zline7INPUT7 = ''line8INPUT8 = 'line8\n'line9INPUT9 = 'line9\n'

As you can see, when CTRL-C is pressed, the custom SIGINT handler runs, doesn't raiseKeyboardInterrupt, butreadline() then returns an empty string. There is also similar behaviour for lines beginning with CTRL-Z, which appears to be intentional, and somewhat consistent with how cmd behaves, but since it doesn't actually close the underlying file handle (you can still read more data after encountering CTRL-Z) it might be surprising, and potentially worth documenting (though I'm not sure where, and it might be already somewhere that I didn't look 😛).

Just for reference, this doesn't affect reading from a pipe, for example, or presmably other file-like objects. Using the following script:

importsignal,sys,timesignal.signal(signal.SIGINT,lambda*args:print('<CTRL-C>',file=sys.stderr,flush=True))foriinrange(5):time.sleep(1)print(f"test",flush=True)
C:\>py script2.py | py script1.pyINPUT0 = 'test0\n'<CTRL-C><SIGINT>INPUT1 = 'test1\n'INPUT2 = 'test2\n'<CTRL-C><CTRL-C><CTRL-C><SIGINT>INPUT3 = 'test3\n'<CTRL-C><SIGINT>INPUT4 = 'test4\n'INPUT5 = ''INPUT6 = ''INPUT7 = ''INPUT8 = ''INPUT9 = ''

Also interestingly in this case, it seems like the ctrl-c isn't delivered to the reading process till the next read completes (the writing process can receive and handle multiple interrupts between write operations). I'm not sure this behaviour is correct either, as it means there's no way to interrupt a read on a pipe that isn't receiving any data.

From what I can tell, the bug is in theread_console_w() function in_io/winconsoleio.c:

if (n==0) {err=GetLastError();if (err!=ERROR_OPERATION_ABORTED)break;err=0;HANDLEhInterruptEvent=_PyOS_SigintEvent();if (WaitForSingleObjectEx(hInterruptEvent,100, FALSE)==WAIT_OBJECT_0) {ResetEvent(hInterruptEvent);Py_BLOCK_THREADSsig=PyErr_CheckSignals();Py_UNBLOCK_THREADSif (sig<0)break;    }}*readlen+=n;/* If we didn't read a full buffer that time, don't try    again or we will block a second time. */if (n<len)break;

The code seems to check for Ctrl-C (signified byn == 0 && err == ERROR_OPERATION_ABORTED), then checks for a pending exception in a signal handler, but if there isn't one (sig == 0) it just falls through and then breaks out becausen < len - with the comment about not blocking a second time. Ithink the solution would be to simplycontinue at the end of then == 0 block, but I don't entirely know how the_PyOS_SigintEvent() thing works, and if it matters which side of that if-block you are.

CPython versions tested on:

3.12

Operating systems tested on:

Windows

Metadata

Metadata

Assignees

No one assigned

    Labels

    OS-windowstype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


      [8]ページ先頭

      ©2009-2025 Movatter.jp