Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
bgColor#FFCCCC
langcpp
#include <memory>
 
struct Base {
  virtual void f();
};
 
struct Derived : Base {};
 
void f() {
  std::unique_ptr<Base> b = std::make_unique<Derived()>unique<Derived>();
}

Compliant Solution

In this compliant solution, the destructor for Base has an explicitly declared virtual destructor, ensuring that the polymorphic delete operation results in well-defined behavior.

Code Block
bgColor#ccccff
langcpp
struct Base {
  virtual ~Base() = default;
  virtual void f();
};

struct Derived : Base {};

void f() {
  Base *b = new Derived();
  // ...
  delete b;
}

Exceptions

OOP52-CPP:EX0: Deleting a polymorphic object without a virtual destructor is permitted if the object is referenced by a pointer to its class, rather than via a pointer to a class it inherits from.

Code Block
bgColor#ccccff
langcpp
class Base {
public:
  // ...
  virtual void AddRef() = 0;
  virtual void Destroy() = 0;
};

class Derived final : public Base {
public:
  // ...
  virtual void AddRef() { /* ... */ }
  virtual void Destroy() { delete this; }
private:
  ~Derived() {}
};

Note that if Derived were not marked as final, then delete this could actually reference a subclass of Derived, violating this rule.

OOP52-CPP:EX1: Deleting a polymorphic object without a virtual destructor is permitted if its base class has a destroying operator delete that will figure out the correct derived class's destructor to call by other means.

Code Block
bgColor#ccccff
langcpp
#include <new>

class Base {
  const int whichDerived;

protected:
  Base(int whichDerived) : whichDerived(whichDerived) {}

public:
  Base() : Base(0) {}
  void operator delete(Base *, std::destroying_delete_t);
};

struct Derived1 final : Base {
  Derived1() : Base(1) {}
};

struct Derived2 final : Base {
  Derived2() : Base(2) {}
};

void Base::operator delete(Base *b, std::destroying_delete_t) {
  switch (b->whichDerived) {
  case 0:
    b->~Base();
    break;
  case 1:
    static_cast<Derived1 *>(b)->~Derived1();
    break;
  case 2:
    static_cast<Derived2 *>(b)->~Derived2();
  }
  ::operator delete(b);
}

void f() {
  Base *b = new Derived1();
  // ...
  delete b;
}


Risk Assessment

Attempting to destruct a polymorphic object that does not have a virtual destructor declared results in undefined behavior. In practice, potential consequences include abnormal program termination and memory leaks. 

Rule

Severity

Likelihood

Detectable

Remediation Cost

Repairable

Priority

Level

OOP52-CPP

Low

Likely

Low

No

No

P9

P3

L2

L3

Automated Detection

Tool

Version

Checker

Description

PRQA QA-C++ Include PagePRQA QA-C++_VPRQA QA-C++_V

2116, 3403

 

Astrée

Include Page
Astrée_V
Astrée_V

non-virtual-public-destructor-in-non-final-class
Partially checked
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC++-OOP52
Clang
Include Page
Clang_V
Clang_V
-Wdelete-non-virtual-dtor
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

LANG.STRUCT.DNVD

delete with Non-Virtual Destructor

Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C++3402, C++3403, C++3404


Klocwork
Include Page
Klocwork_V
Klocwork_V

CL.MLK.VIRTUAL
CWARN.DTOR.NONVIRT.DELETE

 Clang

LDRA tool suite
Include Page
LDRA_V
LDRA_V

303 S

Partially implemented

Parasoft C/C++test
Include Page
Clang
Parasoft_V
Clang
Parasoft_V

CERT_CPP-

Wdelete-non-virtual-dtor LDRA tool suite Include PageLDRA_VLDRA_V

303 S

Partially implemented

Parasoft C/C++test9.5OOP-22

OOP52-a

Define a virtual destructor in classes used as base classes which have virtual functions

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C++: OOP52-CPPChecks for situations when a class has virtual functions but not a virtual destructor (rule partially covered)
PVS-Studio

Include Page
PVS-Studio_V
PVS-Studio_V

V599, V689
RuleChecker
Include Page
RuleChecker_V
RuleChecker_V
non-virtual-public-destructor-in-non-final-class
Partially checked
 
SonarQube C/C++ Plugin
Include Page
SonarQube C/C++ Plugin_V
SonarQube C/C++ Plugin_V
S1235
 

Related Vulnerabilities

Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

Bibliography

[ISO/IEC 14882-2014]

Subclause 5.3.5, "Delete"
Subclause 12.4, "Destructors" 

[Stroustrup 2006]"Why Are Destructors Not Virtual by Default?"

...


...

Image Modified Image Modified Image Modified