오늘도 열심히 커널 프로그래밍을 하고 있는 나 맨날 할 때마다 무언가 하나씩 배워간다. 그래서 오늘도 하날 배웠다. 그거슨.. 포스팅 시작




어떠한 테스트를 하기위해서 위와 같이 코드를 사용한적이 있다.(동적할당이 귀찮은 관계로..) 물론 실제 제품 개발 시 하나의 모듈에서 지역변수의 크기를 저렇게 쓰는 일은 없겠지만 아무튼 테스트 목적인 코드였다. 저 코드는 유저에서는 잘 돌아갔다. 이제 kernel 포팅을 해야되서 똑같은 일을 하는 작업을 드라이버로 열심히 옮기면서 테스트 하던 중!!

****************************************************

*                                                                             *

*                        Bugcheck Analysis                          *

*                                                                             *

****************************************************


PAGE_FAULT_IN_NONPAGED_AREA (50)

Invalid system memory was referenced.  This cannot be protected by try-except,

it must be protected by a Probe.  Typically the address is just plain bad or it

is pointing at freed memory.

Arguments:

Arg1: 807d9000, memory referenced.

Arg2: 00000000, value 0 = read operation, 1 = write operation.

Arg3: 82ca236b, If non-zero, the instruction address which referenced the bad memory

address.

Arg4: 00000000, (reserved)


두둥! 머징?

이상한 메모리를 참조 했다네요. 뻑이 난 위치는 함수 시작 후 지역변수를 위한 스택 공간이 할당되기 전! 바로



저 빨간색 함수에서 뻑이 났습니다.

보통 지역변수를 위해 스택 공간 확보시

mov ebp, esp 후

sub esp, xxx 를 해주는데

위 코드에선 확보할 스택 공간을 eax에 넣고 chkstk 함수를 호출하고 있습니다. 어딜 찾아봐도 sub esp, xxx 같은 부분은 보이질 않네요. chkstk 함수는 처음 보는 함수라 난감해 하고 있었습니다. 모든 모듈들을 검사해본 결과 스택에 페이지 크기 이상의 지역변수 공간을 확보하려 할 때 컴파일러(Visual Studio 2012)에서 넣어주는 것이었습니다. 즉, 만약 스택에 30Byte 를 확보할 땐 chkstk 함수는 존재하지 않습니다. 일단 저 함수 내부에서 뻑이 났으므로 "337C" 라는 값이 내부적으로 어떻게 chkstk 를 후려쳤는지 분석을 해봐야겠습니다.


먼저 chkstk 함수가 호출된 모듈 이름이 GOODMAN 이라고 가정하겠습니다.



대충 주석으로 달아놓았는데 결론적으로 chkstk 가 하는 역할은

만약 chkstk 를 호출한 모듈에서 337C 의 지역 변수 공간을 사용한다면 총 4개의 페이지를 필요로 합니다.

그러면 그 4개의 페이지가 전부 유효한 페이지인지를 검사하는 것입니다.


검사하는 부분은 test 명령어를 수행하는 부분에서 검사를 하는데 유효하지 않다면 test 명령어 부분에서 [eax]를 하고 있으므로 뻑이나게 됩니다. 잘못된 메모리 주소를 참조했다는 이유로 말이죠. 만약 4개의 페이지가 전부 유효한다면 sub esp,xxx와 같은 일을 하는 코드를 수행하게 됩니다. 그러니 GOODMAN 함수에선 sub esp,xxx 코드가 없었던 것이지요.


일단 지역변수의 크기를 조절하는 방법으로 위 문제는 해결하였습니다. 뻑이난 이유로는 해당 모듈에서 사용할 수 있는 스택 크기를 넘어섰다는 걸로 생각할 수 있는데 정확한 이유를 알기위해 구글링 시작..


역시 msdn에 있습니다.



전 x86 에서 테스트를 했으므로 제 드라이버에서 사용할 수 있는 커널 스택 크기는 12K 였습니다.

그러면 337C는 십진수로하면 13180 이고 이는 12K 를 넘어서게 됩니다. 당연히 잘못됬다는 것을 알 수 있겠네요.


제 나름대로 생각은 chkstk 함수가 생성되지 않는 범위 즉, 지연변수 크기는 페이지 크기 이하로 설정하는게 좋을 것 같습니다. 하지만 다른 드라이버 개발자 분은 함수 하나당 100Byte 이하로 하는 것을 권장한다고 하네요. 아무튼 지역변수는 되도록 크게 안잡는게 좋을 것 같습니다. 특히 커널에선 말이죠 :D


'My Study > Programming&Theory' 카테고리의 다른 글

Red-Black Tree - 1  (0) 2012.12.10
GetFileTime 신뢰도  (2) 2012.12.05
윈도우 커널 프로세스 당 스택 크기  (9) 2012.12.04
Windows 7 NTFS Time 규칙!  (0) 2012.11.28
NTFS 원하는 파일 속성 출력하기  (3) 2012.11.27
NTFS 메타데이터파일 정보  (0) 2012.11.22
Posted by Ezbeat