2012-08-09 7 views
5

Ho disattivato ingresso di linea con il seguente codice:Perché chiamare ReadConsole in un ciclo che danneggia lo stack?

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

Poi sto chiamando ReadConsole in un ciclo ... in un ciclo:

wchar_t cBuf; 

while (1) { 
    /* Display Options */ 

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

    putwchar(cBuf); 

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

Se faccio funzionare il programma e premere 0 subito, esiste pulito.
Ma se si preme un mazzo di chiavi, quindi premere 0, quando esiste il programma si blocca con:

Run-Time Check Failure # 2 - pila intorno la variabile 'cBuf' stato danneggiato.

Per quale motivo lo stack risulta danneggiato? Il codice è semplice, quindi non riesco a capire cosa c'è che non va.

piccolo programma che posso riprodurre il problema con:

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

Devi tipo di schiacciare la tastiera dopo lo si esegue, quindi premere 0, e si blocca con la corruzione dello stack.

Anche io non riesco a riprodurre il problema ogni volta, ci vogliono alcuni tentativi.
L'ho eseguito in Visual Studio 2010, dopo aver creato un nuovo progetto di console vuoto e aggiunto un file con quel codice.

+0

Non riesco a riprodurre il problema. Potresti per favore pubblicare un piccolo ma completo programma che mostri il problema? –

+0

Suggerirei di controllare il valore restituito di 'ReadConsoleW' ed esaminare' GetLastError' quando necessario. Altrimenti, non ne ho idea! –

+0

Controllato il valore di ritorno di 'ReadConsoleW', ma ogni volta il valore di ritorno era diverso da zero, quindi nessun errore. Anche quando si blocca con la corruzione dello stack, il debugger si trova alla fine del programma. – Josh

risposta

7

Per quanto posso dire, si tratta di un bug in Windows. Ecco un programma leggermente più semplice che illustra il problema:

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

Il sonno rende un po 'più facile per innescare il problema, che si verifica ogni volta più di un carattere è in attesa al momento si chiama ReadConsoleW.

Considerando il contenuto di cBuf[1] al momento in cui l'asserzione rilevante non riesce, sembra che ReadConsoleW stia scrivendo un byte in più alla fine del buffer.

La soluzione alternativa è semplice: assicurarsi che il buffer abbia almeno un byte in più. Nel tuo caso, usa il primo carattere di un array di due caratteri.

+1

Interessante. Solo curioso, come mai se rimuovo la funzione Sleep, non riesco a far scattare un break point? Che cosa significa averlo dormire per 5 secondi? – Josh

+1

Senza il sonno, è improbabile che tu possa colpire le chiavi abbastanza rapidamente da ottenere più di una lettura alla volta, sebbene l'utilizzo di copia e incolla potrebbe comunque funzionare. (Il tuo codice originale era un po 'più lento per il loop a causa di putwchar e wprintf, quindi un sonno non era essenziale.) –

Problemi correlati