malloc ()가 어떻게 sigsegv를 유발할 수 있습니까?
문제
나는 내 프로그램에 이상한 버그가 있습니다. Malloc ()가 Sigsegv를 일으키는 것으로 보입니다. 동적 목록을 위해 SimClist라는 라이브러리를 사용하고 있습니다.
다음은 나중에 참조되는 구조물입니다.
typedef struct {
int msgid;
int status;
void* udata;
list_t queue;
} msg_t;
그리고 여기 코드가 있습니다.
msg_t* msg = (msg_t*) malloc( sizeof( msg_t ) );
msg->msgid = msgid;
msg->status = MSG_STAT_NEW;
msg->udata = udata;
list_init( &msg->queue );
list_init
프로그램이 실패하는 곳입니다. List_Init의 코드는 다음과 같습니다.
/* list initialization */
int list_init(list_t *restrict l) {
if (l == NULL) return -1;
srandom((unsigned long)time(NULL));
l->numels = 0;
/* head/tail sentinels and mid pointer */
l->head_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
l->tail_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
l->head_sentinel->next = l->tail_sentinel;
l->tail_sentinel->prev = l->head_sentinel;
l->head_sentinel->prev = l->tail_sentinel->next = l->mid = NULL;
l->head_sentinel->data = l->tail_sentinel->data = NULL;
/* iteration attributes */
l->iter_active = 0;
l->iter_pos = 0;
l->iter_curentry = NULL;
/* free-list attributes */
l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS * sizeof(struct list_entry_s *));
l->spareelsnum = 0;
#ifdef SIMCLIST_WITH_THREADS
l->threadcount = 0;
#endif
list_attributes_setdefaults(l);
assert(list_repOk(l));
assert(list_attrOk(l));
return 0;
}
라인 l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS *
스택 추적에 따라 SIGSEGV가 발생하는 곳입니다. 디버깅을 위해 GDB/Nemiver를 사용하고 있지만 손실 중입니다. 이 기능이 처음이라고 불리는 것은 잘 작동하지만 항상 두 번째로 실패합니다. malloc ()가 어떻게 sigsegv를 유발할 수 있습니까?
이것은 스택 추적입니다.
#0 ?? () at :0
#1 malloc () at :0
#2 list_init (l=0x104f290) at src/simclist.c:205
#3 msg_new (msg_switch=0x1050dc0, msgid=8, udata=0x0) at src/msg_switch.c:218
#4 exread (sockfd=8, conn_info=0x104e0e0) at src/zimr-proxy/main.c:504
#5 zfd_select (tv_sec=0) at src/zfildes.c:124
#6 main (argc=3, argv=0x7fffcabe44f8) at src/zimr-proxy/main.c:210
모든 도움이나 통찰력은 대단히 감사합니다!
해결책
malloc
예를 들어 힙이 손상되었을 때 예를 들어 Segfault 할 수 있습니다. 이전 할당의 범위를 넘어서는 것을 쓰지 않는지 확인하십시오.
다른 팁
아마도 메모리 위반은 코드의 다른 부분에서 발생할 수 있습니다. 당신이 리눅스에 있다면, 당신은 반드시 Valgrind를 시도해야합니다. Valgrind를 통과하지 않으면 내 자신의 C 프로그램을 결코 신뢰하지 않을 것입니다.
편집 : 또 다른 유용한 도구입니다 전기 울타리. glibc도 다음을 제공합니다 malloc_check_ 메모리 문제를 디버깅하는 데 도움이되는 환경 변수. 이 두 가지 방법은 Valgrind만큼 달리기 속도에 영향을 미치지 않습니다.
이 호출 전에 버퍼 오버플로 또는 free
할당되지 않은 포인터로 malloc
(또는 이미 해방되었습니다).
Malloc에서 사용하는 내부 데이터 구조가 이런 식으로 손상되면 Malloc은 유효하지 않은 데이터를 사용하여 충돌 할 수 있습니다.
코어 덤프를 유발하는 무수한 방법이 있습니다. malloc()
(그리고 realloc()
그리고 calloc()
). 여기에는 다음이 포함됩니다.
- 버퍼 오버 플로우 : 할당 된 공간의 끝을 넘어서 쓰기 (제어 정보 트램핑
malloc()
거기에 보관하고 있었다). - 버퍼 언더 플로우 : 할당 된 공간이 시작되기 전의 쓰기 (제어 정보 트램핑
malloc()
거기에 보관하고 있었다). - 할당되지 않은 메모리를 자유롭게합니다
malloc()
. 혼합 된 C 및 C ++ 프로그램에서 C ++에 할당 된 프리링 메모리가 포함됩니다.new
. - 할당 된 메모리 블록을 통해 부품을 가리키는 포인터를 제거합니다.
malloc()
- 이전 사례의 특별한 경우입니다. - 이미 해방 된 포인터를 해제 - 악명 높은 '더블 프리'.
진단 버전 사용 malloc()
또는 시스템 표준 버전에서 진단을 활성화하면 이러한 문제 중 일부를 식별하는 데 도움이 될 수 있습니다. 예를 들어, 작은 언더 플로우와 오버 플로우를 감지 할 수 있습니다 (요청한 공간 주위에 버퍼 영역을 제공하기 위해 추가 공간을 할당하기 때문에), 아마도 할당되지 않았거나 이미 풀려난 자유 메모리에 대한 시도를 감지 할 수 있습니다. 또는 할당 된 공간을 통해 부분적으로 포인터를 포인터 - 할당 된 공간과 별도로 저장하기 때문입니다. 비용은 디버깅 버전이 더 많은 공간을 차지하는 것입니다. 정말 좋은 할당자는 스택 추적 및 라인 번호를 기록하여 코드에서 할당이 어디에서 발생했는지 또는 첫 번째 자유가 발생한 위치를 알려줄 수 있습니다.
문제가 실제로 Segfault가 생성되는 위치에 있는지 확인하려면이 코드를 분리하여 디버깅해야합니다. (나는 그것이 아니라고 생각합니다).
이것은 다음을 의미합니다.
#1 : GDB가 올바른 줄 번호 정보를 얻을 수 있도록 -o0으로 코드를 컴파일하십시오.
#2 : 코드 의이 부분을 호출하는 단위 테스트를 작성하십시오.
내 생각에 별도로 사용하면 코드가 올바르게 작동한다는 것입니다. 그런 다음 버그의 원인을 찾을 때까지 같은 방식으로 다른 모듈을 테스트 할 수 있습니다.
다른 사람들이 제안한 것처럼 Valgrind를 사용하는 것도 아주 좋은 생각입니다.
코드는 문제가됩니다. Malloc이 NULL을 반환하면 코드 에서이 케이스가 올바르게 처리되지 않습니다. 당신은 단순히 기억이 실제로 없었을 때 당신을 위해 할당되었다고 가정합니다. 이것은 메모리 손상을 유발할 수 있습니다.