Linux useful tool Valgrind(dynamic analysis). 02 Memcheck (leak)

Valgrind의 memcheck 기능 중 leak의 기능을 살펴보겠습니다.
이 기능은 heap메모리에 메모리 할당,메모리 해제을 분석합니다.

memory leak은 실행 시 '--leak-check' 옵션으로 추적할 수 있으며 기본 설정은 summry입니다.
* --leak-check=<no|summary|yes|full> [default: summary]

소스
빌드 및 실행
 $ cc -o hello hello.c -g3 -O0
 $ valgrind ./hello

결과
-bash-4.2$ valgrind ./hello
==31359== Memcheck, a memory error detector
==31359== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==31359== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==31359== Command: ./hello
==31359==
leak
==31359==
==31359== HEAP SUMMARY:
==31359==     in use at exit: 10 bytes in 1 blocks
==31359==   total heap usage: 1 allocs, 0 frees, 10 bytes allocated
==31359==
==31359== LEAK SUMMARY:
==31359==    definitely lost: 10 bytes in 1 blocks
==31359==    indirectly lost: 0 bytes in 0 blocks
==31359==      possibly lost: 0 bytes in 0 blocks
==31359==    still reachable: 0 bytes in 0 blocks
==31359==         suppressed: 0 bytes in 0 blocks
==31359== Rerun with --leak-check=full to see details of leaked memory
==31359==
==31359== For counts of detected and suppressed errors, rerun with: -v
==31359== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

위와 같이 실행하면 메모리 누수는 확인이 되었는데 어디서 누수가 발생했는지 알수가 없습니다.

아래와 같이 leak-check 옵션으로 레벨을 조정하면 메모리 누수 위치를 찾을 수 있습니다.
* debugging symbol이 같이 빌드되어야 합니다.

실행
 $ valgrind --leak-check=full ./hello


결과
-bash-4.2$ valgrind --leak-check=full ./hello
==31406== Memcheck, a memory error detector
==31406== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==31406== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==31406== Command: ./hello
==31406==
leak
==31406==
==31406== HEAP SUMMARY:
==31406==     in use at exit: 10 bytes in 1 blocks
==31406==   total heap usage: 1 allocs, 0 frees, 10 bytes allocated
==31406==
==31406== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1
==31406==    at 0x4A0645D: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==31406==    by 0x400637: main (hello.c:7)
==31406==
==31406== LEAK SUMMARY:
==31406==    definitely lost: 10 bytes in 1 blocks
==31406==    indirectly lost: 0 bytes in 0 blocks
==31406==      possibly lost: 0 bytes in 0 blocks
==31406==    still reachable: 0 bytes in 0 blocks
==31406==         suppressed: 0 bytes in 0 blocks
==31406==
==31406== For counts of detected and suppressed errors, rerun with: -v
==31406== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)


샘플 코드에서는 definitely lost(명백한 누수)에 대한 예제입니다.
각 항목 별 누수의 경우는 아래와 같습니다.
     Pointer chain            AAA Leak Case   BBB Leak Case
     -------------            -------------   -------------
(1)  RRR ------------> BBB                    DR
(2)  RRR ---> AAA ---> BBB    DR              IR
(3)  RRR               BBB                    DL
(4)  RRR      AAA ---> BBB    DL              IL
(5)  RRR ------?-----> BBB                    (y)DR, (n)DL
(6)  RRR ---> AAA -?-> BBB    DR              (y)IR, (n)DL
(7)  RRR -?-> AAA ---> BBB    (y)DR, (n)DL    (y)IR, (n)IL
(8)  RRR -?-> AAA -?-> BBB    (y)DR, (n)DL    (y,y)IR, (n,y)IL, (_,n)DL
(9)  RRR      AAA -?-> BBB    DL              (y)IL, (n)DL

Pointer chain legend:
- RRR: a root set node or DR block
- AAA, BBB: heap blocks
- --->: a start-pointer
- -?->: an interior-pointer

Leak Case legend:
- DR: Directly reachable
- IR: Indirectly reachable
- DL: Directly lost
- IL: Indirectly lost
- (y)XY: it's XY if the interior-pointer is a real pointer
- (n)XY: it's XY if the interior-pointer is not a real pointer
- (_)XY: it's XY in either case
*참조 Valgrind manual

Definitely lost(DL)는 3번 케이스와 같이 명확한 누수 경우 입니다.
Indirectly lost(IL)는 4,9번과 같이 root node가 손실되었고 이로 인해 하위에 있는 모든 블록이 손실된 경우 입니다.
Possibly lost는 5~8번과 같이 포인터 주소가 손실될 가능성이 있는 경우 입니다.
Still reachable는 1,2번의 경우 입니다. 일반적인 경우에는 문제가 되지 않습니다.

Possibly lost 예제.

getline함수는 첫번째 인자에 메모리를 할당해 줍니다. 이 메모리는 종료 전에 free를 해야하는데 abort가 발생하여 포인터가 정상 위치로 돌아갈것이라는 것이 불분명하기 때문에 possible lost입니다.

-bash-4.2$ valgrind --leak-check=full --show-leak-kinds=all  ./hello
==23840== Memcheck, a memory error detector
==23840== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==23840== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==23840== Command: ./hello
==23840==
input any : test
your input test

==23840==
==23840== HEAP SUMMARY:
==23840==     in use at exit: 120 bytes in 1 blocks
==23840==   total heap usage: 1 allocs, 0 frees, 120 bytes allocated
==23840==
==23840== 120 bytes in 1 blocks are possibly lost in loss record 1 of 1
==23840==    at 0x4A0645D: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==23840==    by 0x34CD46CDD4: getdelim (in /usr/lib64/libc-2.18.so)
==23840==    by 0x4006FD: main (hello.c:10)
==23840==
==23840== LEAK SUMMARY:
==23840==    definitely lost: 0 bytes in 0 blocks
==23840==    indirectly lost: 0 bytes in 0 blocks
==23840==      possibly lost: 120 bytes in 1 blocks
==23840==    still reachable: 0 bytes in 0 blocks
==23840==         suppressed: 0 bytes in 0 blocks
==23840==
==23840== For counts of detected and suppressed errors, rerun with: -v
==23840== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)
Aborted (core dumped)
-bash-4.2$


유용한 옵션
--leak-check=<no|summary|yes|full> [default: summary]
--show-leak-kinds=<set> [default: definite,possible]
 : definite,indirect,possible,reachable 또는 all 사용 가능


명령어 예제
valgrind --leak-check=full --show-leak-kinds=all --log-file="val.log" ./hello

댓글