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

            Bug ID: 68210
           Summary: nothrow operator fails to call default new
           Product: gcc
           Version: 6.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: msebor at gcc dot gnu.org
  Target Milestone: ---

A recent discussion about operator new
(https://gcc.gnu.org/ml/gcc-patches/2015-11/msg00192.html) revealed that the
libstdc++ implementation of the nothrow overload of the operator doesn't
conform to the requirement to "return a pointer obtained as if acquired from
the (possibly replaced) ordinary version."  The test case below illustrates
some of the problems.

The requirement quoted above implies that a conforming implementation of the
nothrow overload must call the ordinary form like so:

void* operator new (size_t n, const nothrow_t&) {
    try {
        return operator new (n);
    }
    catch (...) {
        return 0;
    }
}


$ cat t.cpp && ~/bin/gcc-5.1.0/bin/g++ -Wall t.cpp && ./a.out 
#include <new>
#include <assert.h>
#include <stdlib.h>

struct MyBadAlloc: std::bad_alloc { };

static bool new_fail;
static bool bad_alloc_thrown;
static unsigned new_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<size_t*>(p) = ++cntr;
            return static_cast<size_t*>(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)
{
    if (p)
        free (static_cast<size_t*>(p) - 1);
}

int main ()
{
    new_called = 0;
    void *p = operator new (1, std::nothrow);

    assert (p != 0);
    assert (1 == new_called);

    std::set_new_handler (new_handler);
    new_fail = true;

    try {
        p = operator new (1, std::nothrow);
    }
    catch (...) {
        assert (!"nothrow operator new threw");
    }

    assert (0 == p);
    assert (2 == new_handler_called);
    assert (bad_alloc_thrown);
}
a.out: t.cpp:53: int main(): Assertion `1 == new_called' failed.
Aborted (core dumped)

Reply via email to