On 10/17/2017 03:57 PM, David Malcolm wrote:

> Given that we build with -fno-exceptions, what are we guaranteed about
> what happens when "new" fails?  (am I right in thinking that a failed
> allocation returns NULL in this case?).  Is XNEWVEC preferable here?

No, that's incorrect.  Even with -fno-exceptions, if new fails,
then an exception is thrown.  And then because the unwinder
doesn't find a frame that handles the exception, std::terminate
is called...

You can easily see it with this:

$ cat new-op.cc 
int main ()
{
  char * p = new char [-1];
  return 0;
}

$ g++ new-op.cc -o new-op -g3 -O0 -fno-exceptions
$ ./new-op 
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted (core dumped)

If you want new to return NULL on allocation failure, you either
have to call the std::nothrow_t overload of new:

  char* p = new (std::nothrow) char [-1];

or you have to replace [1] the global operator new to not throw.

> 
> i.e. do we prefer:
> 
> (A)
> 
>   gnu::unique_ptr<uint32_t[]> data (new uint32_t[size + 1]);
> 
> (implicitly delete-ing the data, with an access-through-NULL if the
> allocation fails)

That'd be my preference too [2].

Though I think that GCC should replace the global
operator new/new[] functions to call xmalloc instead of malloc.

Like:

void *
operator new (std::size_t sz)
{
  return xmalloc (sz);
}

void *
operator new (std::size_t sz, const std::nothrow_t&)
{
  /* malloc (0) is unpredictable; avoid it.  */
  if (sz == 0)
    sz = 1;
  return malloc (sz);
}

Then memory allocated by all new expressions, including those done
via the standard allocators within standard containers, std::vector,
std::string, etc., ends up in xmalloc, which calls xmalloc_failed on
allocation failure.  I.e., replace operator new to behave just
like xmalloc instead of letting it throw an exception that is
guaranteed to bring down gcc, badly.

Note there are already many "new" expressions/calls in GCC
today.  Any of those can bring down GCC.

This is very much like what I did for GDB.  See GDB's (latest)
version here:

  
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=gdb/common/new-op.c;hb=bbe910e6e1140cb484a74911f3cea854cf9e7e2a

GDB's version still throws, because well, GDB uses exceptions.

[1] Replacing global operator new is something that is totally
defined by the standard (unlike -fno-exceptions).
See "global replacements" 
at <http://en.cppreference.com/w/cpp/memory/new/operator_new>.

[2] - Or in many cases, use a std::vector instead.  And if
you care about not value-initializing elements, see gdb's
gdb/common/{def-vector, default-init-alloc}.h.

Thanks,
Pedro Alves

Reply via email to