// Copyright (C) 2018-2021 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// .
// { dg-do run }
// { dg-xfail-run-if "AIX operator new" { powerpc-ibm-aix* } }
#include
#include
#include
// PR libstdc++/68210
struct MyBadAlloc: std::bad_alloc { };
static bool new_fail;
static bool bad_alloc_thrown;
static unsigned new_called;
static unsigned delete_called;
static unsigned new_vec_called;
static unsigned delete_vec_called;
static unsigned new_handler_called;
static void new_handler ()
{
if (new_handler_called++)
throw MyBadAlloc ();
}
void* operator new (size_t n)
{
static size_t cntr;
++new_called;
for ( ; ; ) {
if (void *p = new_fail ? 0 : malloc (n + sizeof n)) {
*static_cast(p) = ++cntr;
return static_cast(p) + 1;
}
if (std::new_handler h = std::set_new_handler (0)) {
std::set_new_handler (h);
h ();
}
else {
bad_alloc_thrown = true;
throw MyBadAlloc ();
}
}
}
void operator delete (void *p)
{
++delete_called;
if (p)
free (static_cast(p) - 1);
}
void* operator new[] (size_t n)
{
++new_vec_called;
return operator new(n);
}
void operator delete[] (void *p)
{
++delete_vec_called;
operator delete(p);
}
#if __cplusplus >= 201402L
void operator delete (void *p, std::size_t)
{
::operator delete(p);
}
void operator delete[] (void *p, std::size_t)
{
::operator delete[](p);
}
#endif
void init()
{
new_fail = false;
new_called = 0;
delete_called = 0;
new_vec_called = 0;
delete_vec_called = 0;
new_handler_called = 0;
std::set_new_handler (0);
}
void
test01()
{
init ();
void *p = operator new (1, std::nothrow);
VERIFY (p != 0);
VERIFY (1 == new_called);
VERIFY (0 == new_handler_called);
VERIFY (!bad_alloc_thrown);
operator delete (p, std::nothrow);
VERIFY( 1 == delete_called );
new_fail = true;
p = operator new (1, std::nothrow);
VERIFY (0 == p);
VERIFY (2 == new_called);
VERIFY (0 == new_handler_called);
VERIFY (bad_alloc_thrown);
new_fail = true;
bad_alloc_thrown = false;
std::set_new_handler (new_handler);
p = operator new (1, std::nothrow);
VERIFY (0 == p);
VERIFY (3 == new_called);
VERIFY (2 == new_handler_called);
VERIFY (!bad_alloc_thrown);
}
void
test02()
{
init ();
void *p = operator new[] (1, std::nothrow);
VERIFY (p != 0);
VERIFY (1 == new_called);
VERIFY (1 == new_vec_called);
VERIFY (0 == new_handler_called);
VERIFY (!bad_alloc_thrown);
operator delete[] (p, std::nothrow);
VERIFY( 1 == delete_called );
VERIFY( 1 == delete_vec_called );
new_fail = true;
p = operator new[] (1, std::nothrow);
VERIFY (0 == p);
VERIFY (2 == new_called);
VERIFY (2 == new_vec_called);
VERIFY (0 == new_handler_called);
VERIFY (bad_alloc_thrown);
new_fail = true;
bad_alloc_thrown = false;
std::set_new_handler (new_handler);
p = operator new[] (1, std::nothrow);
VERIFY (0 == p);
VERIFY (3 == new_called);
VERIFY (3 == new_vec_called);
VERIFY (2 == new_handler_called);
VERIFY (!bad_alloc_thrown);
}
int main()
{
test01();
test02();
}