실무활용 가능성 실험
강제종료시 호출스택 남기는 방법
무한 나무
2023. 6. 23. 21:21
#include <iostream>
#include <csignal>
#include <execinfo.h>
void signalHandler(int signum) {
std::cout << "Received signal:" << signum << std::endl;
/* Get the backtrace*/
const int MAX_FRAMES = 100;
void* frames[MAX_FRAMES];
int numFrames = backtrace(frames, MAX_FRAMES);
char** symbols = backtrace_symbols(frames, numFrames);
if (symbols != nullptr) {
for (int i = 0; i < numFrames; ++i) {
// symbols[i] 로 호출함수 이름 얻어서 기록하기
}
free(symbols);
}
/* Terminate the program */
std::exit(signum);
}
int main() {
// Register the signal handler
std::signal(SIGSEGV, signalHandler); // Handle segmentation fault signal
std::signal(SIGABRT, signalHandler);
std::signal(SIGILL, signalHandler);
// Your program code
return 0;
}
위 예제에서 signalHandler 함수는 시그널 핸들러로 등록됩니다. 여기서는 SIGSEGV 시그널(세그멘테이션 폴트)을 처리하는 예시로 작성되었습니다. 시그널 핸들러가 호출되면 해당 시그널 번호와 호출 스택 정보를 로그에 출력한 후, std::exit() 함수를 사용하여 프로그램을 강제 종료합니다.
backtrace() 함수와 backtrace_symbols() 함수를 사용하여 호출 스택 정보를 얻을 수 있습니다. 이를 활용하여 로그에 출력할 수 있습니다. 호출 스택 정보를 얻기 위해서는 컴파일 시 -rdynamic 옵션을 사용하여 실행 파일에 심볼 정보를 포함해야 합니다.
위 예제는 SIGSEGV 시그널에 대한 핸들러로 작성되었지만, 다른 시그널에 대해서도 동일한 방식으로 핸들러를 등록하고 호출 스택 정보를 얻을 수 있습니다. 시그널 핸들러를 등록하는 부분은 main() 함수 시작 전에 수행되어야 합니다.
SIGSEGV ("Segmentation Violation")
시스템에서 발생하는 예외적인 상황 중 하나로, 프로그램이 잘못된 메모리 접근을 시도할 때 발생합니다. 예를 들어, 잘못된 포인터를 역참조하거나, 할당되지 않은 메모리를 접근하려고 할 때 발생할 수 있습니다. SIGSEGV 시그널은 프로그램이 더 이상 안전하게 진행될 수 없는 메모리 오류를 나타내며, 기본적으로는 프로그램을 강제로 종료시킵니다.
SIGABRT (Abort Signal):
- SIGABRT는 프로그램 자체가 비정상적인 상황을 감지하여 스스로를 중단하고자 할 때 발생하는 시그널입니다.
- 주로 abort() 함수가 호출되었을 때 발생하며, 프로그램이 심각한 오류를 감지하고 중단해야 할 때 사용됩니다.
- 일반적으로 프로그램 내부의 논리 오류나 잘못된 상태를 감지할 때 사용되며, 디버깅이나 예외 처리에 활용될 수 있습니다.
SIGILL (Illegal Instruction Signal):
- SIGILL은 프로세스가 비정상적인 명령어나 명령어의 시퀀스를 수행하려고 할 때 발생하는 시그널입니다.
- 주로 잘못된 기계어 명령어, 잘못된 CPU 명령어 또는 CPU 아키텍처와 관련된 문제가 발생했을 때 발생합니다.
- 일반적으로 프로그램 내부에서 잘못된 명령어 실행을 감지하고 처리해야 할 때 사용됩니다.
- SIGILL은 보안 관련 문제나 호환성 문제 등을 확인하는 데에도 사용될 수 있습니다.