뇌 마음 반반저장소

[42] valgrind로 메모리 누수 찾기 본문

좌뇌/왕초보의 컴퓨터 언어 세계

[42] valgrind로 메모리 누수 찾기

맹진저 2023. 1. 10. 00:17
728x90

memory leak을 찾는 프로그램 Valgrind를 친구들이 많이 쓰는 것을 보았다. 일단 설치하자.

$ sudo apt-get install valgrind

설치 후 프로그램을 실행할 때 앞에 valgrind 만 붙여주면 된다. 일부러 free를 하지 않고 코드 하나를 만들어 봤다.

#include <stdio.h>
#include <stdlib.h>

void    main()
{
    char    *str;

    str = malloc(sizeof(char) * 10);
    str =  "Valgrind test!";
    printf("%s\n", str);
}

free가 없는 malloc 함수를 하나 만들었다.

$ gcc valgrind_test.c 
$ ./a.out
Valgrind test!

실행은 잘 되지만 valgrind를 사용해서 프로그램을 돌려보면,

$ valgrind ./a.out
==3729== Memcheck, a memory error detector
==3729== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.        
==3729== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info     
==3729== Command: ./a.out
==3729==
Valgrind test!
==3729== 
==3729== HEAP SUMMARY:
==3729==     in use at exit: 10 bytes in 1 blocks
==3729==   total heap usage: 2 allocs, 1 frees, 1,034 bytes allocated #2개 빌렸는데 1개만 free되었다.
==3729==
==3729== LEAK SUMMARY:
==3729==    definitely lost: 10 bytes in 1 blocks #이곳을 잘 보자
==3729==    indirectly lost: 0 bytes in 0 blocks
==3729==      possibly lost: 0 bytes in 0 blocks
==3729==    still reachable: 0 bytes in 0 blocks
==3729==         suppressed: 0 bytes in 0 blocks
==3729== Rerun with --leak-check=full to see details of leaked memory #더 자세한 메모리 누수를 확인할 수 있다.
==3729==
==3729== For lists of detected and suppressed errors, rerun with: -s
==3729== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

이렇게 길게 나온다는 것은 뭔가 문제가 있다는 소리다. 위의 설명을 보면 1개가 해제가 안된 것을 볼 수 있다.

아래의 명령어를 추가하면 어디서 누수가 되었는지 자세한 함수를 설명해 준다.

$ valgrind --leak-check=full ./a.out
==3740== Memcheck, a memory error detector
==3740== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.        
==3740== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info     
==3740== Command: ./a.out
==3740==
Valgrind test!
==3740== 
==3740== HEAP SUMMARY:
==3740==     in use at exit: 10 bytes in 1 blocks
==3740==   total heap usage: 2 allocs, 1 frees, 1,034 bytes allocated
==3740==
==3740== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1
==3740==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==3740==    by 0x10917E: main (in /mnt/c/Users/.../a.out) #요 함수들에서 안된걸 확인할 수 있다.
==3740==
==3740== LEAK SUMMARY:
==3740==    definitely lost: 10 bytes in 1 blocks
==3740==    indirectly lost: 0 bytes in 0 blocks
==3740==      possibly lost: 0 bytes in 0 blocks
==3740==    still reachable: 0 bytes in 0 blocks
==3740==         suppressed: 0 bytes in 0 blocks
==3740==
==3740== For lists of detected and suppressed errors, rerun with: -s
==3740== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

free를 추가해서 메모리를 모두 해제해 보자.

$ valgrind ./a.out     
==3859== Memcheck, a memory error detector
==3859== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.        
==3859== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info     
==3859== Command: ./a.out
==3859==
Valgrind test!
==3859== Invalid free() / delete / delete[] / realloc()
==3859==    at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==3859==    by 0x1091C5: main (in /mnt/c/Users/MJi/Desktop/Ecole/복습/a.out)    
==3859==  Address 0x10a004 is in a r-- mapped file /mnt/c/Users/MJi/Desktop/Ecole/복습/a.out segment
==3859==
==3859== 
==3859== HEAP SUMMARY:
==3859==     in use at exit: 100 bytes in 1 blocks
==3859==   total heap usage: 2 allocs, 2 frees, 1,124 bytes allocated #잘 해제가 되었다.
==3859==
==3859== LEAK SUMMARY:
==3859==    definitely lost: 100 bytes in 1 blocks #홋? 이건 무슨 뜻일까?
==3859==    indirectly lost: 0 bytes in 0 blocks
==3859==      possibly lost: 0 bytes in 0 blocks
==3859==    still reachable: 0 bytes in 0 blocks
==3859==         suppressed: 0 bytes in 0 blocks
==3859== Rerun with --leak-check=full to see details of leaked memory
==3859==
==3859== For lists of detected and suppressed errors, rerun with: -s
==3859== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

LEAK SUMMARY에 아직 문제가 있는 부분이 있다. 위의 다섯 가지 카테고리가 뭔지 확인해 보자.

 

definitely lost / 확실히 손실됨 : 확실히 손실된 첫 번째 범주는 해당 메모리를 사용하거나 복구할 방법이 없기 때문에 일반적으로 추적해야 할 가장 시급한 누출 유형이다.
indirectly lost / 간접적으로 손실됨 : 주소 포인터를 잃어버린 경우
possibly lost / 손실 가능성 : 주소 포인터가 해제되지 않고 남아있는 경우
still reachable / 여전히 도달 가능: 종료 직전까지 메모리를 차지하는 경우
suppressed / 억제됨 : 라이브러리 혹은 외부 프로세스 간에 메로리를 공유하는 과정에서의 누수

 

그래서 str에 직접 문자열을 넣지 않고 메모리에 문자열을 복사해주는 함수인 memcpy를 사용하니 해결되었다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int    main()
{
    char    *str;

    str = malloc(sizeof(char) * 100);
    memcpy(str, "Valgrind test!", strlen(str));
    printf("%s\n", str);
    free(str);
    return(0);
}
$ valgrind ./a.out
==4032== Memcheck, a memory error detector
==4032== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.        
==4032== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info     
==4032== Command: ./a.out
==4032==
==4032== Invalid read of size 1
==4032==    at 0x483EF54: strlen (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4032==    by 0x48E0433: puts (ioputs.c:35)
==4032==    by 0x1091E6: main (in /mnt/c/Users/MJi/Desktop/Ecole/복습/a.out)    
==4032==  Address 0x4a5104e is 0 bytes after a block of size 14 alloc'd
==4032==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4032==    by 0x1091BE: main (in /mnt/c/Users/MJi/Desktop/Ecole/복습/a.out)    
==4032==
Valgrind test!
==4032== 
==4032== HEAP SUMMARY:
==4032==     in use at exit: 0 bytes in 0 blocks
==4032==   total heap usage: 2 allocs, 2 frees, 1,038 bytes allocated
==4032==
==4032== All heap blocks were freed -- no leaks are possible
==4032==
==4032== For lists of detected and suppressed errors, rerun with: -s
==4032== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

 

728x90
Comments