11

Clang++ 3.2 on ArchLinux (i686) is used to build the following C++11 codes

#include <iostream>
#include <functional>

typedef std::function<void ()> Action;
typedef std::function<int ()> Generator;

Action act(Generator const& gen)
{
    return [=]()
    {
        std::cout << gen() << std::endl;
    };
}

int main()
{
    static Generator const gen([]() { return 0; });
    act(gen);
    return 0;
}

With clang++ test.cpp -std=c++0x && valgrind --leak-check=full --log-file=tmp.log.memcheck ./a.out then I get

==600== HEAP SUMMARY:
==600==     in use at exit: 1 bytes in 1 blocks
==600==   total heap usage: 3 allocs, 2 frees, 18 bytes allocated
==600== 
==600== 1 bytes in 1 blocks are definitely lost in loss record 1 of 1
==600==    at 0x402B124: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==600==    by 0x8048D4F: std::_Function_base::_Base_manager<main::$_1>::_M_clone(std::_Any_data&, std::_Any_data const&, std::integral_constant<bool, false>) (in /home/neuront/a.out)
==600==    by 0x8048C21: std::_Function_base::_Base_manager<main::$_1>::_M_manager(std::_Any_data&, std::_Any_data const&, std::_Manager_operation) (in /home/neuront/a.out)
==600==    by 0x8049455: std::function<int ()>::function(std::function<int ()> const&) (in /home/neuront/a.out)
==600==    by 0x8049283: std::function<int ()>::function(std::function<int ()> const&) (in /home/neuront/a.out)
==600==    by 0x80489B1: act(std::function<int ()> const&) (in /home/neuront/a.out)
==600==    by 0x8048A6C: main (in /home/neuront/a.out)
==600== 
==600== LEAK SUMMARY:
==600==    definitely lost: 1 bytes in 1 blocks
==600==    indirectly lost: 0 bytes in 0 blocks
==600==      possibly lost: 0 bytes in 0 blocks
==600==    still reachable: 0 bytes in 0 blocks
==600==         suppressed: 0 bytes in 0 blocks
==600== 
==600== For counts of detected and suppressed errors, rerun with: -v
==600== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

I'm not sure whether there's any problem with that code (and causes just ONE byte leak), but there will be no memory leak if using g++ 4.7 to compile. Any suggestion about that?

neuront
  • 9,312
  • 5
  • 42
  • 71
  • 1
    FWIW it's reported with `-v --leakcheck=full` only on my Debian. Which means it's probably an exclusion already – sehe Mar 04 '13 at 08:31
  • 1
    I'd wager that if you got rid of the `static` then the "leak" would disappear. – ildjarn Mar 04 '13 at 10:34
  • @ildjarn In this case it doesn't matter if `gen` is `static` but in my program many objects share this functor. But I've noticed that the leak will also disappear if a new function object is constructed each time, other than a static one. Thanks for your advice. – neuront Mar 04 '13 at 11:33
  • This sounds like a wrong evaluation on the memory checker's side rather than a memory leak. – Etherealone Mar 17 '13 at 23:43

2 Answers2

1

The allocation is happening here:

    return [=]()

Which says "Capture everything that's not a parameter by value", including "std::cout" etc, which means making copies of them.

The following code passes the same compile & valgrind check without the errors, but with the caveat that the programmer is responsible for ensuring the lifetime of act's "gen" parameter is longer than the lifetime of the lambda.

#include <iostream>
#include <functional>

typedef std::function<void ()> Action;
typedef std::function<int ()> Generator;

Action act(Generator const& gen)
{
    return [&gen]()
    {
        std::cout << gen() << std::endl;
    };
}

int main()
{
    static Generator const gen([]() { return 0; });
    act(gen);
    return 0;
}

See also http://en.cppreference.com/w/cpp/language/lambda

kfsone
  • 23,617
  • 2
  • 42
  • 74
0

Static variables notoriously 'cause' these memory leaks in valgrind for complex objects which in addition allocate something on the heap (like for example STL containers etc).

In practice there is nothing to worry about, but of course it destroys the 'my program is free of leaks'-fact and makes real leaks harder to spot.

I would assume g++ just manages to keep the generator entirely in the BSS area while clang sees the need to allocate a byte on the heap.

Johannes Overmann
  • 4,914
  • 22
  • 38
  • Don't forget that you can generate a suppression for specific memory leaks using the `--gen-suppressions=yes` command line option for valgrind. – JS. Apr 17 '13 at 13:16