AllocConsole и стандартный ввод / вывод

У меня проблемы с _1 _ / _ 2_ и их подключением к stdio (_3 _ / _ 4 _ / _ 5_ стандартные указатели файлов). Я годами успешно использую эту последовательность:

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

(см., например, этот вопрос). Однако в Windows10 с последними обновлениями я получаю исключение 0xC0000008 в freopen. Обратите внимание, что

  1. Я вижу это только во время сеансов отладки (VS2017, конфигурация отладки). Кажется, что нормальный запуск приложения и конфигурация выпуска тоже работают (или, может быть, исключение автоматически игнорируется?).
  2. Это случается очень часто, но не повторяется. Иногда первый freopen выходит из строя, иногда второй, иногда третий, иногда ни один из них.
  3. Отладчик перехватывает исключение (я знаю, что могу его выключить, но я бы предпочел не делать этого, так как это вообще интересное событие). Когда я принудительно продолжаю программу, кажется, что программа работает правильно. Однако я вовсе не уверен, что состояние CRT все еще безопасно.
  4. Если я добавлю fclose(stdin); fclose(stdout); fclose(stderr) перед FreeConsole, исключение произойдет в FreeConsole.

Вопросов:

  • Что-то не так в приведенной выше последовательности?
  • Как правильно подключить стандартные указатели файлов к новой консоли?
  • Есть ли способ избежать этого исключения (т.е. убедиться, что этого не происходит, а не просто игнорировать)? Во время сеансов отладки это очень раздражает.

Больше информации:

  • Я использую VS2017, но программа использует набор инструментов VS2013.
  • Программа скомпилирована для x86 (32 бита).
  • Как в конфигурации отладки, так и в конфигурации выпуска используются библиотека DLL-Multithread (/ MD) и многобайтовый набор символов.
  • ОС Windows10-64 Professional 1903 - 18362.720

Спасибо заранее


person Giuseppe Guerrini    schedule 24.03.2020    source источник
comment
Я тоже это вижу. Они сильно повозились с подсистемой консоли в Win10, чтобы лучше поддерживать WSL2, изменения дестабилизируют. Да, 0xC0000008 обычно вызывается только с подключенным отладчиком, они очень паникуют по поводу атак с повторным использованием обработчиков. Трудно дать хороший совет, это не очень часто проверяется, поскольку вы обычно делаете это, ориентируясь на подсистему Windows, поэтому вызов FreeConsole () не нужен. Учитывая, что у вас есть эта ошибка, и это проблема безопасности, лучше всего обратиться в службу поддержки Microsoft.   -  person Hans Passant    schedule 24.03.2020
comment
Я бы закрыл стандартные потоки перед вызовом FreeConsole. В противном случае закрытие в freopen может сбрасываться до недопустимого дескриптора. Как есть, он позволяет избежать утечки дескрипторов, поскольку FreeConsole не закрывает общие дескрипторы консоли (для \ Device \ ConDrv \ Input и \ Device \ ConDrv \ Output, которые изначально установлены в стандартных дескрипторах процесса), а AllocConsole открывает новую общую консоль ручки. Эта утечка дескриптора была ошибкой с тех пор, как condrv.sys был добавлен в Windows 8.   -  person Eryk Sun    schedule 24.03.2020
comment
Вам следует войти в FreeConsole и проанализировать вызов, который вызывает исключение STATUS_INVALID_HANDLE. Я бы хотел, но не могу воспроизвести проблему в 10.0.18363.   -  person Eryk Sun    schedule 24.03.2020
comment
При переходе в FreeConsole системная служба, которая вызывает исключение, всегда одна и та же (как в FreeConsole, так и в freopen): EAX = 0x3000F, я полагаю, это NtClose, поскольку он используется в CloseHandle.   -  person Giuseppe Guerrini    schedule 24.03.2020
comment
При входе в NtClose дамп информации о дескрипторе. В отладчиках платформы (windbg, cdb) значение дескриптора должно быть ? poi(@esp + 4), и вы можете выгрузить информацию о дескрипторе через !handle <handle value> f. Кроме того, текущие стандартные дескрипторы (StandardInput и т. Д.) Находятся в параметрах процесса ?? @$peb->ProcessParameters.   -  person Eryk Sun    schedule 24.03.2020