-
Notifications
You must be signed in to change notification settings - Fork 8.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Console ReadFile canceled by Ctrl+C fails to set ERROR_OPERATION_ABORTED #334
Comments
If designing this from scratch, I'd expect the following methods to return with the reply status set to In turn, Unfortunately, failing the call goes against the documented behavior of
Since this has been broken for many years now, I'd prefer it was fixed by internally returning If retaining the original documented behavior is desired, without any changes to the console host, then |
Any update on this? |
I just ran into this exact issue as well. I tested with this C# program: using System;
using System.Threading;
using Vanara.PInvoke;
using static Vanara.PInvoke.Kernel32;
namespace Test
{
static class Program
{
static HandlerRoutine _handler;
static bool Handler(CTRL_EVENT e)
{
Console.WriteLine("Got {0} signal", e);
return true; // Suppress.
}
unsafe static void Main()
{
_handler = Handler;
SetConsoleCtrlHandler(_handler, true);
var stdin = GetStdHandle(StdHandleType.STD_INPUT_HANDLE);
Span<byte> buf = stackalloc byte[4096];
fixed (byte* p = buf)
{
var ret = ReadFile(stdin, (IntPtr)p, (uint)buf.Length, out var read, IntPtr.Zero);
Console.WriteLine("ret={0}, err={1}, read={2}", ret, Win32Error.GetLastError(), read);
}
Console.WriteLine("Exiting...");
Thread.Sleep(1000);
}
}
} What makes this particularly painful in my case is that I don't want |
Unfortunately making a second system call has a race condition. The handle may have been closed and possibly reassigned to a different kernel file object. If the success-error behavior has to be retained, maybe the server could return a new I/O facility information status code (i.e. 0x4004_XXXX) such as |
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 toERROR_OPERATION_ABORTED
(995). It used to do this in previous versions, and it's documented as such. (It still works forReadConsole
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 viaReadFile
.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. viaNtAlertThread
). 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
andReadConsole
used to have a common implementation that special casedSTATUS_ALERTED
. But now they're split up.ReadFile
callsNtReadFile
andReadConsole
callsNtDeviceIoControlFile
(due to thepInputControl
parameter).ReadConsole
can still special caseSTATUS_ALERTED
. On the other hand, toReadFile
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 returnSTATUS_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. ThenReadFile
could easily detect a console handle and special caseSTATUS_ALERTED
.The proper status code is
STATUS_CANCELLED
(0xC0000120), which automatically maps toERROR_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 byCancelIo
orCancelSynchronousIo
.The text was updated successfully, but these errors were encountered: