Valgrindでのメモリリークチェックがおかしい件

概要

プログラム開発時に有用な Valgrind というツールがある。 Valgrindは色々なツールを提供してくれる。 この記事を書いた時点では以下のように書かれていて、6つのツールが提供されているとのこと。

The Valgrind distribution currently includes six production-quality tools: a memory error detector, two thread error detectors, a cache and branch-prediction profiler, a call-graph generating cache and branch-prediction profiler, and a heap profiler.

今回はこの中でもメモリチェックツールのお話。 Linux上でpthreadを使用している場合に常にメモリリークとなってしまう件。

環境は以下。 Vagrantで作成したdebian sid。

% uname -a
Linux debian 4.2.0-1-amd64 #1 SMP Debian 4.2.6-1 (2015-11-10) x86_64 GNU/Linux
% valgrind --version
valgrind-3.11.0

再現手順

メモリリークしないコード test.c を用意する。 pthread_create して pthread_join するだけの簡単なお仕事。

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void *test(void *arg)
{
    sleep(1);
    pthread_exit(NULL);
    return NULL;
}

int main(void)
{
    pthread_t th;

    printf("%d\n", pthread_create(&th, NULL, test, NULL));
    printf("%d\n", pthread_join(th, NULL));

    sleep(1);

    return(0);
}

スレッドとして起動する関数 test ではちょっと待ってから pthread_exit するだけ。 起動元では pthread_join してあげる。 これでスレッド用の資源が回収されるのでメモリリークはない。はずなのだが・・・。

このプログラムをコンパイルして、valgrindを実行してみる。

% gcc -Wall -g -lpthread -otest test.c
% valgrind --tool=memcheck \
  --leak-check=yes \
  --leak-resolution=high \
  --num-callers=40 \
  --undef-value-errors=no \
  --run-libc-freeres=no \
  -v ./test

結果は以下。

==1424== Memcheck, a memory error detector
==1424== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==1424== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==1424== Command: ./test
==1424==
--1424-- Valgrind options:
--1424--    --tool=memcheck
--1424--    --leak-check=yes
--1424--    --leak-resolution=high
--1424--    --num-callers=40
--1424--    --undef-value-errors=no
--1424--    --run-libc-freeres=no
--1424--    -v
--1424-- Contents of /proc/version:
--1424--   Linux version 4.2.0-1-amd64 (debian-kernel@lists.debian.org) (gcc version 4.9.3 (Debian 4.9.3-5) ) #1 SMP Debian 4.2.6-1 (2015-11-10)
--1424--
--1424-- Arch and hwcaps: AMD64, LittleEndian, amd64-cx16-rdtscp-sse3-avx
--1424-- Page sizes: currently 4096, max supported 4096
--1424-- Valgrind library directory: /usr/lib/valgrind
--1424-- Reading syms from /home/vagrant/tmp/test
--1424-- Reading syms from /lib/x86_64-linux-gnu/ld-2.19.so
--1424--   Considering /lib/x86_64-linux-gnu/ld-2.19.so ..
--1424--   .. CRC mismatch (computed 809091d5 wanted 33fd79cd)
--1424--   Considering /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.19.so ..
--1424--   .. CRC is valid
--1424-- Reading syms from /usr/lib/valgrind/memcheck-amd64-linux
--1424--   Considering /usr/lib/valgrind/memcheck-amd64-linux ..
--1424--   .. CRC mismatch (computed 2611121c wanted fdf174ed)
--1424--   Considering /usr/lib/debug/usr/lib/valgrind/memcheck-amd64-linux ..
--1424--   .. CRC is valid
--1424--    object doesn't have a dynamic symbol table
--1424-- Scheduler: using generic scheduler lock implementation.
--1424-- Reading suppressions file: /usr/lib/valgrind/default.supp
==1424== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-1424-by-vagrant-on-???
==1424== embedded gdbserver: writing to   /tmp/vgdb-pipe-to-vgdb-from-1424-by-vagrant-on-???
==1424== embedded gdbserver: shared mem   /tmp/vgdb-pipe-shared-mem-vgdb-1424-by-vagrant-on-???
==1424==
==1424== TO CONTROL THIS PROCESS USING vgdb (which you probably
==1424== don't want to do, unless you know exactly what you're doing,
==1424== or are doing some strange experiment):
==1424==   /usr/lib/valgrind/../../bin/vgdb --pid=1424 ...command...
==1424==
==1424== TO DEBUG THIS PROCESS USING GDB: start GDB like this
==1424==   /path/to/gdb ./test
==1424== and then give GDB the following command
==1424==   target remote | /usr/lib/valgrind/../../bin/vgdb --pid=1424
==1424== --pid is optional if only one valgrind process is running
==1424==
--1424-- REDIR: 0x4017960 (ld-linux-x86-64.so.2:strlen) redirected to 0x3809e1b1 (vgPlain_amd64_linux_REDIR_FOR_strlen)
--1424-- Reading syms from /usr/lib/valgrind/vgpreload_core-amd64-linux.so
--1424--   Considering /usr/lib/valgrind/vgpreload_core-amd64-linux.so ..
--1424--   .. CRC mismatch (computed 0900b121 wanted bb491432)
--1424--   Considering /usr/lib/debug/usr/lib/valgrind/vgpreload_core-amd64-linux.so ..
--1424--   .. CRC is valid
--1424-- Reading syms from /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so
--1424--   Considering /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so ..
--1424--   .. CRC mismatch (computed d60576bf wanted 177f5f93)
--1424--   Considering /usr/lib/debug/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so ..
--1424--   .. CRC is valid
==1424== WARNING: new redirection conflicts with existing -- ignoring it
--1424--     old: 0x04017960 (strlen              ) R-> (0000.0) 0x3809e1b1 vgPlain_amd64_linux_REDIR_FOR_strlen
--1424--     new: 0x04017960 (strlen              ) R-> (2007.0) 0x04c2c0e0 strlen
--1424-- REDIR: 0x4017710 (ld-linux-x86-64.so.2:index) redirected to 0x4c2bc80 (index)
--1424-- REDIR: 0x4017930 (ld-linux-x86-64.so.2:strcmp) redirected to 0x4c2d190 (strcmp)
--1424-- REDIR: 0x4018660 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x4c303b0 (mempcpy)
--1424-- Reading syms from /lib/x86_64-linux-gnu/libpthread-2.19.so
--1424--   Considering /lib/x86_64-linux-gnu/libpthread-2.19.so ..
--1424--   .. CRC mismatch (computed f433f5b8 wanted a1539920)
--1424--   Considering /usr/lib/debug/lib/x86_64-linux-gnu/libpthread-2.19.so ..
--1424--   .. CRC is valid
--1424-- Reading syms from /lib/x86_64-linux-gnu/libc-2.19.so
--1424--   Considering /lib/x86_64-linux-gnu/libc-2.19.so ..
--1424--   .. CRC mismatch (computed f7678cca wanted c4a92976)
--1424--   Considering /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.19.so ..
--1424--   .. CRC is valid
--1424-- REDIR: 0x50d7e20 (libc.so.6:strcasecmp) redirected to 0x4a23730 (_vgnU_ifunc_wrapper)
--1424-- REDIR: 0x50da110 (libc.so.6:strncasecmp) redirected to 0x4a23730 (_vgnU_ifunc_wrapper)
--1424-- REDIR: 0x50d75f0 (libc.so.6:memcpy@GLIBC_2.2.5) redirected to 0x4a23730 (_vgnU_ifunc_wrapper)
--1424-- REDIR: 0x50d5970 (libc.so.6:rindex) redirected to 0x4c2b960 (rindex)
--1424-- REDIR: 0x50ce990 (libc.so.6:calloc) redirected to 0x4c2ab60 (calloc)
--1424-- REDIR: 0x50de7b0 (libc.so.6:strchrnul) redirected to 0x4c2fee0 (strchrnul)
--1424-- REDIR: 0x50d77d0 (libc.so.6:__GI_mempcpy) redirected to 0x4c300e0 (__GI_mempcpy)
--1424-- REDIR: 0x50ce020 (libc.so.6:malloc) redirected to 0x4c28be0 (malloc)
--1424-- Reading syms from /lib/x86_64-linux-gnu/libgcc_s.so.1
--1424--   Considering /lib/x86_64-linux-gnu/libgcc_s.so.1 ..
--1424--   .. CRC mismatch (computed de5828bf wanted 0f4d8de1)
--1424--    object doesn't have a symbol table
--1424-- REDIR: 0x50d3c70 (libc.so.6:strlen) redirected to 0x4c2c020 (strlen)
--1424-- REDIR: 0x50ce660 (libc.so.6:free) redirected to 0x4c29e40 (free)
==1424==
==1424== HEAP SUMMARY:
==1424==     in use at exit: 1,942 bytes in 6 blocks
==1424==   total heap usage: 6 allocs, 0 frees, 1,942 bytes allocated
==1424==
==1424== Searching for pointers to 6 not-freed blocks
==1424== Checked 8,483,328 bytes
==1424==
==1424== 272 bytes in 1 blocks are possibly lost in loss record 4 of 6
==1424==    at 0x4C2AC15: calloc (vg_replace_malloc.c:711)
==1424==    by 0x4010FE1: allocate_dtv (dl-tls.c:296)
==1424==    by 0x40116ED: _dl_allocate_tls (dl-tls.c:460)
==1424==    by 0x4E3DC27: allocate_stack (allocatestack.c:589)
==1424==    by 0x4E3DC27: pthread_create@@GLIBC_2.2.5 (pthread_create.c:495)
==1424==    by 0x400728: main (test.c:16)
==1424==
==1424== LEAK SUMMARY:
==1424==    definitely lost: 0 bytes in 0 blocks
==1424==    indirectly lost: 0 bytes in 0 blocks
==1424==      possibly lost: 272 bytes in 1 blocks
==1424==    still reachable: 1,670 bytes in 5 blocks
==1424==         suppressed: 0 bytes in 0 blocks
==1424== Reachable blocks (those to which a pointer was found) are not shown.
==1424== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==1424==
==1424== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
==1424== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

この部分が「リークしているかも」と言われている。 これは明らかに pthread_create した分。

==1424== 272 bytes in 1 blocks are possibly lost in loss record 4 of 6
==1424==    at 0x4C2AC15: calloc (vg_replace_malloc.c:711)
==1424==    by 0x4010FE1: allocate_dtv (dl-tls.c:296)
==1424==    by 0x40116ED: _dl_allocate_tls (dl-tls.c:460)
==1424==    by 0x4E3DC27: allocate_stack (allocatestack.c:589)
==1424==    by 0x4E3DC27: pthread_create@@GLIBC_2.2.5 (pthread_create.c:495)
==1424==    by 0x400728: main (test.c:16)

うーむ・・・。