Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

gflags와 _CrtIsMemoryBlock을 이용한 Heap 메모리 손상 여부 체크

지난 글에서,

windbg 분석 사례 - ODP.NET 사용 시 Finalizer에서 System.AccessViolationException 예외 발생으로 인한 비정상 종료
; https://www.sysnet.pe.kr/2/0/11785

windbg - CoTaskMemFree/FreeCoTaskMem에서 발생한 덤프 분석 사례
; https://www.sysnet.pe.kr/2/0/12058

CoTaskMemFree에서 발생한 예외의 원인이 Heap이 깨진 것이라고 설명했습니다.

ntdll!RtlReportCriticalFailure+97
ntdll!RtlpHeapHandleError+12
ntdll!RtlpLogHeapFailure+96
ntdll!RtlFreeHeap+823
OraOps19!ssmem_free+f
OraOps19!OpsMetFreeValCtx+89
DomainNeutralILStubClass.IL_STUB_PInvoke(Oracle.DataAccess.Client.OpoMetValCtx*)+6e
Oracle.DataAccess.Client.MetaData.Finalize()+25

결국 해결을 하긴 했지만,

windbg - Marshal.FreeHGlobal에서 발생한 덤프 분석 사례
; https://www.sysnet.pe.kr/2/0/12086

그래도 혹시나 이 문제가 제가 만든 응용 프로그램에서 발생했다고 가정하고 문제를 빠르게 찾을 수 있는 방법이 없을까 고민을 하게 되었는데요. 가령 지난 글에서 사용한 예제 코드의 경우,

AcLayers의 API 후킹과 FaultTolerantHeap
; https://www.sysnet.pe.kr/2/0/12050

char *cp = new char[10];
(*(cp - 5))++;

CRT Heap의 헤더를 깨먹은 것이기 때문에 "delete cp;"를 수행 시 비정상 종료할 수 있습니다. C++의 경우에는 대개 할당을 한 함수 내에서 해제도 함께 하는 경우가 많기 때문에 문제를 쉽게 발견할 수 있는데, 반면 C#처럼 Finalizer로 인해 해제되는 경우에는 원인 분석이 쉽지 않습니다.




이런 유의 원인 분석을 위해 도움이 되는 것이 있다면 gflags의 heap 관련 옵션을 켜는 것입니다.

Detecting Heap Corruption Using GFlags and Dumps
; https://blogs.msdn.microsoft.com/webdav_101/2010/06/22/detecting-heap-corruption-using-gflags-and-dumps/

Debugging Heap corruption with Application Verifier and Debugdiag
; https://blogs.msdn.microsoft.com/lagdas/2008/06/24/debugging-heap-corruption-with-application-verifier-and-debugdiag/

gflags.exe -p /enable w3wp.exe /full
gflags.exe -p /enable ConsoleApplication1.exe /full

그러고 보니 예전에 ^^ 0xBAADF00D 쿠키를 확인하기 위해 사용해 본 적이 있었는데요.

Win32 Debug CRT Heap Internals의 0xBAADF00D 표시 재현
; https://www.sysnet.pe.kr/2/0/11255

옵션에 따라 할당 시점의 call stack을 가지고 있기 때문에 free/delete를 수행한 시점에 예외가 발생해도 어떤 메모리를 위해 할당한 것인지 구분할 수 있어 그와 연관된 코드를 좀 더 세심하게 찾아보는데 도움은 될 수 있습니다.

하지만, 저런 식으로 하면 Heap 관련 부가 정보가 더 점유하기 때문에 이전에는 CRT Header를 깨먹은 것도 gflags 이후에는 header가 아닐 수 있어 오히려 문제가 감춰지는 경우도 있습니다. (실제로 위의 예제 코드가 그런 경우입니다.) 이런저런 이유로 인해 이런 유의 문제를 해결하는 정답은 없습니다. 운이 좋다면, 깨진 header에 저장된 데이터를 보고... 만약 그것이 "파일 경로"인 듯한 데이터가 들어 있다면 프로그램에서 관련 데이터를 썼을 것 같은 코드를 범인으로 유추해 나가는 정도가 됩니다.

부가적으로 (Windows Heap이 아닌) CRT heap의 경우 _CrtIsMemoryBlock이라는 디버그 빌드에서만 사용 가능한 함수가 있습니다.

_CrtIsMemoryBlock
; https://learn.microsoft.com/ko-kr/cpp/c-runtime-library/reference/crtismemoryblock?view=vs-2019

그래도 이게 그나마 쓸만한데요, 다음과 같이 사용하면,

long requestNumber;
char* filename[MAX_PATH];
int linenumber;

printf("_CrtIsMemoryBlock == %d\n", _CrtIsMemoryBlock(cp, sizeof(char) * 10, &requestNumber,
    filename, &linenumber));

"(*(cp - 5))++;"로 깨진 바로 저 포인터를 넘겨서 해당 메모리가 유효한 CRT Heap의 구조를 가지고 있는지 체크해 줍니다. 물론, 그렇다고 해서 Header를 깬 위치를 알 수 있는 것은 아니고 의심이 가는 부분에 디버깅 용으로 저 코드를 심어놓고 assert 등의 처리를 해야 합니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 3/9/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13607정성태4/25/2024191닷넷: 2248.C# - 인터페이스 타입의 다중 포인터를 인자로 갖는 C/C++ 함수 연동
13606정성태4/24/2024203닷넷: 2247. C# - tensorflow 연동 (MNIST 예제)파일 다운로드1
13605정성태4/23/2024395닷넷: 2246. C# - Python.NET을 이용한 파이썬 소스코드 연동파일 다운로드1
13604정성태4/22/2024440오류 유형: 901. Visual Studio - Unable to set the next statement. Set next statement cannot be used in '[Exception]' call stack frames.
13603정성태4/21/2024710닷넷: 2245. C# - IronPython을 이용한 파이썬 소스코드 연동파일 다운로드1
13602정성태4/20/2024801닷넷: 2244. C# - PCM 오디오 데이터를 연속(Streaming) 재생 (Windows Multimedia)파일 다운로드1
13601정성태4/19/2024851닷넷: 2243. C# - PCM 사운드 재생(NAudio)파일 다운로드1
13600정성태4/18/2024885닷넷: 2242. C# - 관리 스레드와 비관리 스레드
13599정성태4/17/2024870닷넷: 2241. C# - WAV 파일의 PCM 사운드 재생(Windows Multimedia)파일 다운로드1
13598정성태4/16/2024893닷넷: 2240. C# - WAV 파일 포맷 + LIST 헤더파일 다운로드2
13597정성태4/15/2024880닷넷: 2239. C# - WAV 파일의 PCM 데이터 생성 및 출력파일 다운로드1
13596정성태4/14/20241072닷넷: 2238. C# - WAV 기본 파일 포맷파일 다운로드1
13595정성태4/13/20241052닷넷: 2237. C# - Audio 장치 열기 (Windows Multimedia, NAudio)파일 다운로드1
13594정성태4/12/20241069닷넷: 2236. C# - Audio 장치 열람 (Windows Multimedia, NAudio)파일 다운로드1
13593정성태4/8/20241084닷넷: 2235. MSBuild - AccelerateBuildsInVisualStudio 옵션
13592정성태4/2/20241219C/C++: 165. CLion으로 만든 Rust Win32 DLL을 C#과 연동
13591정성태4/2/20241200닷넷: 2234. C# - WPF 응용 프로그램에 Blazor App 통합파일 다운로드1
13590정성태3/31/20241079Linux: 70. Python - uwsgi 응용 프로그램이 k8s 환경에서 OOM 발생하는 문제
13589정성태3/29/20241154닷넷: 2233. C# - 프로세스 CPU 사용량을 나타내는 성능 카운터와 Win32 API파일 다운로드1
13588정성태3/28/20241270닷넷: 2232. C# - Unity + 닷넷 App(WinForms/WPF) 간의 Named Pipe 통신 [2]파일 다운로드1
13587정성태3/27/20241170오류 유형: 900. Windows Update 오류 - 8024402C, 80070643
13586정성태3/27/20241337Windows: 263. Windows - 복구 파티션(Recovery Partition) 용량을 늘리는 방법
13585정성태3/26/20241132Windows: 262. PerformanceCounter의 InstanceName에 pid를 추가한 "Process V2"
13584정성태3/26/20241251개발 환경 구성: 708. Unity3D - C# Windows Forms / WPF Application에 통합하는 방법파일 다운로드1
13583정성태3/25/20241472Windows: 261. CPU Utilization이 100% 넘는 경우를 성능 카운터로 확인하는 방법
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...