public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug libstdc++/63840] New: std::function copy constructor deletes an uninitialized pointer if new fails
@ 2014-11-12 20:46 tavianator at gmail dot com
  2014-11-12 23:44 ` [Bug libstdc++/63840] " redi at gcc dot gnu.org
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: tavianator at gmail dot com @ 2014-11-12 20:46 UTC (permalink / raw)
  To: gcc-bugs

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.


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-12-06 22:26 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-12 20:46 [Bug libstdc++/63840] New: std::function copy constructor deletes an uninitialized pointer if new fails tavianator at gmail dot com
2014-11-12 23:44 ` [Bug libstdc++/63840] " redi at gcc dot gnu.org
2014-11-13  0:08 ` redi at gcc dot gnu.org
2014-12-01 13:49 ` redi at gcc dot gnu.org
2014-12-01 13:50 ` redi at gcc dot gnu.org
2014-12-06 20:38 ` redi at gcc dot gnu.org
2014-12-06 22:24 ` redi at gcc dot gnu.org
2014-12-06 22:26 ` redi at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).