id summary reporter owner description type status milestone component version severity resolution keywords cc 6844 [function] Memory leaks if used with allocator and throwing copy-c'tor of functor Daniel Krügler Douglas Gregor "There are two places where the implementation of boost::function uses a user-provided allocator: 1. boost/function/function_base.hpp, line 485 2. boost/function/function_template.hpp, line 591 Both use cases do not protected against a possibly throwing copy constructor of a function-object because there is an unprotected two-step sequence of the following style: {{{ wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1); wrapper_allocator.construct(copy, functor_wrapper_type(f,a)); }}} If the second step fails, no clean-up of the allocated memory takes place. The following test program emulates this situation and demonstrates the problem: {{{ #include ""boost/function.hpp"" #include #include struct F { static bool dothrow; unsigned char prevent_short_object_opt[sizeof(boost::detail::function::function_buffer) + 1]; F(){} F(const F&) { if (dothrow) throw 0; } void operator()() {} }; bool F::dothrow = false; int alloc_cnt = 0; template struct my_alloc : std::allocator { template struct rebind { typedef my_alloc other; }; void construct(typename std::allocator::pointer p, const T& val) { F::dothrow = true; ::new((void *)p) T(val); } void deallocate(typename std::allocator::pointer p, typename std::allocator::size_type n) { --alloc_cnt; std::cout << ""deallocate: "" << alloc_cnt << std::endl; return std::allocator::deallocate(p, n); } typename std::allocator::pointer allocate(typename std::allocator::size_type n) { ++alloc_cnt; std::cout << ""allocate: "" << alloc_cnt << std::endl; return std::allocator::allocate(n); } }; int main() { F f; my_alloc a; try { boost::function fu(f, a); } catch (int) { std::cout << ""Caught expected - allocation count: "" << alloc_cnt << std::endl; } } }}} The program outputs {{{ allocate: 1 Caught expected - allocation count: 1 }}} on all systems I tested (Visual Studio 11 beta and mingw with gcc 4.8) showing that the deallocation function is never called. The two-step process of allocation+construct needs to be made exception-safe. In my own type-erased allocators I'm using a helper type {{{ template struct allocated_ptr { typedef typename Alloc::pointer pointer; explicit allocated_ptr(Alloc& alloc) : alloc(alloc), ptr(alloc.allocate(1)) {} ~allocated_ptr() { if (ptr != pointer()) { alloc.deallocate(ptr, 1); } } pointer get() const { return ptr; } pointer release() { pointer result = ptr; ptr = pointer(); return result; } private: Alloc& alloc; pointer ptr; }; }}} to handle this, invoking the release function, after successful construction. Of-course other means are possible. " Bugs new To Be Determined function Boost 1.49.0 Problem