parts/6.41.Inheritance-RIP.md

6.41 Inheritance [RIP]

6.41.1 Applicability to language

The vulnerability as described in ISO/IEC TR 24772-1:2019 clause 6.41 is applicable to C++.

Inheritance as a mechanism in C++ serves multiple purposes and is defined differently than in most other languages supporting inheritance.

The compiler-provided default behaviour for copy and move operations as well as destruction favors value semantics which conflicts with object-oriented polymorphic behaviour.

If a base class overloads operator new and operator delete, any derived classes will inherit and therefore will use such. If the base class’ operator new and/or operator delete assume the size of the objects being allocated are all the size of the base class and they are not all the same size, then this will result in undefined behaviour such as access errors to memory that wasn’t allocated, overwriting of memory (if there are regions of memory immediately after the last byte allocated), memory leaks, etc. For example, consider,

#include <new>
#include <iostream>

class base
{
public:
  static void* operator new(std::size_t sz)
  {
    std::cerr << "DEBUG: Base::" << __func__ << "(" << sz << ")" << '\n';
    return ::operator new(sizeof(base));
  }

  static void operator delete(void *ptr, std::size_t sz)
  {
    std::cerr << "DEBUG: Base::" << __func__ << "(" << ptr << ',' << sz << ")" << '\n';
    ::operator delete(ptr);
  }

};

class derived : public base
{
  double d;
};


int main()
{
  std::cerr << "DEBUG: sizeof(base): " << sizeof(base) << '\n';
  std::cerr << "DEBUG: sizeof(derived): " << sizeof(derived) << '\n';

  // new derived invokes base::operator new
  derived *p = new derived;

  // delete p invokes base::operator delete
  delete p;
}

If a class-overloaded operator new and operator delete can only handle fixed-sized allocations, then consider the following:

if (sz != sizeof(base))
  return ::operator new(sz);
if (sz != sizeof(base))
  ::operator delete(ptr);

It should also be mentioned that C++ requires operator new to return a valid pointer should its size parameter be zero.

The mechanisms of failure from ISO/IEC TR 24772-1:2019 clause 6.41 manifest and can be mitigated in C++ as follows:

6.41.2 Avoidance mechanisms for language users

To avoid the vulnerability or mitigate its ill effects, C++ software developers can: