6

我使用以下代码禁用了行输入:

DWORD dwConsoleMode;
GetConsoleMode(hStdIn, &dwConsoleMode);
dwConsoleMode ^= ENABLE_LINE_INPUT;
SetConsoleMode(hStdIn, dwConsoleMode);

然后我在一个循环中调用 ReadConsole ......在一个循环中:

wchar_t cBuf;

while (1) {
    /* Display Options */

    do {
        ReadConsole(hStdIn, &cBuf, 1, &dwNumRead, NULL);
    } while (!iswdigit(cBuf));

    putwchar(cBuf);

    if (cBuf == L'0') break;
}

如果我运行程序并立即按 0,它就干净地存在。
但是如果我按一堆键,然后按 0,当程序存在时它会崩溃:

运行时检查失败 #2 - 变量“cBuf”周围的堆栈已损坏。

为什么这会导致堆栈损坏?代码很简单,所以我不知道出了什么问题。

我可以重现问题的小程序:

#include <windows.h>
#include <stdio.h>

int wmain(int argc, wchar_t *argv[])
{
    DWORD dwNumRead;
    wchar_t cBuf;

    HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);

    DWORD dwConsoleMode;
    GetConsoleMode(hStdIn, &dwConsoleMode);
    dwConsoleMode ^= ENABLE_LINE_INPUT;
    SetConsoleMode(hStdIn, dwConsoleMode);

    while (true)
    {
        wprintf(L"\nEnter option: ");

        do {
            ReadConsoleW(hStdIn, &cBuf, 1, &dwNumRead, NULL);
        } while (!iswdigit(cBuf));

        putwchar(cBuf);

        if (cBuf == L'0') break;
    }

    return 0;
}

你必须在你运行它之后把你的键盘捣碎,然后按 0,它会因堆栈损坏而崩溃。

我也无法每次都重现该问题,需要尝试几次。
在创建一个新的空控制台项目并添加一个包含该代码的文件之后,我在 Visual Studio 2010 下运行它。

4

1 回答 1

8

据我所知,这是 Windows 中的一个错误。这是一个稍微简单的程序来演示这个问题:

#include <windows.h>
#include <crtdbg.h>

int wmain(int argc, wchar_t *argv[])
{
    DWORD dwNumRead;
    wchar_t cBuf[2];

    cBuf[0] = cBuf[1] = 65535;

    HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
    SetConsoleMode(hStdIn, 0);

    while (true)
    {
        _ASSERT(ReadConsoleW(hStdIn, &cBuf[0], 1, &dwNumRead, NULL));
        _ASSERT(dwNumRead == 1);
        _ASSERT(cBuf[1] == 65535);
        Sleep(5000);
    }
}

睡眠使触发问题变得更容易一些,只要在您调用ReadConsoleW时有多个字符在等待时,就会发生该问题。

查看cBuf[1]相关断言失败时的内容,ReadConsoleW 似乎正在缓冲区末尾写入一个额外的字节。

解决方法很简单:确保您的缓冲区至少有一个额外的字节。在您的情况下,请使用两个字符数组的第一个字符。

于 2012-08-09T04:46:37.003 回答