Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructor call when operator new failed

Tags:

c++

gcc

c++03

I’m trying to implement a technique to test failing operator new described in http://www.codeproject.com/Articles/6108/Simulating-Memory-Allocation-Failure-for-Unit-Test.

This is a sample code being tested:

VArray* arr = new VArray(1U, 3U, true);

I can make new return NULL instead of allocating memory. In this case, the program should continue to next line (which should test if arr == NULL) and this is exactly what it does in MSVC.

However, the constructor of VArray is still called after the failed new in GCC. And since this is NULL, it results in SIGSEGV on the first assignment to a property. This seems to be a wrong behavior according to C++03 standard: https://stackoverflow.com/a/11514528/711006

My implementation of operators new and delete follows.

unsigned int OperatorPlainNewFailsAfter = UINT_MAX;

void* operator new(const size_t _size) throw()
{
  void* result;
  if(OperatorPlainNewFailsAfter == 0U)
  {
    result = NULL;
  }
  else
  {
    result = malloc(_size);
    OperatorPlainNewFailsAfter--;
  }
  return result;
}

void operator delete(void* _memory) throw()
{
  free(_memory);
}

What do I miss?

like image 565
Melebius Avatar asked Feb 18 '26 03:02

Melebius


2 Answers

The C++ standard requires that an allocation function (e.g. the basic operator new) fails by throwing a std::bad_alloc exception, if it fails. It's not allowed to return a nullpointer. When you do return a nullpointer you have Undefined Behavior, and yes, one possible consequence is that a constructor is called.

like image 88
Cheers and hth. - Alf Avatar answered Feb 19 '26 16:02

Cheers and hth. - Alf


If the operator new being called is declared throw(), then it is an error for the compiler to not check for a null pointer. But it is illegal to declare a non-placement new throw(), so there's no point in the compiler checking it; if anything, it should complain when it sees the declaration, because the non-placement operator new is implicitly declared.

If you want to test for failing new (and it's a good idea), your operator new function shouldn't return a null pointer, but should throw std::bad_alloc. Otherwise, you're not testing the same thing. On the page you site, the test code uses a placement new instead. The code is still illegal, because his operator new may return a null pointer without having declared the function throw(), but that is easily fixed. (Or not. He calls ::operator new, rather than malloc, for the actual allocation, and this function may throw. He also calls the ::operator new function to allocate, but used the ::delete operator de free; if you call ::operator new to allocate, you should call ::operator delete to free.) Of course, even fixed, it doesn't test anything useful, since what you need to know is that your program reacts correctly to std::bad_alloc, not that it reacts correctly to a null pointer that it will never see.

like image 45
James Kanze Avatar answered Feb 19 '26 17:02

James Kanze



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!