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.