초기화하지 않은 지역변수의 쓰레기값 문제
안녕하세요! 제 지식으로는 도저히 해결이 안되는 문제로 kldp까지 찾아오게 되었습니다. 도움 부탁드립니다.
먼저 현재 환경은 아래와 같습니다.
Windows XP 32bit, Windows 7 32bit
VC 7.1
일단 문제의 시작은 아래의 코드에서 시작되었습니다.
// sample.cpp 레지스트리값을 읽거나 쓰는 기능을 하는 그냥 작은 클래스 char buf[256]={0,}; DWORD size; if(RegQueryValueEx( ... 중략 ... , (LPBYTE)buf, &size)!=ERROR_SUCCESS) { MessageBox("실패"); }
일단 위에 ReqQueryValueEx의 마지막 인자인 size는 buf의 크기를 설정해서 전달을 해줘야하는데 위에 코드에서는 그렇게 하지 않고 있었습니다.
일단 위에 코드에 문제가 있지만 약 5년가까이 한번도 문제가 되지 않았습니다.(실제 프로젝트에서는 해당 소스를 참조하는 곳은 단 한곳이긴 합니다..)
아무튼 그러던 중에 제가 해당 소스가 포함된 프로젝트를 맡게되었고, 일부기능을 수정하면서 해당 소스를 수정했습니다.
단, 위에 부분은 수정하지 않았습니다. 이때까지는 몰랐습니다.
그런데 제가 수정한 이후부터 몇몇 PC에서 "실패"라는 메시지 박스가 뜨는 현상이 나타났습니다.
이때 이상했던것이 제PC에서 컴파일한 바이너리는 문제가 발생하지 않았고 사내에서 총괄적으로 컴파일하는 PC에서 컴파일한 바이너리에서는 문제가 발생했습니다.
다시 말씀드리면 결과적으로
제PC에서 컴파일한 바이너리 --> 모든PC에서 문제가 발생안함.
총괄PC에서 캄파일한 바이너리 --> 문제가 발생하는 PC는 계속 발생, 문제가 없는 PC는 계속 문제가 없음.
위와 같은 상황에서 문제를 찾다가 size변수를 초기화하지 않아서 발생한 문제였습니다.
일단 문제는 해결했지만 다시 다른 의문이 생겼습니다.
---------------------------------------------------------------------------
왜 이전에는 위와 같은 문제가 단 한번도 발생하지 않았나????
왜 컴파일한 PC에 따라서 문제가 생기기도 하고 안 생기기도 하는지???
왜일까요??
---------------------------------------------------------------------------
winapi.co.kr 사이트에서 전역/지역변수 설명중...
"global은 0으로 초기화되어 있지만 local에는 이상한 값이 들어 있다. 이 값은 실행할 때마다 달라지는데 지역변수가 생성된 스택 위치의 값이 그대로 출력되는 것이다. 스택에 어떤 값이 들어 있을지 예측할 수 없으므로 이 값을 쓰레기라고 하는 것이다."
제가 위에 글중에 혼란스러운게 "이 값은 실행할 때마다 달라지는데..." <-- 이 부분입니다. 저도 그렇게 생각을 했는데..
이상하게 값이 전혀 변하지가 않습니다.
예를들어 일부러 초기화하지 않은 변수의 값을 확인하면 매번, 프로그램을 재실행해도 , 재부팅을 해도 똑같은 값이 나오던데요..
이건 무슨 현상인가요??
일단 위와 같이 한번 설정된 쓰레기값이 계속 같은 값이라면 5년동안 한번도 문제가 되지 않았다는게 이해가 됩니다..
근데 문제가 제가 해당 소스를 수정한후에는 어떤 PC에서는 문제가 생기고 , 어떤 PC에서는 문제가 안생기는게 다시 설명이 되지를 않네요;;;
조언 좀 부탁드립니다. 감사합니다.
일단 전역변수는 초기화 하지 않아도 0으로 초기화
일단 전역변수는 초기화 하지 않아도 0으로 초기화 됩니다. static 지역변수도 전역변수처럼 동작합니다.
쓰레기값에 대해서 왜 같은 값이 들어갔는지, 또는 왜
쓰레기값에 대해서 왜 같은 값이 들어갔는지, 또는 왜 다른 값이 들어가게 되는지에 대한 원인을 알 필요가 있을까요?
컴파일러 버전이나 최적화 옵션 또는 단계에 따라 달라질 수 있는 문제라 아무도 정확한 답변을 드릴 수 없는 문제라고 생각합니다.
해당 소스를 수정한 후에 문제가 생긴다는 말씀은 제대로 초기화를 해주어도 문제가 생긴다는 말씀인가요?
경우에 따라서 random 값이 아닌 경우도 생깁니다.
해당 프로그램이 single thread로 구성되어 있고 해당 함수가 호출되기 전에 문제의 변수가 사용하는 stack 영역을 사용한 함수가 있다면 당연히 그 함수의 어느 변수 값이 계속 유지됩니다. 그리고 컴파일러의 코드 최적화 방식에 따라 변수 할당도 차이가 있을 수 있으니 컴파일한 PC가 다를 때 값이 바뀌는 것도 쉽게 이해할 수 있을 겁니다.
쓰레기 값은 그냥 쓰레기 값이니 재수가 없었다고 생각하고 심각하게 고민하지 맙시다.
고정되어 있는 사이즈가 문제일
고정되어 있는 사이즈가 문제일 수도....
http://www.tipssoft.com/bulletin/board.php?bo_table=FAQ&wr_id=10
발췌:
데이터를 저장할 공간이 실제 데이터의 크기보다 작은 경우에는 전달된 데이터 크기만큼 데이터가
복사되며 RegQueryValueEx 함수는 ERROR_MORE_DATA 값을 반환할 것이다. 따라서 복사할 데이터의
크기를 예상할수 없는 경우 또는 최적의 메모리 공간만 사용하고 하는 경우에는 데이터를 복사하지 않고
데이터의 크기를 알아낼수 있는 방법이 필요한데 lpData에 NULL을 명시하고 lpcbData에 데이터의 크기를
담을 변수의 주소를 명시한 후, 함수를 호출하면 데이터의 크기가 해당 변수에 저장될 것이다.
-----
오늘 나의 취미는 끝없는, 끝없는 인내다. 1973 法頂
원래 세상이 죽지 않으면 삽니다.
궁금하시면 assembly 출력해보시죠. 또 link time 최적화가 들어갈 수 있으니 binary deassemble 도 해보시고요.
C, C++ 는 정확한 source에 대해서 정확한 동작만을 보장할 뿐 잘못된 source에서 잘못된 동작을 보장하지는 않죠.
C, C++ 하면서 피곤한 이유입니다.
뭐, 어쨌든 이유는 갔다 붙이면 많습니다.
5년동안 문제가 없었다고 했지만 그것도 사실 알 수 없는 것이죠.
Compiler option, SDK, Service Pack 등 영향을 줄 수 있는 다양한 요소가 있을 수 있을테고,
저라면 신경 안 쓸 겁니다.
그런데 Visual C++ 2003 이라... 저도 그걸로 주업무를 하는데 솔직히 제 불행의 직접적인 요소 중 하나죠.
물론 근원원인은 다른데 있겠습니다만...
댓글 고맙습니다. 많은 도움되었습니다^^
댓글 고맙습니다. 많은 도움되었습니다^^
저런 행동에 의문을 가지고 또 "이 값은 실행할
저런 행동에 의문을 가지고 또 "이 값은 실행할 때마다 달라지는데..." 이게 이해가 안간다면
기초가 덜 닦여서 그런것 아닐까요?? 컴파일러가 어떻게 컴파일하는지 알아보면 도움될거 같습니다
글쓴분을 깎아내리거나 그런건 아닙니다. 나쁘게 듣진 말아주세요
댓글 달기