qt(C++) 에서 메모리 할당(malloc)후에 해제(free) 할때 세그멘테이션 에러가 나는데 왜 이러는지 모르겠네요
글쓴이: biokk / 작성시간: 목, 2014/04/24 - 5:35오후
생성자에서 메모리를 할당하구요
소멸자에서 메모리 해제하는 코드를 넣어놨느데요
생성자
test = (unsigned char*)malloc(512);
소멸자
if(test != NULL)
{
free(test)<---------------여기서 세그멘테이션
test= NULL;
}
이런식으로 처리하는데요
항상 free하는 부분에서 세그멘테이션 에러가 나더라구요
생성자에서 디버깅해서 메모리 할당하는것 확인까지 했는데도 이런 에러가 나는데요
다른 곳에서 메모리 해제 하는 데도 없는데 저러니깐 원인을 모르겠습니다.
프로그램 상에서 동적 메모리 할당(malloc)을 여러개 하는데 저 한곳에서만 저런 에러가 나는데요
메모리 할당을 많이 해서 그런가...원인이 무엇인지 모르겠네요
항상 세그멘테이션이 나는게 아니고..어떨때는 잘되고 어떨때는 에러가 나더라구요
감사합니다.
Forums:
?
이미 해제된 메모리를 다시 해제한다고 해서 세그먼테이션 오류가 나지는 않습니다.
물론 경우에 따라서 Double free bug 등의 취약점은 있을 수 있겠으나
당장 문제가 되는 부분은 아닙니다.
힙 해제시에 발생하는 세그먼테이션 오류는 보통 할당한 크기 이상으로
데이터를 쓰셨을 때 발생합니다. 가령 512바이트 할당했는데 1024바이트를 쓴다던가 하는 경우입니다.
malloc 과 같은 함수는 기본적으로 Double Linked List 등으로 내부적인 메모리 관리를 하기 때문에
힙과 힙 사이에는 항상 이런 부가적인 데이터가 들어 있으며, 할당된 크기 이상으로 쓰게 되면
Heap Corruption 이 발생할 수 밖에 없습니다.
또한, 그렇다고 30바이트 할당했는데 31바이트 쓴다고 해서 당장 에러가 나거나 하진 않습니다.
Visual Studio 의 Debug 모드 처럼 따로 힙 오버플로우가 발생했는지 체크해서 1바이트만 넘어도
오류 메시지를 표시해주는 경우가 아니면 그냥 Release 로 아무런 디버깅용 코드가 없는 경우
단지 할당된 공간 이상으로 쓴다고 해서 문제가 발생하지는 않습니다.
이는 또한 malloc 과 같은 함수들이 내부적으로 특정 크기의 배수로만 할당을 한다는 이유도 작용합니다.
페이징 때문에 이런 식으로 처리하며 따라서 실제로 쓰기 가능한 영역은 조금 더 많을 수 있습니다.
어쨌든 결론은 메모리를 쓰는 부분에서 오버플로우가 되지 않나 살펴보시기 바랍니다.
할당하지 않은 메모리를 해제하려 했는지 확인해보세요.
test에 메모리를 할당하지 않았더라도 생성자에서 빈 test에 NULL을 채우지 않았을 경우(종종 쓰레깃값이 채워지기도 하는데)메모리를 할당한 경우로 알고 알고리즘을 구현하셨다면 그것 때문에 free에서 에러가 발생했을 수 있습니다. 즉 할당하지도 않는 다른 곳의 메모리를 깨려하는 경우가 있을 수도 있는데, 혹시 그 경우가 아닐까요?
본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.
복사생성자같은 경로를 통해서 이중해제가 이뤄졌을거라
복사생성자같은 경로를 통해서 이중해제가 이뤄졌을거라 추측되는군요
이런 생각도 드는군요. 할당된 메모리가 프로그램의
이런 생각도 드는군요.
할당된 메모리가 프로그램의 실행 큐에서 사용되고 있엇고 free()할 때도 계속 사용되니까 segmentation fault가 나는 거라구요.
몇가지 팁..
일단 저도 맨 윗분 말씀대로 할당받은 영역 이상의 메모리를 사용했다에 한표입니다. 메모리를 사용하는 구간에서 바운더리를 초과했는지를 검사하는 코드를 넣어보시면 좋겠군요. (이걸 감시하는 툴들도 있습니다만 일단 생략하겠습니다.)
그리고 위에 나온 코드도 (비록 세그멘테이션 폴트와는 무관할 수 있지만) 멀티스레딩 환경에선 쓰기 어려워 보입니다. 혹시 멀티스레딩 환경이면 참고해보세요.
(1)번이 수행된 직후 (2)번이 수행되기 직전 다른 스레드에서 저 test 값을 참조할 수 있게 됩니다. (변수 자체는 프라이빗이라 해도 외부 메서드 등에 의해 참조될 수 있겠죠.) 따라서 여기서 추가적인 동기화를 해줘야 합니다.
프로그램 구조에 따라서 다음과 같이 바꾸는 것만으로 해결될 수도 있습니다만, 보통은 제대로 된 동기화를 해줘야 합니다.
이렇게 바꿔주면 워커 스레드에서 포인터를 체크해줄 경우 test를 사용하는 새 작업은 시작되지 않겠지만, 기존에 돌아가던 작업이 있었을 경우에는 여전히 문제가 발생하겠죠. 결국 완벽하게 해결하려면 동기화(또는 기타 비슷한 처리)를 해줘야 합니다.
그리고 또 한가지 아주 사소한 팁을 드리면.. free(0)은 에러를 발생하지 않습니다. 따라서 if문은 꼭 넣지는 않아도 됩니다.
--
댓글 달기