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++/83658] any::emplace deletes invalid memory when an overloaded operator new() throws


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83658

Jonathan Wakely <redi at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |ASSIGNED
   Last reconfirmed|                            |2018-01-29
           Assignee|unassigned at gcc dot gnu.org      |redi at gcc dot gnu.org
   Target Milestone|---                         |7.4
     Ever confirmed|0                           |1

--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> ---
As requested by https://gcc.gnu.org/bugs/ please don't post links to code
hosted elsewhere, provide the code here in bugzilla:

#include <any>
#include <cstdint>
#include <iostream>
#include <new>

struct AllocThrows {
    AllocThrows() {}
    AllocThrows(const AllocThrows&) {}

    // Not marked noexcept so std::any doesn't inline AllocThrows instances.
    AllocThrows(AllocThrows&&) {}
    template <typename... Args>
    static void* operator new(size_t, Args&&... args) {
        std::cout << "throwing bad alloc\n";
        throw std::bad_alloc();
    }

    static void operator delete(void*) noexcept {
        std::cout << "deleting\n";
    }
};

int main() {
    std::any a;
    try {
        a.emplace<AllocThrows>();  // double-deletes!
    } catch(...) {}
}


(In reply to Jon Cohen from comment #0)
> __do_emplace sets the manager pointer before attempting to create a new
> object.  When new() throws after calling reset(), _M_ptr doesn't point to
> valid memory.  When, later, the destructor is called on the any, the manager
> pointer still is non-null, so the destructor, via reset(), will trigger the
> call to _S_manage(_Op_destroy, ...), calling delete on the invalid _M_ptr.  

It's not invalid, it's guaranteed to be a null pointer.

This is definitely a bug (because a.has_value() is true after the exception,
and user-provided deallocation functions aren't required to handle null
pointers) but there's no double-delete.

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