2012-08-09 3 views
5

나는 다음과 같은 코드를 사용할 수 라인 입력을했습니다 :루프에서 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을 누릅니다

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

은 그 때 나는 루프 ... 루프에서 ReadConsole를 호출하고 바로, 그것은 깔끔하게 존재합니다. 변수 'cBuf'주위에 스택 손상되었습니다 -

가 확인 실패 # 2 런타임이

을 : 나는 키의 무리를 누르면 프로그램이 그것과 충돌이있는 경우
는하지만, 다음, 0을 누릅니다.

왜 스택이 손상 될 수 있습니까? 코드는 간단하기 때문에 무엇이 잘못되었는지 알 수 없습니다. 내가 가진 문제를 재현 할 수

리틀 프로그램 :

당신은 당신이 그것을 실행 한 후 종류의 키보드를 반하게해야
#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에서 실행하고있었습니다.

+0

문제를 재현 할 수 없습니다. 이 문제를 전시 한 작지만 완전한 프로그램을 게시 할 수 있습니까? –

+0

필자는'ReadConsoleW'의 리턴 값을 검사하고 필요할 때'GetLastError'를 검사 할 것을 제안합니다. 그렇지 않으면, 나는 단서가 없습니다! –

+0

'ReadConsoleW'의 반환 값을 검사했으나 반환 값이 0이 아니었을 때마다 오류가 없었습니다. 또한 스택 손상으로 인해 충돌이 발생하면 디버거가 프로그램의 끝에 있습니다. – Josh

답변

7

내가 알 수있는 한, 이것은 Windows의 버그입니다. 슬립 그것이 좀 더 쉽게 이상의 캐릭터가 당신이 ReadConsoleW를 호출 할 때 대기 할 때마다 발생하는 문제를 트리거 할 수

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

다음은 문제를 보여줍니다 약간 간단한 프로그램입니다.

해당 어설 션이 실패 할 때 cBuf[1]의 내용을 보면 ReadConsoleW가 버퍼 끝에 하나의 여분의 바이트를 쓰고있는 것처럼 보입니다.

해결 방법은 간단합니다. 버퍼에 적어도 하나의 추가 바이트가 있는지 확인하십시오. 귀하의 경우, 2 문자 배열의 첫 번째 문자를 사용하십시오.

+1

흥미 롭습니다. 단지 궁금해서, 잠자기 기능을 제거하면 중단 점을 발생시키지 못합니다. 5 초 동안 잠을 자면 무엇을 할 수 있습니까? – Josh

+1

수면이 없으면 한 번에 두 개 이상의 읽음을 얻을 수있을만큼 빨리 키를 누르지 않을 수 있습니다. 잘라 내기 및 붙여 넣기를 사용해도 여전히 작동 할 수 있습니다. (원래 코드는 putwchar 및 wprintf 때문에 루프가 느려졌으므로 수면은 필수적이지 않았습니다.) –

관련 문제