0

I am having troubles with FreeConsole/AllocConsole and their connection with stdio (stdin/stdout/stderr standard file pointers). I have successfully used this sequence for years:

int main(int argc, char **argv)
{
    FreeConsole();
    AllocConsole();
    freopen("CONIN$", "rb", stdin);
    freopen("CONOUT$", "wb", stdout);
    freopen("CONOUT$", "wb", stderr);

(see this question for example). However, on Windows10 with latest updates I am getting exception 0xC0000008 in freopen. Note that

  1. I can see it only during a debugging sessions (VS2017, Debug configuration). Normal application launch, and Release configuration too, seem to work (or maybe the exception is silently ignored?).
  2. It happens very often, but not in a repeteable way. Sometimes the first freopen fails, sometimes the second one, sometimes the third one, sometimes none o them.
  3. The debugger intercepts the exception (I know, I could turn it off, but I would prefer not to since it is an interesting event in general). When I force program continuation, the program seems to work correctly. However, I am not at all sure that the CRT state is still safe.
  4. If I add fclose(stdin); fclose(stdout); fclose(stderr) before FreeConsole, the exception happens in FreeConsole.

Questions:

  • Is there something wrong in the sequence above?
  • What is the correct way to connect standard file pointers to a new console?
  • Is there a way to avoid this exception (i.e. make sure that it doesn't happen, not just silently ignore)? It is quite annoying in my debugging sessions.

More information:

  • I am using VS2017, but the program uses VS2013 toolset.
  • The program is compiled for x86 (32 bits).
  • In both Debug and Release configuration DLL-Multithread (/MD) library and Multibyte character set are used.
  • OS is Windows10-64 Professional 1903 - 18362.720

Thak you in advance

Giuseppe Guerrini
  • 4,274
  • 17
  • 32
  • I see it too. They've been tinkering heavily with the console subsystem in Win10 to support WSL2 better, the changes have been destabilizing. Yes, 0xC0000008 normally only gets raised with a debugger attached, they are very panicky about handle recycle attacks. Hard to give good advice, this doesn't get put the test very often since you'd normally do this by targeting the Windows subsystem so the FreeConsole() call isn't necessary. Given that you've got this bug out in the wild, and it is a security problem, contacting Microsoft Support would be your best bet. – Hans Passant Mar 24 '20 at 16:47
  • I'd close the standard streams before calling `FreeConsole`. Otherwise the close in `freopen` might flush to an invalid handle. As is, it avoids a handle leak since `FreeConsole` doesn't close the generic console handles (for "\Device\ConDrv\Input" and "\Device\ConDrv\Output" that are initially set in the process standard handles), and `AllocConsole` opens new generic console handles. This handle leak has been a bug since condrv.sys was added in Windows 8. – Eryk Sun Mar 24 '20 at 18:01
  • You should step into `FreeConsole` and analyze the call that raises the `STATUS_INVALID_HANDLE` exception. I would, but I can't reproduce the problem in 10.0.18363. – Eryk Sun Mar 24 '20 at 18:05
  • Stepped into FreeConsole, the system service that raises the exception is always the same (both in FreeConsole and in freopen): EAX=0x3000F, I suppose it is NtClose, since it's the same used by CloseHandle. – Giuseppe Guerrini Mar 24 '20 at 18:23
  • When you step into `NtClose` dump information about the handle. In the platform debuggers (windbg, cdb), the handle value should be `? poi(@esp + 4)`, and you can dump information about the handle via `!handle f`. Also, the current standard handles (`StandardInput`, etc) are in the process parameters, `?? @$peb->ProcessParameters`. – Eryk Sun Mar 24 '20 at 19:24

0 Answers0