~76 kB memory leak per client instance
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Canonical System Image |
Fix Released
|
High
|
Unassigned | ||
net-cpp |
Fix Released
|
Critical
|
Thomas Voß | ||
net-cpp (Ubuntu) |
Fix Released
|
Undecided
|
Unassigned |
Bug Description
net-cpp leaks memory for each http client instance. To reproduce:
#include <core/net/
int main()
{
core:
}
==22658==
==22658== HEAP SUMMARY:
==22658== in use at exit: 78,572 bytes in 1,040 blocks
==22658== total heap usage: 13,600 allocs, 12,560 frees, 446,676 bytes allocated
==22658==
...
==22658== LEAK SUMMARY:
==22658== definitely lost: 512 bytes in 1 blocks
==22658== indirectly lost: 77,996 bytes in 1,037 blocks
==22658== possibly lost: 0 bytes in 0 blocks
==22658== still reachable: 64 bytes in 2 blocks
Dropping a bit of trace into the library shows that the Handle::Private struct is never destroyed:
multi::
: handle(
keep_
timeout(
{
std::cerr << "initializing" << std::endl;
}
multi::
{
std::cerr << "cleaning up" << std::endl;
multi:
}
This prints "initializing", but doesn't print "cleaning up".
Checking the use count of the multi::Handle member of http::Client in the Client destructor shows that the use count is 2 when the Client goes out of scope.
The leak is caused here:
multi::
{
auto holder = new Holder<Private>{d};
set_
set_
set_
set_
set_
}
The Holder that is allocated here is never deleted and points at the Private a second time.
Related branches
- Michi Henning (community): Approve
- PS Jenkins bot: Needs Fixing (continuous-integration)
-
Diff: 484 lines (+149/-91)4 files modifieddebian/control (+0/-1)
src/core/net/http/impl/curl/easy.cpp (+19/-9)
src/core/net/http/impl/curl/easy.h (+38/-12)
src/core/net/http/impl/curl/multi.cpp (+92/-69)
Changed in canonical-devices-system-image: | |
importance: | Undecided → High |
milestone: | none → ww13-ota |
status: | New → In Progress |
Changed in net-cpp: | |
importance: | Undecided → Critical |
assignee: | nobody → Thomas Voß (thomas-voss) |
status: | New → In Progress |
Changed in canonical-devices-system-image: | |
status: | In Progress → Fix Released |
Changed in net-cpp: | |
status: | In Progress → Fix Released |
With the MP attached to this bug, the leaks are gone, except for a spurious one on shutdown that can be attributed to CURL. Quoting from the original MP discussion here:
Running the load test in a loop, after maybe a hundred iterations or so, I got a valgrind complaint:
==29504== valgrind/ vgpreload_ memcheck- amd64-linux. so) asio::detail: :thread_ info_base: :allocate( boost:: asio::detail: :thread_ info_base* , unsigned long) (thread_ info_base. hpp:60) asio::asio_ handler_ allocate( unsigned long, ...) (handler_ alloc_hook. ipp:50) handler_ alloc_helpers: :allocate< curl::multi: :Handle: :Private: :Timeout: :Private: :async_ wait_for( std::weak_ ptr<curl: :multi: :Handle: :Private> const&, std::chrono: :duration< long, std::ratio<1l, 1000l> > const&) ::{lambda( boost:: system: :error_ code const&) #1}>(unsigned long, curl::multi: :Handle: :Private: :Timeout: :Private: :async_ wait_for( std::weak_ ptr<curl: :multi: :Handle: :Private> const&, std::chrono: :duration< long, std::ratio<1l, 1000l> > const&) ::{lambda( boost:: system: :error_ code const&)#1}&) (handler_ alloc_helpers. hpp:37) asio::detail: :deadline_ timer_service< boost:: asio::time_ traits< boost:: posix_time: :ptime> >::async_ wait<curl: :multi: :Handle: :Private: :Timeout: :Private: :async_ wait_for( std::weak_ ptr<curl: :multi: :Handle: :Private> const&, std::chrono: :duration< long, std::ratio<1l, 1000l> > const&) ::{lambda( boost:: system: :error_ code const&) #1}>(boost: :asio:: detail: :deadline_ timer_service< boost:: asio::time_ traits< boost:: posix_time: :ptime> >::implementati on_type& , curl::multi: :Handle: :Private: :Timeout: :Private: :async_ wait_for( std::weak_ ptr<curl: :multi: :Handle: :Private> const&, std::chrono: :duration< long, std::ratio<1l, 1000l> > const&) ::{lambda( boost:: system: :error_ code const&)#1}&) (deadline_ timer_service. hpp:185) asio::async_ result< boost:: asio::handler_ type<curl: :multi: :Handle: :Private: :Timeout: :Private: :async_ wait_for( std::weak_ ptr<curl: :multi: :Handle: :Private> const&, std::chrono: :duration< long, std::ratio<1l, 1000l> > const&) ::{lambda( boost:: system: :error_ code const&)#1}, void (boost: :system: :error_ code)>: :type>: :type boost:: asio::deadline_ timer_service< boost:: posix_time: :ptime, boost:: asio::time_ traits< boost:: posix_time: :ptime> >::async_ wait<curl: :multi: :Handle: :Private: :Timeout: :Private: :async_ wait_for( std::weak_ ptr<curl: :multi: :Handle: :Private> const&, std::chrono: :duration< long, std::ratio<1l, 1000l> > const&) ::{lambda( boost:: system: :error_ code const&) #1}>(boost: :asio:: detail: :deadline_ timer_service< boost:: asio::time_ traits< boost:: posix_time: :ptime> >::implementati on_type& , boost:: asio::handler_ type&&) (deadline_ timer_service. hpp:149) asio::async_ result< boost:: ...
==29504== HEAP SUMMARY:
==29504== in use at exit: 161,360 bytes in 1,769 blocks
==29504== total heap usage: 325,601 allocs, 323,832 frees, 54,917,164 bytes allocated
==29504==
==29504== 161,296 (73 direct, 161,223 indirect) bytes in 1 blocks are definitely lost in loss record 64 of 64
==29504== at 0x4C2B100: operator new(unsigned long) (in /usr/lib/
==29504== by 0x4E8A699: boost::
==29504== by 0x4E8A7A8: boost::
==29504== by 0x4E883DE: void* boost_asio_
==29504== by 0x4E87F56: void boost::
==29504== by 0x4E87CA1: boost::
==29504== by 0x4E87B93: boost::