충돌 위치와 손상 위치는 다를 수 있다
Windows 프로그램에서 access violation은 허용되지 않는 메모리 읽기, 쓰기 또는 실행이 발생했을 때 볼 수 있는 예외입니다. 오류를 만난 명령어가 원인을 만든 명령어와 같지는 않을 수 있습니다. 앞에서 버퍼 경계를 넘어 쓴 값이 나중에 포인터로 사용되면서 충돌하기도 합니다. 그래서 예외가 난 줄을 다른 값으로 바꾸거나 널 검사만 추가하기 전에 무엇에 접근하려 했는지를 확인해야 합니다. 운영체제와 디버거가 보여주는 예외 표현은 다를 수 있으므로 DBG Desk에서는 정지 이유와 신호 이름, GDB 로그를 함께 확인합니다. 예외를 무시하고 계속 실행하면 처음 상태를 잃을 수 있습니다.
현재 명령어가 사용한 주소 계산하기
먼저 디스어셈블리의 현재 명령어를 보고 메모리를 읽는지 쓰는지 확인합니다. 주소가 레지스터 하나로 정해지는지, 기준 주소에 인덱스와 오프셋을 더해 만들어지는지도 봅니다. 예를 들어 잘못된 주소가 작은 숫자라면 널 포인터에 구조체 필드의 오프셋이 더해졌을 가능성을 조사할 수 있지만 그것만으로 확정할 수는 없습니다. 해당 레지스터가 어디서 값을 받았는지 이전 계산과 호출을 추적해야 합니다. 주소가 예상하는 객체의 범위에 들어가는지, 접근하는 크기가 영역 끝을 넘는지도 함께 확인하세요. 오류 메시지의 숫자 하나만 검색하는 것보다 구체적인 단서를 얻을 수 있습니다.
호출자가 지켜야 할 조건 확인하기
문자열 복사나 파일 처리 함수 안에서 멈췄다면 호출 스택을 보고 누가 포인터와 길이를 전달했는지 찾습니다. 길이는 문자 수인지 바이트 수인지, 끝 문자를 포함하는지, 대상 버퍼의 용량과 일치하는지 따로 점검합니다. 입력 크기가 특정 경계에 도달할 때만 실패한다면 경계 계산이 좋은 조사 대상입니다. 현재 실행에서 보이는 주소를 기록하는 것과 재현 조건을 기록하는 것은 다릅니다. 주소는 다음 실행에서 바뀔 수 있으므로 어떤 파일과 인수, 어떤 입력 크기로 충돌했는지를 남겨야 다른 세션에서도 같은 계산을 조사할 수 있습니다.
재현 가능한 입력으로 쓰기 시점 찾기
문제를 확인한 뒤에는 실패하는 입력을 가능한 작게 줄입니다. 큰 프로젝트에서만 나는 충돌이라도 특정 레코드나 요청 하나로 줄일 수 있으면 할당과 쓰기를 추적하기 쉬워집니다. 컴파일 환경이 지원한다면 AddressSanitizer 같은 도구로 경계를 벗어난 접근이나 해제 후 사용을 함께 검사하는 것도 방법입니다. DBG Desk 자체가 모든 메모리 오류를 자동 진단하는 것은 아닙니다. 정지 화면은 관찰 자료이며 수정의 근거는 입력, 수명, 경계 조건이 어떻게 어긋났는지에 있습니다. 수정 후에는 충돌했던 입력과 그 주변 크기의 입력을 다시 실행해 원인이 해결됐는지 확인하세요.
실패 입력을 기록하는 예
입력 파일을 읽다가 충돌했다면 파일 이름만 남기지 말고 레코드 수와 마지막 레코드의 크기처럼 실패를 가르는 조건을 기록합니다. 예를 들어 길이 15에서는 통과하고 16에서 실패한다면 두 입력을 함께 보관해 버퍼 용량과 종료 문자 처리를 비교할 수 있습니다. 정지한 명령어가 읽는 주소와 길이를 적으면 다음 실행에서 같은 논리적 접근을 찾기 쉬워집니다. 파일에 실제 고객 정보가 있다면 공개 가능한 데이터로 바꾼 뒤에도 동일한 오류가 나는지 확인해야 합니다. 수정 확인은 실패 파일 하나만 정상 종료하는지보다 인접한 크기의 입력이 모두 의도한 결과를 내는지를 기준으로 합니다.