2012-08-09 47 views
5

I deaktiviert Line-Eingang mit dem folgenden Code haben:Warum ruft ReadConsole in einer Schleife den Stack auf?

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

Dann nenne ich Readconsole in einer Schleife ... in einer Schleife:

wchar_t cBuf; 

while (1) { 
    /* Display Options */ 

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

    putwchar(cBuf); 

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

Wenn ich das Programm ausführen und drücken 0 sofort, es existiert sauber.
Aber wenn ich ein paar Tasten drücken, und drücken Sie dann 0, wenn das Programm existiert stürzt mit:

Run-Time Check Failure # 2 - Stapeln Sie rund um die Variable 'cbuf' beschädigt wurde.

Warum wird der Stapel dadurch beschädigt? Der Code ist einfach, deshalb kann ich nicht herausfinden, was falsch ist.

kleines Programm, das ich das Problem mit reproduzieren kann:

#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; 
} 

Sie müssen Art der Tastatur Maische, nachdem Sie es ausführen, dann 0 drücken, und stürzt mit dem Stapel Korruption.

Ich kann das Problem auch nicht jedes Mal reproduzieren, es dauert ein paar Versuche.
Ich habe es unter Visual Studio 2010 ausgeführt, nachdem ich ein neues leeres Konsolenprojekt erstellt und eine Datei mit diesem Code hinzugefügt habe.

+0

Ich kann das Problem nicht reproduzieren. Könnten Sie bitte ein kleines, aber vollständiges Programm veröffentlichen, das das Problem aufzeigt? –

+0

Ich würde vorschlagen, den Rückgabewert von 'ReadConsoleW' zu überprüfen und' GetLastError' zu überprüfen, wenn benötigt. Sonst habe ich keine Ahnung! –

+0

Überprüft den Rückgabewert von 'ReadConsoleW', aber jedes Mal war der Rückgabewert ungleich Null, also keine Fehler. Auch wenn es mit der Stapelbeschädigung abstürzt, ist der Debugger am Ende des Programms. – Josh

Antwort

7

Soweit ich das beurteilen kann, ist dies ein Fehler in Windows. Hier ist ein etwas einfacheres Programm, das das Problem veranschaulicht:

#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); 
    } 
} 

Der Schlaf macht es etwas einfacher, das Problem auslösen, die auftritt, wenn mehr als ein Zeichen an der Zeit, die Sie ReadConsoleW Anklopfen.

Mit Blick auf den Inhalt von cBuf[1] zu dem Zeitpunkt, zu dem die relevante Behauptung fehlschlägt, scheint es, dass ReadConsoleW ein zusätzliches Byte am Ende des Puffers schreibt.

Die Problemumgehung ist einfach: Stellen Sie sicher, dass Ihr Puffer über mindestens ein zusätzliches Byte verfügt. Verwenden Sie in Ihrem Fall das erste Zeichen eines aus zwei Zeichen bestehenden Arrays.

+1

Interessant. Nur neugierig, wie kommt es, wenn ich die Sleep-Funktion entferne, kann ich nicht einen Breakpoint auslösen? Was bringt es, 5 Sekunden lang zu schlafen? – Josh

+1

Ohne den Ruhezustand ist es unwahrscheinlich, dass Sie Tasten schnell genug drücken können, um mehr als einen Lesevorgang gleichzeitig zu erhalten, obwohl die Verwendung von Ausschneiden und Einfügen immer noch funktioniert. (Ihr ursprünglicher Code war aufgrund von putwchar und wprintf etwas langsamer zu loopen, so dass ein Sleep nicht notwendig war.) –