This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug libstdc++/63840] New: std::function copy constructor deletes an uninitialized pointer if new fails
- From: "tavianator at gmail dot com" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Wed, 12 Nov 2014 20:46:20 +0000
- Subject: [Bug libstdc++/63840] New: std::function copy constructor deletes an uninitialized pointer if new fails
- Auto-submitted: auto-generated
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63840
Bug ID: 63840
Summary: std::function copy constructor deletes an
uninitialized pointer if new fails
Product: gcc
Version: 5.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: tavianator at gmail dot com
Created attachment 33953
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=33953&action=edit
Reproducer
std::function's copy constructor looks like this:
template<typename _Res, typename... _ArgTypes>
function<_Res(_ArgTypes...)>::
function(const function& __x)
: _Function_base()
{
if (static_cast<bool>(__x))
{
_M_invoker = __x._M_invoker;
_M_manager = __x._M_manager;
__x._M_manager(_M_functor, __x._M_functor, __clone_functor);
}
}
_M_manager(..., __clone_functor) calls _M_clone, which looks like this when the
functor is stored on the heap:
static void
_M_clone(_Any_data& __dest, const _Any_data& __source, false_type)
{
__dest._M_access<_Functor*>() =
new _Functor(*__source._M_access<_Functor*>());
}
If operator new or the copy-constructor throws, __dest._M_pod_data remains
uninitialized. Then the stack unwinds, and ~_Function_base() gets called:
~_Function_base()
{
if (_M_manager)
_M_manager(_M_functor, _M_functor, __destroy_functor);
}
Which ultimately calls
static void
_M_destroy(_Any_data& __victim, false_type)
{
delete __victim._M_access<_Functor*>();
}
Which deletes _M_pod_data. A simple fix could be:
template<typename _Res, typename... _ArgTypes>
function<_Res(_ArgTypes...)>::
function(const function& __x)
: _Function_base()
{
if (static_cast<bool>(__x))
{
+ __x._M_manager(_M_functor, __x._M_functor, __clone_functor);
_M_invoker = __x._M_invoker;
_M_manager = __x._M_manager;
- __x._M_manager(_M_functor, __x._M_functor, __clone_functor);
}
}
I have a test case attached.