Valgrind x GStreamer

4日もアドベントカレンダーの更新できませんでした...
なぜかというと、インフルエンザ(´・ω・｀)ｶｷﾀﾒﾅｶｯﾀﾉｶﾞﾜﾙｲ

なんとか、25日までには遅れを取り戻したいなあ

-----

今日は [Valgrind](http://valgrind.org/) x GStreamer のハンズオン?的な内容です。

## valgrind でリークチェックをするための準備

Debian/Ubuntu 向けの方法を紹介します。

### valgrind のインストール

```sh
$ sudo apt-get install valgrind
```

### デバッグシンボルのパッケージをインストール

```sh
$ sudo apt-get install \
         libglib2.0-0-dbg \
         libgstreamer1.0-0-dbg \
         gstreamer1.0-plugins-base-dbg \
         gstreamer1.0-plugins-good-dbg \
         gstreamer1.0-plugins-ugly-dbg
```

※ この他で必要なパッケージがあれば一緒にインストールしておきましょう。

## リークしていないのにリークしていると言われる

何も考えずに、リークしていない gstreamer アプリ [noleak](https://gist.github.com/shocrunch/5ef915a82c48cab02b084a7edbfc158a) を valgrind に通すとこうなります。

```sh
$ valgrind ./noleak
==15558== memcheck, a memory error detector
==15558== copyright (c) 2002-2015, and gnu gpl'd, by julian seward et al.
==15558== using valgrind-3.12.0 and libvex; rerun with -h for copyright info
==15558== command: ./noleak
==15558==
==15558==
==15558== heap summary:
==15558==     in use at exit: 1,859,301 bytes in 23,260 blocks
==15558==   total heap usage: 39,354 allocs, 16,094 frees, 5,830,404 bytes allocated
==15558==
==15558== leak summary:
==15558==    definitely lost: 16,384 bytes in 1 blocks
==15558==    indirectly lost: 0 bytes in 0 blocks
==15558==      possibly lost: 4,764 bytes in 63 blocks
==15558==    still reachable: 1,746,929 bytes in 22,873 blocks
==15558==                       of which reachable via heuristic:
==15558==                         length64           : 240 bytes in 6 blocks
==15558==                         newarray           : 1,568 bytes in 18 blocks
==15558==         suppressed: 0 bytes in 0 blocks
==15558== rerun with --leak-check=full to see details of leaked memory
==15558==
==15558== for counts of detected and suppressed errors, rerun with: -v
==15558== error summary: 0 errors from 0 contexts (suppressed: 0 from 0)
```

`definitely lost: 16,384 bytes in 1 blocks` と言われ、まるでリークしているかのように言われてしまいます。

そこで、[suppression file](http://valgrind.org/docs/manual/manual-core.html#manual-core.suppress) の登場です。

## Suppression file を使う

GStreamer の suppression file は [gstreamer/common](https://cgit.freedesktop.org/gstreamer/common/tree/) から手に入れることができます。

valgrind に suppression file を指定し noleak のリークチェックを再度行ってみます。 

```sh
$ valgrind --suppressions=gstreamer/common/gst.supp ./noleak
==18190== Memcheck, a memory error detector
==18190== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==18190== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==18190== Command: ./noleak
==18190==
==18190==
==18190== HEAP SUMMARY:
==18190==     in use at exit: 1,859,301 bytes in 23,260 blocks
==18190==   total heap usage: 39,354 allocs, 16,094 frees, 5,830,404 bytes allocated
==18190==
==18190== LEAK SUMMARY:
==18190==    definitely lost: 0 bytes in 0 blocks
==18190==    indirectly lost: 0 bytes in 0 blocks
==18190==      possibly lost: 0 bytes in 0 blocks
==18190==    still reachable: 128,746 bytes in 1,200 blocks
==18190==                       of which reachable via heuristic:
==18190==                         length64           : 240 bytes in 6 blocks
==18190==                         newarray           : 1,568 bytes in 18 blocks
==18190==         suppressed: 1,639,331 bytes in 21,737 blocks
==18190== Rerun with --leak-check=full to see details of leaked memory
==18190==
==18190== For counts of detected and suppressed errors, rerun with: -v
==18190== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
```

メモリリークが無いことを証明できました :tada:
## メモリリークさせてみる

noleak の終了処理をおざなりにした [leak](https://gist.github.com/23d618f2a73e6f6dd1dd5f9d276d87f9) を作ったので、これを使ってためしてみましょう。ちなみに、ここからは GStreamer に限った話ではなく valgrind の話です。

```sh
$ valgrind --suppressions=/home/shotam/src/gst/common/gst.supp ./leak
==18227== Memcheck, a memory error detector
==18227== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==18227== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==18227== Command: ./leak
==18227==
==18227==
==18227== HEAP SUMMARY:
==18227==     in use at exit: 1,871,665 bytes in 23,333 blocks
==18227==   total heap usage: 39,231 allocs, 15,898 frees, 5,821,138 bytes allocated
==18227==
==18227== LEAK SUMMARY:
==18227==    definitely lost: 24 bytes in 1 blocks
==18227==    indirectly lost: 64 bytes in 1 blocks
==18227==      possibly lost: 0 bytes in 0 blocks
==18227==    still reachable: 136,342 bytes in 1,263 blocks
==18227==                       of which reachable via heuristic:
==18227==                         length64           : 240 bytes in 6 blocks
==18227==                         newarray           : 1,568 bytes in 18 blocks
==18227==         suppressed: 1,639,331 bytes in 21,737 blocks
==18227== Rerun with --leak-check=full to see details of leaked memory
==18227==
==18227== For counts of detected and suppressed errors, rerun with: -v
==18227== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
```

先程同様に、suppression fileを指定しましたがリークしているようです。valgrind は `--leak-check=yes` をつけることでリーク箇所を指摘してくれます。

```sh
$ valgrind --suppressions=/home/shotam/src/gst/common/gst.supp --leak-check=yes ./leak
==18373== Memcheck, a memory error detector
==18373== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==18373== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==18373== Command: ./leak
==18373==
==18373==
==18373== HEAP SUMMARY:
==18373==     in use at exit: 1,871,665 bytes in 23,333 blocks
==18373==   total heap usage: 39,231 allocs, 15,898 frees, 5,821,138 bytes allocated
==18373==
==18373== 88 (24 direct, 64 indirect) bytes in 1 blocks are definitely lost in loss record 1,553 of 2,010
==18373==    at 0x4C2ABAF: malloc (vg_replace_malloc.c:299)
==18373==    by 0x540BE08: g_malloc (gmem.c:94)
==18373==    by 0x5424342: g_slice_alloc (gslice.c:1025)
==18373==    by 0x5428522: g_string_sized_new (gstring.c:121)
==18373==    by 0x5428AD1: g_string_new (gstring.c:154)
==18373==    by 0x1089CD: main (leak.c:13)
==18373==
==18373== LEAK SUMMARY:
==18373==    definitely lost: 24 bytes in 1 blocks
==18373==    indirectly lost: 64 bytes in 1 blocks
==18373==      possibly lost: 0 bytes in 0 blocks
==18373==    still reachable: 136,342 bytes in 1,263 blocks
==18373==                       of which reachable via heuristic:
==18373==                         length64           : 240 bytes in 6 blocks
==18373==                         newarray           : 1,568 bytes in 18 blocks
==18373==         suppressed: 1,639,331 bytes in 21,737 blocks
==18373== Reachable blocks (those to which a pointer was found) are not shown.
==18373== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==18373==
==18373== For counts of detected and suppressed errors, rerun with: -v
==18373== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 64 from 64)
```

リーク箇所は [13行目の`g_string_new`](https://gist.github.com/shocrunch/23d618f2a73e6f6dd1dd5f9d276d87f9#file-leak-c-L13) であることがわかりました。[noleakの15行目](https://gist.github.com/shocrunch/5ef915a82c48cab02b084a7edbfc158a#file-noleak-c-L15) の `g_string_free` を加えてあげることでこれを修正することができます。

## まとめ

* GStreamer のメモリリークチェックは [valgrind](http://valgrind.org/) で行える
* `-dbg` のパッケージも忘れずにインストールすべし
* リークチェックするときには Suppression file を使うことで余計なリーク報告を除外できる
* GStreamer の Suppression file は [gstreamer/common](https://cgit.freedesktop.org/gstreamer/common/tree/) にある。
* Suppression fileは `--suppressions` オプションで使える
* メモリリークの箇所を調べるには `--leak-check=yes` をつける