Versions Compared

Key

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

Virtual functions enable a program to invoke a function appropriate to the object the allow for the choice of member function calls to be determined at run time based on the dynamic type of the object that the member function is being called on. If a virtual method is called on a pointer, the actual class of the pointed-to object is consulted at run-time, to determine the appropriate function to invoke. This contrasts with non-virtual functions, where the function invoked is determined by the compilerThis convention supports object-oriented programming practices commonly associated with object inheritance and function overriding. When calling a nonvirtual member function or when using a class member access expression to denote a call, the specified function is called. Otherwise, a virtual function call is made to the final overrider in the dynamic type of the object expression.

However, during the construction and destruction of an object, the rules for virtual invocation are different. method dispatch on that object are restricted. The C++ 2003Standard, section 12.7 "Construction and Destruction", says[class.cdtor], paragraph 4 [ISO/IEC 14882-2014], states the following:

Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When . When a virtual function is called directly or indirectly from a constructor (including from the mem-initializer for a data member) or from a destructoror from a destructor, including during the construction or destruction of the class’s non-static data members, and the object to which the call the call applies is the object (call it x) under construction or destruction, the function called is the one defined in the constructor or destructor’s own class or in one of its bases, but not a function final overrider in the constructor’s or destructor’s class and not one overriding it in a class derived from the constructor or destructor’s class, or overriding it in one of the other base classes of the most derived object (1.8)more-derived class. If the virtual function virtual function call uses an explicit class member access (5.2.5) and access and the object - expression refers to the complete object of x or one of that object’s base class subobjects but not x or one of its base class subobjects, the behavior is undefined.

Do not directly or indirectly invoke a virtual function from a constructor or destructor that attempts to call into the object under construction or destruction

...

. Because the order of construction starts with base classes and moves to more derived classes, attempting to call a derived class function from a base class under construction is dangerous. The derived class has not had the opportunity to initialize its resources, which is why calling a virtual function from a constructor does not result in a call to a function in a more derived class. Similarly, an object is destroyed in reverse order from construction, so attempting to call a function in a more derived class from a destructor may access resources that have already been released.

Noncompliant Code Example

In this noncompliant code example, the base class

Because of this difference in behavior, it is recommended that you never invoke an object's virtual function while it is being constructed or destroyed.

Non-Compliant Code Example

Consider a design that attempts to seize and release an object's resources through calls to virtual functions from a base class's the constructor and destructor. However, the B::B() constructor calls B::seize() rather than D::seize(). Likewise, the B::~B() destructor calls B::release() rather than D::release().

Code Block
bgColor#FFcccc
langcpp

classstruct B {
  public:
    B() { seize(); }
    virtual ~B() { release(); }
 
  protected:
    virtual void seize() {};
    virtual void release() {};
};

classstruct D : public B {
  public:
    Dvirtual ~D() = {}
    ~D() {}
  default;
 
protected:
    void seize() override {
        B::seize();
        // getGet derived resources...
    }
 
    void release() override {
        // releaseRelease derived resources...
        B::release();
    }
};

D x;

The result of running this code is that no derived class resources will be seized or released during the initialization and destruction of the x object of type D. At the time of the call to seize in the initialization of x() from B::B(), the D constructor has not been entered, and the behavior of the under-construction x object will be to invoke B::seize() rather than D::seize(). A similar situation occurs for the call to release() in the base class destructor. If the functions seize() and release() were declared to be pure virtual functions, the result would be undefined behavior.

Compliant Solution

Avoid calling an object's virtual functions while it is being constructed or destroyedIn this compliant solution, the constructors and destructors call a nonvirtual, private member function (suffixed with mine) instead of calling a virtual function. The result is that each class is responsible for seizing and releasing its own resources.

Code Block
bgColor#ccccff
langcpp

class B {
   public:void seize_mine();
  void  Brelease_mine() {;
  
public:
  B() {   // seize base resources...
    }
  seize_mine(); }
  virtual ~B() { release_mine(); }

protected:
  virtual void seize() { seize_mine(); }
 // releasevirtual base resources...
    void release() { release_mine(); }
};

class D : public B {
  void seize_mine();
  void release_mine();
  
public:
  D() { Dseize_mine(); {}
  virtual ~D() { release_mine(); }

protected:
  //void seize() derived resources...override {
    }B::seize();
    ~Dseize_mine();
  {}
  
  void release() override {
   // release_mine();
 derived resources...
  B::release();
  }
};

D x;

Note that it is perfectly legitimate to call virtual functions of other, fully constructed objects from a constructor or destructor.

Exceptions

Exceptions

OOP50-CPP Anchorex1ex1OOP30-EX1: Since Because valid uses use cases exist that involve calling (non-pure) virtual functions from the constructor of a class, it is recommended to explicitly qualify the name of permissible to call the virtual function with the name of the class that defines it. This approach silences warnings from compilers such as HP aCC that diagnose violations of the rule. Note that calls to ordinary, non-virtual member functions that call virtual functions of the same class that aren't so qualified may be unsafe and thus lead to diagnostics. Thus, this exception does not extend to such cases.an explicitly qualified ID. The qualified ID signifies to code maintainers that the expected behavior is for the class under construction or destruction to be the final overrider for the function call.

Code Block
bgColor#ccccff
langcpp

classstruct A {
  A() {
    // f();   // WRONG!
    A::f();   // okayOkay
  }
  virtual void f();
};

OOP50-CPP-EX2: It is permissible to call a virtual function that has the final virt-specifier from a constructor or destructor, as in this example.

Code Block
bgColor#ccccff
langcpp
struct A {
  A();
  virtual void f();
};
 
struct B : A {
  B() : A() {
    f();  // Okay
  }
  void f() override final;
};

Similarly, it is permissible to call a virtual function from a constructor or destructor of a class that has the final class-virt-specifier, as in this example.

Code Block
bgColor#ccccff
langcpp
struct A {
  A();
  virtual void f();
};
 
struct B final : A {
  B() : A() {
    f();  // Okay
  }
  void f() override;
};

In either case, f() must be the final overrider, guaranteeing consistent behavior of the function being called.

Risk Assessment

Rule

Severity

Likelihood

Detectable

Remediation Cost

Repairable

Priority

Level

OOP30

OOP50-CPP

Low

low

Unlikely

unlikely

Yes

medium

No

P2

L3

Automated Detection

Tool

Version

Checker

Description

Astrée

Include Page
Astrée_V
Astrée_V

virtual-call-in-constructor
invalid_function_pointer
Fully checked
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC++-OOP50
Clang
Include Page
Clang_V
Clang_V
clang-analyzer-alpha.cplusplus.VirtualCallChecked by clang-tidy
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

LANG.STRUCT.VCALL_IN_CTOR

LANG.STRUCT.VCALL_IN_DTOR

Virtual Call in Constructor

Virtual Call in Destructor

Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C++4260, C++4261, C++4273, C++4274, C++4275, C++4276, C++4277, C++4278, C++4279, C++4280, C++4281, C++4282


Klocwork
Include Page
Klocwork_V
Klocwork_V

CERT.OOP.CTOR.VIRTUAL_FUNC


LDRA tool suite
Include Page
LDRA_V
LDRA_V

467 S, 92 D

Fully implemented

Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V

CERT_CPP-OOP50-a
CERT_CPP-OOP50-b
CERT_CPP-OOP50-c
CERT_CPP-OOP50-d

Avoid calling virtual functions from constructors
Avoid calling virtual functions from destructors
Do not use dynamic type of an object under construction
Do not use dynamic type of an object under destruction

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C++: OOP50-CPPChecks for virtual function call from constructors and destructors (rule fully covered)
PVS-Studio

Include Page
PVS-Studio_V
PVS-Studio_V

V1053
RuleChecker
Include Page
RuleChecker_V
RuleChecker_V
virtual-call-in-constructor
Fully checked
Security Reviewer - Static Reviewer

Include Page
Security Reviewer - Static Reviewer_V
Security Reviewer - Static Reviewer_V

 UNSAFE_07Fully implemented
SonarQube C/C++ Plugin
Include Page
SonarQube C/C++ Plugin_V
SonarQube C/C++ Plugin_V
S1699

Related Vulnerabilities

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

Bibliography

...

2002]Gotcha

...

#75, "Calling Virtual Functions in Constructors and Destructors"
[

...

ISO/IEC 14882-2014]

Subclause 5.5, "Pointer-to-Member Operators"

[Lockheed Martin

...

2005]AV Rule 71.1, "A

...

class's virtual functions shall not be invoked from its destructor or any of its constructors"
[Sutter 2004]Item 49, "Avoid Calling Virtual Functions in Constructors and Destructors"


...

Image Added Image Added Image Added .OOP07-CPP. Do not inherit from multiple classes that have distinct objects with the same name      13. Object Oriented Programming (OOP)      OOP31-CPP. Ensure object construction invocations isn't mistaken for a function variable declaration