멈춘 함수와 원인을 만든 함수 구분하기
프로그램이 메모리 복사 함수에서 멈췄다고 해서 그 함수 자체가 잘못되었다고 단정할 수는 없습니다. 호출자가 잘못된 포인터나 길이를 전달했다면 실제 오류의 출발점은 더 위에 있습니다. 호출 스택은 현재 실행 위치까지 어떤 함수 호출을 거쳤는지 보여줍니다. 가장 위의 프레임은 지금 정지한 실행 문맥이고, 그 아래는 호출한 쪽의 문맥입니다. 먼저 현재 함수가 받아야 하는 값의 조건을 생각한 뒤 호출자가 그 조건을 지켰는지 확인하세요. 라이브러리 이름만 보고 조사 범위에서 빼거나 반대로 그 내부만 계속 따라가는 실수를 줄일 수 있습니다.
프레임마다 질문을 하나씩 정하기
예를 들어 파일을 읽다가 실패했다면 최상위에서는 어떤 읽기 함수가 실패했는지, 바로 위에서는 길이와 버퍼가 어떻게 결정됐는지, 그 위에서는 파일 경로가 어디서 왔는지를 봅니다. 모든 프레임에서 모든 변수를 찾기보다 각 호출이 전달한 값과 가정을 확인하는 방식입니다. DBG Desk의 현재 호출 스택 화면은 프레임 번호와 함수, 주소, 가능한 경우 소스 위치를 보여주는 읽기 전용 목록입니다. 프레임을 선택해 지역 변수를 탐색하는 UI는 아직 없습니다. 화면에서 확인한 경로를 재현 순서와 연결하고 필요한 함수에 중단점을 다시 설정해 값을 관찰할 수 있습니다.
목록이 짧거나 낯설게 보이는 이유
스택 목록이 예상보다 짧다고 항상 스택이 손상된 것은 아닙니다. 최적화 과정에서 함수가 인라인으로 합쳐지거나 꼬리 호출로 바뀌면 소스에 보이는 호출 구조와 디버거의 프레임이 다를 수 있습니다. 심볼이 없으면 함수 이름 대신 주소나 물음표가 표시되기도 합니다. 반대로 잘못된 메모리 쓰기로 반환 주소가 손상되면 스택 복원이 어려워질 수 있습니다. 이 경우 한 화면만으로 원인을 확정하기보다 빌드 설정, 디버그 정보, 직전의 호출과 반환 명령어를 함께 확인해야 합니다. 이름이 없다는 사실과 호출 경로를 복원하지 못했다는 사실은 서로 다른 문제입니다.
정상 경로와 실패 경로를 비교하기
호출 스택을 가장 유용하게 쓰는 방법 중 하나는 정상 입력과 실패 입력에서 같은 함수에 멈춰 보는 것입니다. 실패할 때만 나타나는 호출자가 있는지, 같은 호출자라도 다른 준비 과정을 거쳤는지 비교하면 조사 범위가 줄어듭니다. 로그에 함수 이름과 프레임 주소만 남기면 나중에 빌드가 바뀌었을 때 해석이 어려워질 수 있으므로 실행 파일 정보와 입력도 함께 기록하세요. 여러 스레드가 있는 프로그램에서는 현재 화면이 모든 스레드의 전체 상태를 대표하지 않는다는 점도 중요합니다. 지금 정지한 스레드의 경로를 먼저 이해한 뒤 다른 실행 흐름과의 관계를 조사합니다.
같은 함수가 여러 번 보일 때
재귀 함수라면 같은 이름의 프레임이 연속으로 나타나는 것이 정상일 수 있습니다. 이름이 반복된다는 이유만으로 무한 재귀라고 결론 내리기보다 종료 조건에 도달하는 입력이 전달되는지 확인하세요. 정상 입력에서 깊이가 줄어드는 경로와 실패 입력에서 계속 늘어나는 경로를 비교하면 판단할 수 있습니다. 프레임 수가 빠르게 증가한다면 함수 입구에 중단점을 두고 재귀 호출 직전의 인수가 어떻게 바뀌는지 보는 방법이 있습니다. 한 단계씩 들어갈 때마다 값이 문제를 작은 범위로 줄이는지 기록해 보세요. 실제로 종료되지 않는지와 단지 깊은 호출인지를 구별한 뒤 수정해야 합니다.