[1. 개요]
C++ 코드 작성 시, 발생한 segmentation fault 사례 및 해결 방안 정리
[2. 예제]
#include <iostream>
#include <string>
#include <deque>
#include <cstring>
struct MyStruct {
long long a;
int b;
char c[32];
std::string d;
};
std::deque<MyStruct> dq;
void GetAndErase(MyStruct& ref)
{
if (dq.size() > 0) {
ref = dq.back(); // seg fault 가 발생하는 순간.
dq.pop_back();
}
}
int main()
{
{
MyStruct item;
strcpy(item.c, "Hello_World");
dq.push_front(item);
}
MyStruct elem;
memset(&elem, 0, sizeof(elem));
GetAndErase(elem);
std::cout << elem.c << std::endl;
std::cout << elem.d << std::endl;
return 0;
}
일단, 문제의 원인은 구조체 elem 의 초기화 에 있다.
- 구조체 MyStruct 는 마지막 멤버가 std::string 객체이다.
- std::string 의 내부 멤버 변수는 어떻게 되는지 알 수 없지만, 어떤 포인터 변수가 있으리라 생각 할 수 있다.
- memset 으로 인해, 이 포인터 변수는 0으로 초기화 된다. (nullptr 이 되버리는 것으로 볼 수 있나?)
- 이제, dq.back() 을 통해 std::string 을 복사 할 때 문제가 될 것으로 본다. (얕은 or 깊은 복사 ? )
- 위 예제의 exception 은 msvc 컴파일러에서 빌드한 경우 발생하지 않았다.
- 그 외, GNU 컴파일러에서만 발생하는 듯.
실제로 위 예제에서 memset 를 주석처리하면 exception 이 발생하지 않는다.
또, 아래 예제에서도 exception 이 발생하지 않는다.
- memset 를 사용하였음.
- 멤버 변수 d 의 초기화가 발생하였음.
- 정확한 원인은?
#include <iostream>
#include <string>
#include <deque>
#include <cstring>
struct MyStruct {
long long a;
int b;
char c[32];
std::string d;
};
std::deque<MyStruct> dq;
void GetAndErase(MyStruct& ref)
{
if (dq.size() > 0) {
ref = dq.back();
dq.pop_back();
}
}
int main()
{
{
MyStruct item;
strcpy(item.c, "Hello_World");
item.d = "New_World"; // 문자열 초기화.
dq.push_front(item);
}
MyStruct elem;
memset(&elem, 0, sizeof(elem));
GetAndErase(elem);
std::cout << elem.c << std::endl;
std::cout << elem.d << std::endl;
return 0;
}
[3. 결론]
class 나 struct 를 대상으로 memset 의 사용은 다소 위험할 수 있다.
- 내부 멤버 변수가 모두 primitive 한 자료형으로 되어있는 경우라면 상관 없지만...
- 가급적 초기화 함수 등을 정의하여 사용하도록 하는 편이 좋아 보임.
'분류대기' 카테고리의 다른 글
Socket, 멀티 캐스트 & 브로드 캐스트 (0) | 2025.03.09 |
---|---|
Segmentation fault 해결 (C++) (0) | 2025.03.04 |
윈도우 컴파일 에러. [No Target Architecture] (0) | 2025.03.04 |
소켓 Linger 옵션 (0) | 2025.02.26 |
[인코딩] EUCKR (0) | 2025.02.04 |