This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug libstdc++/63840] New: std::function copy constructor deletes an uninitialized pointer if new fails


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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]