microsoft / microsoft/terminal

Console ReadFile canceled by Ctrl+C fails to set ERROR_OPERATION_ABORTED

Open
#334 4 comments 1 reaction 1 assignee View on GitHub

@lhecker is already working on this.

Since Jun 27, 2023.

Area-Server Impact-Compatibility Issue-Bug Product-Conhost
Dominant language
C++
Stars
105k
Forks
9.6k
Avg merge
3d 17h
Merged PRs (30d)
29

Description

In Windows 8+, a ReadFile call on a console input handle that's interrupted by Ctrl+C or Ctrl+Break doesn't set the last error to ERROR_OPERATION_ABORTED (995). It used to do this in previous versions, and it's documented as such. (It still works for ReadConsole in all versions.) The consequence is that there's no immediate way to distinguish Ctrl+C from EOF (i.e. success with 0 bytes read) when reading from the console via ReadFile.

When a read is interrupted by Ctrl+C, the console returns (and has always returned, AFAIK) the NT status code STATUS_ALERTED (0x00000101), which is a success code for an alerted wait (e.g. via NtAlertThread). This status code is being misused outside of its intended context, but previously its usage was completely private to the console client/server implementation. What changed is that in Windows 8+ the console uses the ConDrv device instead of an LPC port, and console files are now kernel file objects. ReadFile and ReadConsole used to have a common implementation that special cased STATUS_ALERTED. But now they're split up. ReadFile calls NtReadFile and ReadConsole calls NtDeviceIoControlFile (due to the pInputControl parameter). ReadConsole can still special case STATUS_ALERTED. On the other hand, to ReadFile it's simply a successful read, since there's no immediate way to detect a console handle without making another system call.

Maybe ReadFile can safely assume that no other device would be so weird as to return STATUS_ALERTED for a read request. Alternatively, ConDrv or the I/O manager could bring back the practice of flagging console handles by setting the lower 2 bits, as was done prior to Windows 8. Then ReadFile could easily detect a console handle and special case STATUS_ALERTED.

The proper status code is STATUS_CANCELLED (0xC0000120), which automatically maps to ERROR_OPERATION_ABORTED. It's a failure code, however, and according to the docs this case is supposed to succeed with an error set. I don't understand this. The call really has been canceled and really has failed. It's no different from an I/O request getting canceled by CancelIo or CancelSynchronousIo.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.