PID로 프로세스 FullPath를 검색 및 Cache하는 기능을 개발하고 있습니다.

AVL 타입의 GenericTable을 사용하구요... 메모리 관리는 LookAsideList (NonPaged)를 사용합니다.


이 과정에서 RtlInsertElementGenericTable 을 이용해 새로 구한 프로세스 정보를 GenericTable에 집어넣는데요...

MSDN에 보면 다음과 같이 되어 있습니다.

Remarks

To insert an element, RtlInsertElementGenericTable calls the CompareRoutine and AllocateRoutine that were registered when the generic table was initialized by RtlInitializeGenericTable. After inserting the new element,RtlInsertElementGenericTable rebalances the splay link tree.

When a new element is inserted into the table, its data is copied from Buffer into the new element. Thus the pointer returned by RtlInsertElementGenericTable is never equal to Buffer.

If the caller's CompareRoutine returns GenericEqual, the data at Buffer is assumed to duplicate the data for an existing element in the generic table. In this case, RtlInsertElementGenericTable does not add the new element (and thus does not call the AllocateRoutine), because a generic table cannot have duplicate elements.


위의 내용을 요약하면 다음과 같습니다.

1. 새로운 Element가 insert될때, 그 데이터가 Buffer에서 새로운 Element로 복사된다. (즉, 우리가 인자로 건넨 버퍼가 그대로 GenericTable에 저장되는게 아니고, 복사된 사본이 저장된다는 뜻입니다.)

2. (빨간색 부분) 따라서, RtlInsertElementGenericTable 이 리턴한 포인터는 "절대" 그 버퍼와 같지 않다.


네... 상식적으로 잘 이해가 되죠...


그런데, 디버깅을 하다가 좀 이상한 현상을 발견했습니다. 이모저모로 분석을 하다가... 결국 아래와 같은 테스트를 하게 되었습니다.

 
MSDN 에 따르면 "### pProcessInfoInserted == pProcessInfo == %p ###" 이 로그는 절대 찍혀선 안되겠군요.... 그렇죠?? ^^;; 
그런데 실제로는... 저 로그가 찍히는 경우가 있었습니다.

[ProcessInfoAllocateRoutine] Allocate 2092 bytes (sizeof LEODRV_PROCESS_INFO 2076 bytes)
[LeoLookupProcessInformation] ### pProcessInfoInserted == pProcessInfo == 84E297C0 ###
[LeoLookupProcessInformation] ProcessId 2540 ==> \Device\HarddiskVolume1\Windows\System32\SearchIndexer.exe


이럴수기...!! 혼란스럽군요.... @.@

이걸 어떻게 해석해야 할까요??


이건 정말 중요한 문제입니다. 왜냐하면... 


1. 만약 인자로 넘겨준 버퍼의 주소값과 리턴된 포인터값이 같다는 것이, 우리가 넘겨준 버퍼가 그대로 GenericTable에 저장된다는 것을 의미한다면... RtlInsertElementGenericTable 에 넘겨주었던 그 포인터 메모리를 Free 해서는 안되기 때문입니다. 

2. 위의 가정이 맞다면, RtlInsertElementGenericTable 에 인자로 넘겨주는 데이터는 절대 로컬변수 같은걸 써선 안된다는 뜻이 되어 버립니다.

3. 리턴값이 우리가 할당한 버퍼냐 그 사본이냐에 따라서 리턴값된 값을 처리하는 코드가 달라져야 합니다.


테스트해 본 바로는... 일단 저 84E297C0 라는 버퍼는 GenericTable에 저장된 것이 맞는 것 같습니다.

왜나하면.. 그 이후로 저 버퍼가 GenericTable에서 검색된 로그가 있거든요...


[LeoLookupProcessInformation] Found from Cache Pid 2540 ==> \Device\HarddiskVolume1\Windows\System32\SearchIndexer.exe

[LeoReleaseProcessInformation] Decrement ProcessInfoRefCount : Ptr 84E297C0 RefCount 1 Pid 2540 ==> \Device\HarddiskVolume1\Windows\System32\SearchIndexer.exe


(뭐 로그는 제가 알아보기 쉽게 적은거니 내용에 신경쓰실 필요 없구요... 그냥 저 값이 GenericTable에서 검색되고 있다는 것만 보시면 됩니다.)


음... GenericTable을 처음 써보는 것도 아니고... 지금까지 로컬변수를 Insert해서 사용한 적도 많았는데요... 이게 어찌된 일일까요... ^^;;


AVL 타입의 GenericTable은 처음 써보는데요... AVL 타입은 구현이 약간 다른 걸까요?

아니면... 위의 인자로 넣어준 버퍼와 GenericTable 내에서 할당하는 버퍼가 동일한 LookAsideList에서 할당된다는 점 때문에 저렇게 동작하는 것일까요?


나중에 시간날때... RtlInsertElementGenericTable 의 어셈코드를 한번 분석해봐야겠습니다.







Posted by kuaaan

댓글을 달아 주세요



사랑합니다. 편안히 잠드소서