1. ホーム
  2. C++

Valgrind がメモリ管理エラーを検出する

2022-02-21 16:17:38

への頷き

一般的なメモリ割り当てには、静的ストレージ、スタック割り当て、ヒープ割り当ての3種類があります。グローバル変数は静的でコンパイル時に割り当てられ、関数内のローカル変数はスタックに割り当てられ、最も柔軟にメモリを使えるのがヒープ割り当てで、動的メモリ割り当てとも呼ばれる。

よく使われる動的メモリ割り当て関数には malloc, alloc, realloc, new 等があり、動的解放関数には free, delete 等がある。

ダイナミックメモリの要求が成功したら、自分で管理する必要がありますが、ここが一番失敗しやすいところです。

よくある間違いは以下の通りです。

  • アプリケーションとリリースの不一致:アプリケーションとリリースの混在

  • リクエストとリリースの不一致:リクエストとリリースの数が一致しない

  • リリース後、いつでも読み書きが可能

II 動的メモリ管理エラー例

#include<iostream>
#include<stdlib.h>
int main(){
    int i;
        char *p= (char *)malloc(10);
        char *pt=p;
        for(i=0;i<10;i++){
                p[i]='z';
        }
        delete p;
        pt[1]='x';
        free(pt);
    return 0;
}

III コンパイルと実行

[root@localhost charpter05]# . /0513
*** Error in `. /0513': double free or corruption (fasttop): 0x00000000015b2010 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x7c619)[0x7fd177b80619]
. /0513[0x400821]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7fd177b25c05]
. /0513[0x4006f9]
======= Memory map: ========
00400000-00401000 r-xp 00000000 fd:00 67443254 /root/omc++/charpter05/0513
00600000-00601000 r--p 00000000 fd:00 67443254 /root/omc++/charpter05/0513
00601000-00602000 rw-p 00001000 fd:00 67443254 /root/omc++/charpter05/0513
015b2000-015d3000 rw-p 00000000 00:00 0 [heap]
7fd170000000-7fd170021000 rw-p 00000000 00:00 0
7fd170021000-7fd174000000 ---p 00000000 00:00 0
7fd177b04000-7fd177cbc000 r-xp 00000000 fd:00 33585750 /usr/lib64/libc-2.17.so
7fd177cbc000-7fd177ebc000 ---p 001b8000 fd:00 33585750 /usr/lib64/libc-2.17.so
7fd177ebc000-7fd177ec0000 r--p 001b8000 fd:00 33585750 /usr/lib64/libc-2.17.so
7fd177ec0000-7fd177ec2000 rw-p 001bc000 fd:00 33585750 /usr/lib64/libc-2.17.so
7fd177ec2000-7fd177ec7000 rw-p 00000000 00:00 0
7fd177ec7000-7fd177edc000 r-xp 00000000 fd:00 33554691 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7fd177edc000-7fd1780db000 ---p 00015000 fd:00 33554691 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7fd1780db000-7fd1780dc000 r--p 00014000 fd:00 33554691 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7fd1780dc000-7fd1780dd000 rw-p 00015000 fd:00 33554691 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7fd1780dd000-7fd1781de000 r-xp 00000000 fd:00 33585758 /usr/lib64/libm-2.17.so
7fd1781de000-7fd1783dd000 ---p 00101000 fd:00 33585758 /usr/lib64/libm-2.17.so
7fd1783dd000-7fd1783de000 r--p 00100000 fd:00 33585758 /usr/lib64/libm-2.17.so
7fd1783de000-7fd1783df000 rw-p 00101000 fd:00 33585758 /usr/lib64/libm-2.17.so
7fd1783df000-7fd1784c8000 r-xp 00000000 fd:00 33554693 /usr/lib64/libstdc++.so.6.0.19
7fd1784c8000-7fd1786c8000 ---p 000e9000 fd:00 33554693 /usr/lib64/libstdc++.so.6.0.19
7fd1786c8000-7fd1786d0000 r--p 000e9000 fd:00 33554693 /usr/lib64/libstdc++.so.6.0.19
7fd1786d0000-7fd1786d2000 rw-p 000f1000 fd:00 33554693 /usr/lib64/libstdc++.so.6.0.19
7fd1786d2000-7fd1786e7000 rw-p 00000000 00:00 0
7fd1786e7000-7fd178708000 r-xp 00000000 fd:00 33585742 /usr/lib64/ld-2.17.so
7fd1788f9000-7fd1788fe000 rw-p 00000000 00:00 0
7fd178906000-7fd178908000 rw-p 00000000 00:00 0
7fd178908000-7fd178909000 r--p 00021000 fd:00 33585742 /usr/lib64/ld-2.17.so
7fd178909000-7fd17890a000 rw-p 00022000 fd:00 33585742 /usr/lib64/ld-2.17.so
7fd17890a000-7fd17890b000 rw-p 00000000 00:00 0
7fffe0f6a000-7fffe0f8b000 rw-p 00000000 00:00 0 [stack]
7fffe0ffb000-7fffe0ffd000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted (core dumped)

この時点でプログラムはコアダンプの状態になっています。

IV Valgrindでメモリ管理エラーを検出する

[root@localhost charpter05]# valgrind . /0513
==19563== Memcheck, a memory error detector
==19563== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==19563== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==19563== Command: . /0513
===19563===
==19563== Mismatched free() / delete / delete []
==19563== at 0x4C2B46D: operator delete(void*) (vg_replace_malloc.c:586)
==19563== by 0x400809: main (0513.cpp:10)
==19563== Address 0x5a1a040 is 0 bytes inside a block of size 10 alloc'd
==19563== at 0x4C29EC3: malloc (vg_replace_malloc.c:309)
==19563== by 0x4007CE: main (0513.cpp:5)
===19563===
==19563== Invalid write of size 1
==19563== at 0x400812: main (0513.cpp:11)
==19563== Address 0x5a1a041 is 1 bytes inside a block of size 10 free'd
==19563== at 0x4C2B46D: operator delete(void*) (vg_replace_malloc.c:586)
==19563== by 0x400809: main (0513.cpp:10)
==19563== Block was alloc'd at
==19563== at 0x4C29EC

V解析

1 次の出力は、10 行目の allocate と release 関数の間の不整合を示しています。

==19563== Mismatched free() / delete / delete []
==19563== at 0x4C2B46D: operator delete(void*) (vg_replace_malloc.c:586)
==19563== by 0x400809: main (0513.cpp:10)
==19563== Address 0x5a1a040 is 0 bytes inside a block of size 10 alloc'd
==19563== at 0x4C29EC3: malloc (vg_replace_malloc.c:309)
==19563== by 0x4007CE: main (0513.cpp:5)

2 次の出力は、11 行目で送信された不正な書き込みエラーを示しています。

==19563== Invalid write of size 1
==19563== at 0x400812: main (0513.cpp:11)
==19563== Address 0x5a1a041 is 1 bytes inside a block of size 10 free'd
==19563== at 0x4C2B46D: operator delete(void*) (vg_replace_malloc.c:586)
==19563== by 0x400809: main (0513.cpp:10)
==19563== Block was alloc'd at
==19563== at 0x4C29EC3: malloc (vg_replace_malloc.c:309)
==19563== by 0x4007CE: main (0513.cpp:5)

3 次の出力は、12 行目のフリーメモリー関数が無効であることを示しています。

==19563== Invalid free() / delete / delete[] / realloc()
==19563== at 0x4C2AFBD: free (vg_replace_malloc.c:540)
==19563== by 0x400820: main (0513.cpp:12)
==19563== Address 0x5a1a040 is 0 bytes inside a block of size 10 free'd
==19563== at 0x4C2B46D: operator delete(void*) (vg_replace_malloc.c:586)
==19563== by 0x400809: main (0513.cpp:10)
==19563== Block was alloc'd at
==19563== at 0x4C29EC3: malloc (vg_replace_malloc.c:309)
==19563== by 0x4007CE: main (0513.cpp:5)

4 プログラムが不正にメモリを読み書きしてもコアダンプが発生するとは限りませんが、無効なメモリを解放すると発生します。