This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug libstdc++/83658] any::emplace deletes invalid memory when an overloaded operator new() throws
- From: "redi at gcc dot gnu.org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Mon, 29 Jan 2018 12:11:09 +0000
- Subject: [Bug libstdc++/83658] any::emplace deletes invalid memory when an overloaded operator new() throws
- Auto-submitted: auto-generated
- References: <bug-83658-4@http.gcc.gnu.org/bugzilla/>
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.