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

비밀번호

댓글 작성자
 




... 76  77  78  79  80  81  82  83  84  85  86  87  88  [89]  90  ...
NoWriterDateCnt.TitleFile(s)
11708정성태9/30/201822451개발 환경 구성: 401. .NET Core 콘솔 응용 프로그램을 배포(publish) 시 docker image 자동 생성 [2]파일 다운로드1
11707정성태9/30/201823814오류 유형: 489. ASP.NET Core를 docker에서 실행 시 "Failed with a critical error." 오류 발생 [1]
11706정성태9/29/201820000개발 환경 구성: 400. Synology NAS(DS216+II)에서 실행한 gcc의 Segmentation fault [2]
11705정성태9/29/201820814개발 환경 구성: 399. Synology NAS(DS216+II)에 gcc 컴파일러 설치
11704정성태9/29/201824872기타: 73. Synology NAS 신호음(beep) 끄기 [1]파일 다운로드1
11703정성태9/27/201819616개발 환경 구성: 398. Blazor 환경 구성 후 빌드 속도가 너무 느리다면? [2]
11702정성태9/26/201816822사물인터넷: 44. 넷두이노(Netduino)의 네트워크 설정 방법
11701정성태9/26/201822568개발 환경 구성: 397. 공유기를 일반 허브로 활용하는 방법파일 다운로드1
11700정성태9/21/201820656Graphics: 25. Unity - shader의 직교 투영(Orthographic projection) 행렬(UNITY_MATRIX_P)을 수작업으로 구성
11699정성태9/21/201819128오류 유형: 488. Add-AzureAccount 실행 시 "No subscriptions are associated with the logged in account in Azure Service Management (RDFE)." 오류
11698정성태9/21/201820292오류 유형: 487. 윈도우 성능 데이터를 원격 SQL에 저장하는 경우 "Call to SQLAllocConnect failed with %1." 오류 발생
11697정성태9/20/201819236Graphics: 24. Unity - unity_CameraWorldClipPlanes 내장 변수 의미
11696정성태9/19/201820166.NET Framework: 793. C# - REST API를 이용해 NuGet 저장소 제어파일 다운로드1
11695정성태9/19/201825287Graphics: 23. Unity - shader의 원근 투영(Perspective projection) 행렬(UNITY_MATRIX_P)을 수작업으로 구성
11694정성태9/17/201819543오류 유형: 486. nuget push 호출 시 405 Method Not Allowed 오류 발생
11693정성태9/16/201822707VS.NET IDE: 128. Unity - shader 코드 디버깅 방법
11692정성태9/13/201823036Graphics: 22. Unity - shader의 Camera matrix(UNITY_MATRIX_V)를 수작업으로 구성
11691정성태9/13/201819989VS.NET IDE: 127. Visual C++ / x64 환경에서 inline-assembly를 매크로 어셈블리로 대체하는 방법 - 두 번째 이야기
11690정성태9/13/201822931사물인터넷: 43. 555 타이머의 단안정 모드파일 다운로드1
11689정성태9/13/201822216VS.NET IDE: 126. 디컴파일된 소스에 탐색을 사용하도록 설정(Enable navigation to decompiled sources)
11688정성태9/11/201817557오류 유형: 485. iisreset - The data is invalid. (2147942413, 8007000d) 오류 발생
11687정성태9/11/201819444사물인터넷: 42. 사물인터넷 - 트랜지스터 다중 전압 테스트파일 다운로드1
11686정성태9/8/201818504사물인터넷: 41. 다중 전원의 소스를 가진 회로파일 다운로드1
11685정성태9/6/201818462사물인터넷: 40. 이어폰 소리를 capacitor로 필터링파일 다운로드1
11684정성태9/6/201821095개발 환경 구성: 396. pagefile.sys를 비활성화시켰는데도 working set 메모리가 줄어드는 이유파일 다운로드1
11683정성태9/5/201818707개발 환경 구성: 395. Azure Web App의 이벤트 로그를 확인하는 방법
... 76  77  78  79  80  81  82  83  84  85  86  87  88  [89]  90  ...