2012-08-09 11 views
5

he entrada de línea de lesionados con el siguiente código:¿Por qué está llamando a ReadConsole en un bucle que daña la pila?

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

Entonces me llamo ReadConsole en un bucle ... en un bucle:

wchar_t cBuf; 

while (1) { 
    /* Display Options */ 

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

    putwchar(cBuf); 

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

Si ejecuto el programa y pulse 0 de inmediato, existe limpiamente.
Pero si se presiona un manojo de llaves, a continuación, pulse 0, cuando existe el programa se bloquea con:

Run-Time Check Fracaso # 2 - Stack torno a la variable 'cBuf' fue corrompida.

¿Por qué esto causa que la pila se corrompa? El código es simple, así que no puedo descifrar qué está mal.

pequeño programa que pueda reproducir el problema:

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

Tienes que tipo de machacar el teclado después de que lo ejecute, a continuación, pulse 0, y se estrella con el daño de pila.

Tampoco puedo reproducir el problema todas las veces, se necesitan algunos intentos.
Lo estaba ejecutando en Visual Studio 2010, después de crear un nuevo proyecto de consola vacía y agregar un archivo con ese código.

+0

No puedo reproducir el problema. ¿Podría publicar un programa pequeño pero completo que muestre el problema? –

+0

Sugeriría verificar el valor de retorno de 'ReadConsoleW' y examinar' GetLastError' cuando sea necesario. De lo contrario, no tengo ni idea. –

+0

Comprobó el valor de retorno de 'ReadConsoleW', pero cada vez que el valor de retorno era distinto de cero, no hubo errores. Además, cuando se bloquea con la corrupción de la pila, el depurador se encuentra al final del programa. – Josh

Respuesta

7

Por lo que puedo decir, este es un error en Windows. Aquí es un programa un poco más sencillo que muestra el 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); 
    } 
} 

El sueño hace que sea un poco más fácil para activar el tema, que se produce cada vez más de un carácter está esperando en el momento de llamar ReadConsoleW.

Al mirar el contenido de cBuf[1] en el momento en que falla la aserción correspondiente, parece que ReadConsoleW está escribiendo un byte extra al final del búfer.

La solución alternativa es sencilla: asegúrese de que su memoria intermedia tenga al menos un byte extra. En su caso, use el primer carácter de una matriz de dos caracteres.

+1

Interesante. Solo curiosidad, ¿por qué si elimino la función de Suspensión, no puedo hacer que desencadene un punto de quiebre? ¿Qué logra tenerlo dormir durante 5 segundos? – Josh

+1

Sin la suspensión, es poco probable que pueda presionar las teclas lo suficientemente rápido para obtener más de una lectura a la vez, aunque el uso de cortar y pegar podría funcionar. (Su código original fue un poco más lento de bucle debido a la putwchar y wprintf por lo que un sueño no era esencial.) –

Cuestiones relacionadas