programing

힙 파손 오류를 디버깅하는 방법

mbctv 2023. 4. 16. 15:35
반응형

힙 파손 오류를 디버깅하는 방법

Visual Studio 2008에서 (네이티브) 멀티 스레드 C++ 애플리케이션을 디버깅하고 있습니다.무작위로 보이는 상황에서 "Windows가 중단점을 트리거했습니다." 오류와 함께 힙 파손이 원인일 수 있습니다.이러한 에러에 의해서 애플리케이션이 곧바로 크래쉬 하는 것은 아닙니다만, 그 직후에 크래쉬 할 가능성이 있습니다.

이러한 에러의 큰 문제는, 실제로 파손이 발생한 후에만 팝업이 표시되기 때문에, 특히 멀티 스레드애플리케이션에서는 추적과 디버깅이 매우 어려워집니다.

  • 이러한 에러의 원인이 되는 것은 어떤 것입니까?

  • 디버깅하려면 어떻게 해야 하나요?

힌트, 도구, 방법, 계발...환영합니다.

Application VerifierWindows용 디버깅툴의 조합은 놀라운 셋업입니다.Windows 드라이버 키트 또는 보다 가벼운 Windows SDK 의 일부로서 둘 다 입수할 수 있습니다.(히프 파손 문제에 관한 이전 질문을 조사했을 때 Application Verifier 에 대해 확인).Bounds Checker와 Insure+(다른 답변에서 언급)를 사용한 적이 있지만, Application Verifier에 기능이 얼마나 있는지 놀랐습니다.

Electric Fence(일명 "방어", dmalloc, valgrind 등)는 모두 언급할 가치가 있지만 대부분의 경우 Windows보다 *nix에서 실행하기가 훨씬 쉽습니다.Valgrind는 터무니없이 유연합니다.큰 서버 소프트웨어를 디버깅해 봤지만 힙 문제가 많이 있습니다.

그 외의 모든 것이 실패했을 경우, 독자적인 글로벌 오퍼레이터의 new/delete와 malloc/calloc/realloc 오버로드를 제공할 수 있습니다.그 방법은 컴파일러와 플랫폼에 따라 다소 다릅니다만, 이것은 다소 투자가 됩니다만, 장기적으로는 효과가 있을지도 모릅니다.바람직한 기능 목록은 dmalloc 및 일렉트로펜스, 그리고 놀라울 정도로 훌륭한 책 솔리드 코드 작성:

  • sentry 값: 최대 얼라인먼트 요건을 고려하여 각 할당 전후로 약간의 공간을 확보합니다.매직 수치로 채웁니다(버퍼 오버플로와 언더플로우를 포착하는 데 도움이 됩니다.또, 때때로 「와일드」포인터도 취득할 수 있습니다).
  • allocate: 새로운 할당을 0이 아닌 매직 값으로 채웁니다. Visual C++는 이미 디버깅빌드에서 이 작업을 수행합니다(초기화되지 않은 변수 사용 포착에 도움이 됩니다).
  • free fill: 0이 아닌 매직한 값으로 메모리를 채웁니다.대부분의 경우 seg fault를 트리거하도록 설계되어 있습니다(행잉 포인터 포착에 도움이 됩니다).
  • delayed free: 빈 메모리를 잠시 힙에 반환하지 않고 빈 메모리로 유지하지만 사용할 수 없습니다(더 많은 포인터를 포착하고 근접한 이중 슬롯을 포착하는 데 도움이 됩니다).
  • 트래킹: 할당이 이루어진 위치를 기록할 수 있는 것이 도움이 될 수 있습니다.

로컬 홈브루 시스템(임베디드 타깃용)에서는 런타임 오버헤드가 훨씬 높기 때문에 추적을 다른 대부분의 항목과 분리하여 유지합니다.


이러한 할당 함수/연산자를 과부하시키는 더 많은 이유에 관심이 있는 경우, "글로벌 연산자 new and delete를 과부하해야 하는 이유가 있습니까?"; 파렴치한 자가 진단은 차치하고 힙 파손 오류를 추적하는 데 도움이 되는 기타 기술 및 기타 적용 가능한 툴이 나열됩니다.


MS가 사용하는 allocate/free/fence 값을 검색할 때 여기서 계속 답을 찾을 수 있기 때문에 Microsoft dbgheap fill 값을 다루는 다른 답이 있습니다.

애플리케이션의 페이지 힙을 유효하게 하면, 많은 힙 파손의 문제를 검출할 수 있습니다.이를 위해서는 gflags를 사용해야 합니다.Windows용 디버깅툴의 일부로 제공되는 exe

Gflags를 실행합니다.실행 파일의 이미지 파일 옵션에서 "페이지 힙 사용" 옵션을 선택합니다.

이제 exe를 다시 시작하고 디버거에 연결합니다.페이지 힙을 활성화하면 힙 손상이 발생할 때마다 응용 프로그램이 디버거로 전환됩니다.

느려지고 런타임 체크를 , 「실행 시간 체크」의 맨 과 같이 .main() C에 상당하는 Microsoft Visual Studio C++를 합니다.

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_ALWAYS_DF );

매우 관련성이 높은 문서는 Application VerifierDebugdiag사용한 힙 파손 디버깅입니다.

이러한 에러의 원인이 되는 것은 어떤 것입니까?

버퍼 종료 후 쓰기, 힙으로 해방된 후 버퍼에 쓰기 등 메모리에 장난스러운 작업을 수행합니다.

디버깅하려면 어떻게 해야 하나요?

실행 파일에 자동 경계 검사를 추가하는 도구(유닉스에서는 valgrind 또는 Windows에서는 BoundsChecker(Wikipedia에서는 Purify 및 Insure++도 권장)를 사용합니다.

이 경우 응용 프로그램이 느려질 수 있으므로 소프트 실시간 응용 프로그램일 경우 사용할 수 없습니다.

다른 가능한 디버깅 보조 도구/툴로는 MicroQuill의 HeapAgent가 있습니다.

Detecting access to free memory에서 얻은 간단한 힌트는 다음과 같습니다.

메모리 블록에 액세스하는 모든 문을 확인하지 않고 오류를 신속하게 찾으려면 블록을 해제한 후 메모리 포인터를 비활성 값으로 설정할 수 있습니다.

#ifdef _DEBUG // detect the access to freed memory
#undef free
#define free(p) _free_dbg(p, _NORMAL_BLOCK); *(int*)&p = 0x666;
#endif

매번 유용하고 도움이 되는 최고의 도구는 (좋은 코드 리뷰어를 가진) 코드 리뷰입니다.

코드 리뷰 외에 페이지 힙을 먼저 사용해 보겠습니다.페이지 힙을 설정하는 데 몇 초 정도 걸리고 문제가 발견될 수 있습니다.

페이지 힙을 사용할 수 없는 경우 Microsoft에서 Windows용 디버깅툴을 다운로드하여 WinDbg 사용법을 배우십시오.더 구체적인 도움을 드리지 못해 죄송합니다. 하지만 멀티 스레드 힙 손상을 디버깅하는 것은 과학이라기보다는 예술에 가깝습니다.구글에서 "WinDbg 힙 손상"을 검색하면 해당 주제에 대한 많은 기사를 찾을 수 있습니다.

어떤 종류의 할당 기능을 사용하고 있습니까?최근에 Heap* 스타일의 할당 함수를 사용했을 때 비슷한 오류가 발생했습니다.

있었습니다.HEAP_NO_SERIALIZE스레드 안전성 할 수 합니다.이로 인해 기본적으로 스레드 안전성 없이 힙 기능이 실행됩니다.올바르게 사용하면 성능이 향상되지만 멀티 스레드 프로그램에서 HeapAlloc을 사용하는 경우에는 사용하지 마십시오 [1].글에 멀티 스레드 앱이 있다고 쓰여있기 때문에 이 점만 언급하겠습니다.HEAP_는 NO_SERIALIZE를 의 장소에서될 수 있습니다.NO_SERIALIZE를 선택합니다.

[1] 이것이 합법인 경우는 있습니다만, Heap* 에의 콜을 시리얼화 할 필요가 있습니다.멀티 스레드 프로그램의 경우는 일반적으로 그렇지 않습니다.

이러한 에러가 랜덤하게 발생하는 경우는, 데이터 레이스가 발생했을 가능성이 높아집니다.확인하세요: 다른 스레드에서 공유 메모리 포인터를 수정하시겠습니까?인텔(R) 스레드 체커는 멀티 스레드 프로그램에서 이러한 문제를 검출하는 데 도움이 될 수 있습니다.

또한 동적 또는 정적 C 런타임 라이브러리에 대한 링크 여부를 확인할 수도 있습니다.DLL 파일이 정적 C 런타임 라이브러리에 대해 링크되어 있는 경우 DLL 파일에는 별도의 힙이 있습니다.

따라서 한 DLL에서 개체를 만들고 다른 DLL에서 개체를 해방하려고 하면 위와 같은 메시지가 나타납니다.이 문제는 다른 스택오버플로우 질문인 다른 DLL에 할당된 메모리 해방에서 언급됩니다.

툴을 찾는 것 외에 생각할 수 있는 범인을 찾는 것도 고려합니다.사용하고 있는 컴포넌트 중 멀티스레드 환경에서 동작하도록 설계 및 테스트되지 않은 컴포넌트가 있습니까?또는 단순히 모르는 이 이러한 환경에서 실행되었을 수도 있습니다.

지난번에는 원어민 패키지로 몇 년 동안 배치 작업을 통해 성공적으로 사용되었습니다.하지만 이 회사에서 에서 사용한 것은 이번이 처음입니다.NET Web 서비스(멀티 스레드).그게 다예요. 그들은 코드가 스레드 세이프라고 거짓말을 했어요.

VC CRT 힙 체크매크로는 _CrtSetDbgFlag: _CRTDBG_CHECK_ALways_DF 또는 _CRTDBG_CHECK_EVERY_16_DF 에 사용할 수 있습니다._CRTDBG_CHECK_EVERY_1024_DF.

제 경험을 더하고 싶습니다.지난 며칠 동안 이 오류의 예를 어플리케이션에서 해결했습니다.특히 코드의 오류는 다음과 같습니다.

  • STL 컬렉션에서 요소 제거(Visual Studio에 디버깅 플래그가 있는 것으로 알고 있습니다. 코드 검토 중에 캡처했습니다.)
  • 이것은 좀 더 복잡합니다.단계별로 나누어 보겠습니다.
    • 네이티브 C++ 스레드에서 관리 대상 코드로 콜백
    • 관리 대상 토지에서는Control.Invoke콜백이 속한 네이티브오브젝트를 랩하는 관리대상 오브젝트를 폐기합니다.
    • 오브젝트는 네이티브스레드 내에 아직 활성화되어 있기 때문에(콜백콜에서는 다음 시간까지 차단됩니다).Control.Invokeends)를 사용하고 있음을 명확히 해야 합니다.boost::thread스레드 함수로 멤버 함수를 사용하고 있습니다.
    • 솔루션:사용하다Control.BeginInvoke(GUI는 Winforms를 사용하여 작성됩니다) 대신 네이티브 스레드가 오브젝트가 파기되기 전에 종료할 수 있도록 합니다(콜백의 목적은 스레드가 종료되어 오브젝트가 파기될 수 있음을 정확하게 통지하는 것입니다).

나도 비슷한 문제가 있었는데, 꽤 무작위로 튀어나왔다.빌드 파일에 뭔가 문제가 있는 것 같습니다만, 우선 프로젝트를 청소하고 나서 재구축해 버렸습니다.

따라서 주어진 다른 응답 외에 다음과 같은 답변이 있습니다.

이러한 에러의 원인이 되는 것은 어떤 것입니까?빌드 파일에 뭔가 손상된 것이 있습니다.

디버깅하려면 어떻게 해야 하나요?프로젝트를 청소하고 재구축합니다.문제가 해결되었다면, 이것이 문제였을 가능성이 있습니다.

저도 이 문제에 직면했습니다.저의 경우 x사이즈 메모리를 할당하고 x+n 사이즈의 데이터를 첨부했습니다.따라서 해방 시 힙 오버플로가 표시되었습니다.할당된 메모리가 충분한지 확인하고 메모리에 추가된 바이트 수를 확인합니다.

언급URL : https://stackoverflow.com/questions/1010106/how-to-debug-heap-corruption-errors

반응형