2011-02-17 4 views
2

힙 손상 오류가있는 큰 MFC 기반 응용 프로그램을 충돌시키는 테스트 사례가 있습니다.App Verifier 출력 해석 : 힙 손상 또는 스택 주소를 힙 주소로 잘못 해석 했습니까?

문제의 DLL에 대해 App Verifier를 사용하여 페이지 힙을 켰습니다 (불행히도 전체 프로세스에서 힙을 켜는 것은 다른 이유로는 유용하지 않습니다). 검증 프로그램은 우리가 제공하는 것보다 더 많은 정보를 제공하지 않았습니다. 이미 가지고 있었다; 그것은 원래의 충돌과 같은 시점에서 시작되었습니다.

지금 저는 두 가지 경쟁 이론을 가지고 있습니다. 어떤 이론이 옳을 것이라고 생각합니까? 그리고 다음 단계는 무엇이 될까요?

  1. 이것은 실제로 힙 손상입니다. Verifier가 다른 DLL에서 발생하기 때문에 원래 손상을 포착하지 않습니다. 우리는 더 많은 DLL에 대한 검증자를 활성화하고 어떤 코드가 힙을 손상시키는 지 결정해야합니다.
  2. 힙이 좋습니다. 문제는 스택 주소를 힙 주소로 처리한다는 것입니다. 우리는이 호출 스택의 코드를 자세히 조사하여 잘못된 점을 파악해야합니다.

free()에 대한 매개 변수가 스택 주소와 비슷해 보이지만 지금까지 아무도이 방법에 대한 설명을 제안하지 않았기 때문에 저는 # 2에 기울고 있습니다.

다음은 호출 스택 스 니펫입니다. MyString은 CString을 둘러싼 간단한 래퍼입니다. MyAppDll은 페이지 힙을 사용하도록 설정된 DLL입니다. 여기

msvcr90.dll!free(void * pBlock=0x000000000012d6e8) Line 110 
mfc90u.dll!ATL::CStringT > >::~CStringT > >() Line 1011 + 0x1e bytes 
MyStringDll.dll!MyString::~MyString() Line 59 
MyAppDll.dll!doStuffWithLotsOfStringInlining(MyClass* input=0x000000000012d6d0) Line 863 + 0x26 bytes

는 무료() 스택 프레임 내부 레지스터입니다 :

 
RAX = 0000000000000000 RBX = 000000000012D6E8 RCX = 0000000000000000 
RDX = 0000000000000000 RSI = 000000000012D6D0 RDI = 00000000253C1090 
R8 = 0000000000000000 R9 = 0000000000000000 R10 = 0000000000000000 
R11 = 0000000000000000 R12 = 000000000012D7D0 R13 = 000007FFFFC04CE0 
R14 = 0000000025196600 R15 = 0000000000000000 RIP = 00000000725BC7BC 
RSP = 000000000012D570 RBP = 000007FFF3670900 EFL = 00000000 

을 그리고 여기에 응용 프로그램 검증 메시지는 다음과 같습니다

 
VERIFIER STOP 0000000000000010: pid 0x1778: Corrupted start stamp for heap block. 

    00000000083B1000 : Heap handle used in the call. 
    000000006DD394E8 : Heap block involved in the operation. 
    54D32858A8747589 : Size of the heap block. 
    000000005E33BA8D : Corrupted stamp value. 

답변

1

그것이의 나는 당신의 문자열이나 사용자를 생각/아마도 문자열 포인터 옆에있는 필드에 대해 문자열의 버퍼가 어딘가에서 오버플로/언더 플로 (underflow)하고 있습니다.

당신의 RSP는 당신이 자유롭게하려고하는 것에서 94 쿼드 (ints) 떨어져있는 12D570입니다, 그래서 어딘가에 버퍼로 뭔가 나쁜 일이 일어나고 있습니다.

안전하지 않은 문자열 작업을 수행하지 않고 사용중인 DLL에 버퍼/문자열을 전달하기위한 설명서를 제대로 읽고 있는지 확인하십시오.

좀 더 정확한 답변을 원하면 질문에 더 많은 코드가 필요합니다.

+0

감사합니다. 이것은 내가 찾던 답변입니다. 불행히도 여기에는 완전한 그림을 제공하기 위해 너무 많은 코드가 포함되어 있습니다. 짧은 발췌가 도움이 될 것이라고 생각하지 않습니다. – Dewb

+1

x64 모드에서 호출 스택에 표시된대로 매개 변수 값을 신뢰할 수 없으면 레지스터에 전달됩니다. 이러한 레지스터 값은 오랫동안 덮어 썼습니다. RBP는 매우 불만스럽게 보입니다. –

+1

문자열 래퍼 클래스가 MFC의 nil 문자열 데이터 singleton의 참조 횟수를 영구적으로 늘리는 결과를 초래 한 새로운 위치 지정으로 영리한 작업을 수행했다. 결국 (버그가있는 코드로 20 억 회를 호출 한 후) 참조 횟수가 오버플로되고 음수가되고 nil 버퍼가 삭제됩니다! 그런 다음 파괴 된 다음 빈 문자열에 이중 자유가 적용됩니다. – Dewb