Segmentatin fault 에러, 어떠한 이유일까요??
초보가 또 왔습니다. ;;
어떤 오픈소스에 제가 작성한 소스를 추가해서 리눅스에서 gcc로 컴파일을 완료했습니다.
컴파일은 문제가 없구요, 제가 작성한 부분도 문제 없이 지나갑니다.
그런데, calloc를 하는 부분에서 갑자기
Program received signal SIGSEGV, Segmentation fault.
0x00000034a6e7051b in malloc_consolidate () from /lib64/libc.so.6
이런 에러메세지가 발생합니다.
GDB로 line by line 보다가 저 메세지가 출력되면서 멈추네요.
해당 부분은 calloc를 이용하는 부분이라 했지만, 정확히 말하면 calloc를 이용해 함수를 만들어서 NNEW(sti,double,6*mi[0]*ne) 이렇게 연산하는 부분입니다.
이 함수는
#define NNEW(a,b,c) a=(b *)u_calloc((c),sizeof(b),__FILE__,__LINE__,#a)
void *u_calloc(size_t num,size_t size,const char *file,const int line, const char* ptr_name){
void *a;
char *env;
a=calloc(num,size);
....
}
이런 식으로 정의가 됩니다.1
값을 추적해보니, mi[0]도, ne도 정상적인 값이 들어갔는데, 왜 저런 에러메세지가 나오는 걸까요???
혹시, c라이브러리가 구형이라 그런걸까요??;;
(libc.so.6 를 열어보니
GNU C Library stable release version 2.5, by Roland McGrath et al.
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.1.2 20080704 (Red Hat 4.1.2-50).
Compiled on a Linux 2.6.9 system on 2011-01-30.
Available extensions:
The C stubs add-on version 2.1.2.
crypt add-on version 2.1 by Michael Glad and others
GNU Libidn by Simon Josefsson
GNU libio by Per Bothner
NIS(YP)/NIS+ NSS modules 0.19 by Thorsten Kukuk
Native POSIX Threads Library by Ulrich Drepper et al
BIND-8.2.3-T5B
RT using linux kernel aio
Thread-local storage support included.
For bug reporting instructions, please see:
.
요롷게 나왔습니다.)
현재 gcc버전은 software collection 으로 4.8.2 를 쓰고 있습니다.
파라미터에 정확히 어떤 값들이 들어가서 오류가 나는지
파라미터에 정확히 어떤 값들이 들어가서 오류가 나는지 프린트를 찍어보는게 제일 좋은 방법일 것 같습니다..
아래 코드로 테스트 해봤는데 잘 되네요.
테스트 환경은 다음과 같습니다.
$ gcc --version
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Package: libc6
Priority: required
Section: libs
Installed-Size: 10496
Maintainer: Ubuntu Developers
Original-Maintainer: GNU Libc Maintainers
Architecture: amd64
Source: eglibc
Version: 2.19-0ubuntu6
Replaces: libc6-amd64
Provides: glibc-2.19-1
Depends: libgcc1
Suggests: glibc-doc, debconf | debconf-2.0, locales
---------------------------------
제일 왼쪽이 저입니다 :)
프린트로는..
프린트로는 확인했습니다.
올바르지 않은 값이 아닌걸로 확인되었거든요.
컴파일러가 그냥 넘어가는 곳에서 문제가 발생하는 것 같아요.
답변 감사합니다!! ㅎㅎㅎㅎ
valgrind
valgrind를 설치하신 다음 valgrind (본인의 실행파일) 하고 실행하시면 99%의 확률로 버그를 잡을 수 있습니다.
..."제가 작성한 부분도 문제 없이 지나갑니다."에서 문제가 생겼다는 데 오백원 겁니다.
Valgrind를 설치해서 쓰고 있습니다.
말씀하신 valgrind를 좀전에 설치해서 쓰고 있습니다. 메모리 누수가 문제인거 같네요.
에러메세지에서도 malloc이 문제라 했는데, valgrind설명을 보니 malloc와 free에 대한 언급이 있더라구요.
그리고, 방금 실행해보니, '문제없이 지나간 부분' 에서 문제가 발생했네요. ㅋㅋㅋㅋㅋㅋㅋㅋ
뭐 이런식의..
==21818== Invalid read of size 8
==21818== at 0x57CB1B: get_geom_info (get_geom_info.c:300)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818== Address 0x55ff3b8 is 0 bytes after a block of size 88 alloc'd
==21818== at 0x4A07BEE: realloc (in /opt/rh/devtoolset-2/root/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==21818== by 0x5781E1: u_realloc (u_realloc.c:35)
==21818== by 0x57C8D7: get_geom_info (get_geom_info.c:281)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818==
==21818== Invalid write of size 8
==21818== at 0x57CB25: get_geom_info (get_geom_info.c:300)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818== Address 0x55ff3b8 is 0 bytes after a block of size 88 alloc'd
==21818== at 0x4A07BEE: realloc (in /opt/rh/devtoolset-2/root/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==21818== by 0x5781E1: u_realloc (u_realloc.c:35)
==21818== by 0x57C8D7: get_geom_info (get_geom_info.c:281)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818==
==21818== Invalid read of size 2
==21818== at 0x34A6E622D4: fwrite (in /lib64/libc-2.5.so)
==21818== by 0x57CB6F: get_geom_info (get_geom_info.c:311)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818== Address 0x1 is not stack'd, malloc'd or (recently) free'd
==21818==
==21818==
==21818== Process terminating with default action of signal 11 (SIGSEGV)
==21818== Access not within mapped region at address 0x1
==21818== at 0x34A6E622D4: fwrite (in /lib64/libc-2.5.so)
==21818== by 0x57CB6F: get_geom_info (get_geom_info.c:311)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818== If you believe this happened as a result of a stack
==21818== overflow in your program's main thread (unlikely but
==21818== possible), you can try to increase the size of the
==21818== main thread stack using the --main-stacksize= flag.
==21818== The main thread stack size used in this run was 10485760.
==21818==
==21818== HEAP SUMMARY:
==21818== in use at exit: 456,298 bytes in 112 blocks
==21818== total heap usage: 620 allocs, 508 frees, 723,272,833 bytes allocated
==21818==
==21818== 8 bytes in 1 blocks are definitely lost in loss record 17 of 112
==21818== at 0x4A06775: calloc (in /opt/rh/devtoolset-2/root/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==21818== by 0x578036: u_calloc (u_calloc.c:41)
==21818== by 0x57AB1F: get_geom_info (get_geom_info.c:44)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818==
==21818== 8 bytes in 1 blocks are definitely lost in loss record 18 of 112
==21818== at 0x4A06775: calloc (in /opt/rh/devtoolset-2/root/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==21818== by 0x578036: u_calloc (u_calloc.c:41)
==21818== by 0x57AB41: get_geom_info (get_geom_info.c:45)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818==
==21818== 12 bytes in 1 blocks are definitely lost in loss record 30 of 112
==21818== at 0x4A06775: calloc (in /opt/rh/devtoolset-2/root/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==21818== by 0x578036: u_calloc (u_calloc.c:41)
==21818== by 0x57AAFD: get_geom_info (get_geom_info.c:43)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818==
==21818== 64 bytes in 1 blocks are definitely lost in loss record 57 of 112
==21818== at 0x4A06775: calloc (in /opt/rh/devtoolset-2/root/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==21818== by 0x578036: u_calloc (u_calloc.c:41)
==21818== by 0x57C63F: get_geom_info (get_geom_info.c:246)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818==
==21818== 96 bytes in 1 blocks are possibly lost in loss record 68 of 112
==21818== at 0x4A07BEE: realloc (in /opt/rh/devtoolset-2/root/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==21818== by 0x5781E1: u_realloc (u_realloc.c:35)
==21818== by 0x57C0D6: get_geom_info (get_geom_info.c:183)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818==
==21818== 192 bytes in 1 blocks are definitely lost in loss record 84 of 112
==21818== at 0x4A07BEE: realloc (in /opt/rh/devtoolset-2/root/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==21818== by 0x5781E1: u_realloc (u_realloc.c:35)
==21818== by 0x57C8AB: get_geom_info (get_geom_info.c:280)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818==
==21818== 536 (24 direct, 512 indirect) bytes in 1 blocks are definitely lost in loss record 101 of 112
==21818== at 0x4A079E8: malloc (in /opt/rh/devtoolset-2/root/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==21818== by 0x4DE6F98: ??? (in /usr/lib64/libgfortran.so.3.0.0)
==21818== by 0x4E996E7: ??? (in /usr/lib64/libgfortran.so.3.0.0)
==21818== by 0x4E93C92: ??? (in /usr/lib64/libgfortran.so.3.0.0)
==21818== by 0x4DE6E57: ??? (in /usr/lib64/libgfortran.so.3.0.0)
==21818== by 0x4EA7575: ??? (in /usr/lib64/libgfortran.so.3.0.0)
==21818== by 0x4DE3932: ??? (in /usr/lib64/libgfortran.so.3.0.0)
==21818== by 0x52D2FFF: ??? (in /usr/lib64/libgomp.so.1.0.0)
==21818== by 0x34A660D1BA: call_init (in /lib64/ld-2.5.so)
==21818== by 0x34A660D2C4: _dl_init (in /lib64/ld-2.5.so)
==21818== by 0x34A6600AA9: ??? (in /lib64/ld-2.5.so)
==21818== by 0x1: ???
==21818==
==21818== LEAK SUMMARY:
==21818== definitely lost: 308 bytes in 6 blocks
==21818== indirectly lost: 512 bytes in 1 blocks
==21818== possibly lost: 96 bytes in 1 blocks
==21818== still reachable: 455,382 bytes in 104 blocks
==21818== suppressed: 0 bytes in 0 blocks
==21818== Reachable blocks (those to which a pointer was found) are not shown.
==21818== To see them, rerun with: --leak-check=full --show-reachable=yes
==21818==
==21818== For counts of detected and suppressed errors, rerun with: -v
==21818== ERROR SUMMARY: 14 errors from 10 contexts (suppressed: 7 from 7)
Segmentation fault
하하하하;;;;
오늘 밤 할 일이 생겼군요. ㅋㅋㅋㅋㅋ
(이렇게 메모리가 누수되는 것과 fopen등의 명령어가 제대로 실행되지 않는 것이 연관이 있나요???)
...
메모리가 새는 것은 문제일 수도 있고 아닐 수도 있지만 더 심각한 문제는 로그 처음의 다음 부분입니다.
요약하자면 get_geom_info라는 함수에서 realloc을 불러 88바이트의 공간을 할당했는데 쓰면 안되는 88번째 바이트부터 8바이트 크기의 영역을 읽고 썼다는 얘기입니다.
그 부분은 십중팔구 메모리 할당에 관련된 정보가 들어있을 테니 이곳에 쓰기를 하면 그 이후 malloc/free/realloc 등등이 전부 깨질 수 있습니다. 다시 말해 그 시점부터 프로그램의 정상 동작은 보장이 안됩니다.
==21818== Invalid read of size 8
==21818== at 0x57CB1B: get_geom_info (get_geom_info.c:300)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818== Address 0x55ff3b8 is 0 bytes after a block of size 88 alloc'd
==21818== at 0x4A07BEE: realloc (in /opt/rh/devtoolset-2/root/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==21818== by 0x5781E1: u_realloc (u_realloc.c:35)
==21818== by 0x57C8D7: get_geom_info (get_geom_info.c:281)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818==
==21818== Invalid write of size 8
==21818== at 0x57CB25: get_geom_info (get_geom_info.c:300)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
==21818== Address 0x55ff3b8 is 0 bytes after a block of size 88 alloc'd
==21818== at 0x4A07BEE: realloc (in /opt/rh/devtoolset-2/root/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==21818== by 0x5781E1: u_realloc (u_realloc.c:35)
==21818== by 0x57C8D7: get_geom_info (get_geom_info.c:281)
==21818== by 0x40BEDE: main (ccx_2.8p2.c:614)
감사합니다.
아하.... 그렇군요.
Valgrind설명을 찾아도 요건 쉽게 찾을 수 없었는데, 하하... 그런 뜻이었군요.
지금 제 생각으로는, 한 루프에서 200번 정도 realloc을 하는데, 거기서 메모리 할당에 문제가 생길 가능성이 있을 것 같네요.;;
짬을내서 코드 구성을 간단히 말씀해드리면, main에서 calloc으로 포인터 배열을 (사이즈는 보수적으로 크게하고) 선언합니다. 그리고 서브루틴으로 들어가서 이 배열의 정확한 사이즈를 찾고, 배열에 올바른 값을 넣어줍니다. 그 과정에서 한 포인터 배열은 앞에서 말씀드린 것 처럼 realloc을 200번 정도 수행하게 되요.
어제 pointer관련 책을 찾다보니, 'realloc으로 사이즈를 줄이거나 늘일수는 있지만, 줄이는 것이 낫다. 늘이는 것은 기존에 할당된 공간과 연속적인 것을 보장할 수 없고, 값의 초기화도 보장할 수 없다.' 라는 문장을 봤었습니다. (ref. C포인터의 이해와 활용 / 리처드 리스 지음, 조인중 강성용 옮김). 한 포인터 배열을 제외하고서는 사이즈를 줄이는 목적으로 realloc을 하는데, 200번 반복하는 저놈은 한 번은 줄였다가 점차 사이즈를 늘여가면서 값을 넣는 구성으로 코드를 짰거든요. 흠... 그래서 이런 문제가 발생하지 않았나 추측합니다.
(무슨 말인지 이해가 되실런지.;;??)
이 문제를 해결하기 위해선
1. 사이즈를 조사한 뒤 한 번만 realloc을 한다.
2. main에서 보수적으로 사이즈를 할당했으니, 함수에서 값을 다 넣고난 뒤 main으로 나와서 realloc한다.
어느게 나은 방법일까요??;;
C로 처음 코드를 짜보는지라, 특히 메모리관리에 대한 개념이 없어요. ㅎㅎㅎ;;;
아무것도 모르는 놈이라 답답하셨을텐데, 친절히 답해주셔서 감사합니다!
좋은 답변 감사합니다!!
...
쓰신 부분을 봐서는 제대로 이해하신 건지 아닌지 잘 모르겠어서-_- 노파심에 부연 설명을 하자면,
메모리 할당을 많이 해서 성능에 문제가 생기는 것과 메모리를 잘못 써서 프로그램이 죽는 것은 전혀 별개의 문제입니다.
전자의 경우 프로그램이 느려지기는 하지만 어쨌든 충분히 기다리면 기대하던 결과가 나오는 거고, 후자는 그냥 잘못된 프로그램이라서 언제 어떻게 죽어도 이상하지 않은 상황입니다.
* 물론 같은 데이터에 대고 realloc을 200번 하는 것은 대단한 삽질이므로 그렇게 안 하는 편이 백배(이백배?) 낫습니다. 일단 realloc을 한번만 할 수 있게 코드를 고치면 코드도 단순해질 테니 그 다음에 여전히 포인터 버그가 있나 확인해 보시는 걸 추천합니다.
댓글 달기