 
                            The pointer-to-member operators .* and ->* are used to obtain an object or a function as though it were a member of an underlying object. For instance, the following are functionally equivalent ways to call the member function f() on the object o:.
| Code Block | 
|---|
| struct S {
  void f() {}
};
void func() {
  S o;
  void (S::*pm)() = &S::f;
  
  o.f();
  (o.*pm)();
} | 
...
The C++ Standard, [expr.mptr.oper], paragraph 4 [ISO/IEC 14882-2014], states the following:
Abbreviating pm-expression.*cast-expression as
E1.*E2,E1is called the object expression. If the dynamic type ofE1does not contain the member to whichE2refers, the behavior is undefined.
(A pointer-to-member expression of the form E1->*E2 is converted to its equivalent form, (*(E1)).*E2, so use of pointer-to-member expressions of either form behave equivalently in terms of undefined behavior.)
Further, the C++ Standard, [expr.mptr.oper], paragraph 6, states, in part in part, states the following:
If the second operand is the null pointer to member value, the behavior is undefined.
Do not use a pointer-to-member expression where the dynamic type of the first operand does not contain the member to which the second operand refers, including the use of a null pointer-to-member value as the second operand.
...
In this noncompliant code example, a pointer-to-member object is obtained from D::g but upcast but is then upcast to be a B::*. When called on an object whose dynamic type is D, the pointer-to-member call is well defined. However, in this noncompliant code example, the dynamic type of the underlying object is object is B, resulting which results in undefined behavior:.
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| struct B {
  virtual ~B() = default;
};
struct D : B {
  virtual ~D() = default;
  virtual void g() { /* ... */ }
};
void f() {
  B *b = new B;
 
  // ...
 
  void (B::*gptr)() = static_cast<void(B::*)()>(&D::g);
  (b->*gptr)();
  delete b;
}
 | 
...
In this compliant solution, the upcast is removed, rendering the initial code ill-formed and emphasizing the underlying problem : that B::g() does not exist. This compliant solution assumes that the programmer's intention was to use the correct dynamic type for the underlying object:.
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| struct B {
  virtual ~B() = default;
};
struct D : B {
  virtual ~D() = default;
  virtual void g() { /* ... */ }
};
void f() {
  B *b = new D; // Corrected the dynamic object type.
 
  // ...
  void (D::*gptr)() = &D::g; // Moved static_cast to the next line.
  (static_cast<D *>(b)->*gptr)();
  delete b;
}
 | 
...
In this noncompliant code example, a null pointer-to-member value is passed as the second operand to a pointer-to-member expression, resulting in undefined behavior:.
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| struct B {
  virtual ~B() = default;
};
struct D : B {
  virtual ~D() = default;
  virtual void g() { /* ... */ }
};
 
static void (D::*gptr)(); // Not explicitly initialized, defaults to nullptr.
void call_memptr(D *ptr) {
  (ptr->*gptr)();
}
 
void f() {
  D *d = new D;
  call_memptr(d);
  delete d;
} | 
...
In this compliant solution, gptr is properly initialized to a valid pointer-to-member value instead of to the default value of nullptr:.
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| struct B {
  virtual ~B() = default;
};
 
struct D : B {
  virtual ~D() = default;
  virtual void g() { /* ... */ }
};
 
static void (D::*gptr)() = &D::g; // Explicitly initialized.
void call_memptr(D *ptr) {
  (ptr->*gptr)();
}
 
void f() {
  D *d = new D;
  call_memptr(d);
  delete d;
} | 
Risk Assessment
| Rule | Severity | Likelihood | Detectable | 
|---|
| Repairable | Priority | Level | |
|---|---|---|---|
| OOP55-CPP | High | Probable | No | 
| No | P6 | L2 | 
Automated Detection
| Tool | Version | Checker | Description | ||||||
|---|---|---|---|---|---|---|---|---|---|
| Astrée | 
 | overflow_upon_dereference invalid_function_pointer | |||||||
| Axivion Bauhaus Suite | 
 | CertC++-OOP55 | |||||||
| CodeSonar | 
 | LANG.MEM.UVAR | Uninitialized Variable | ||||||
| Helix QAC | 
 | DF2810, DF2811, DF2812, DF2813, DF2814 | |||||||
| Klocwork | 
 | CERT.OOP.PTR_MEMBER.NO_MEMBER | |||||||
| Parasoft C/C++test | 
| 
 | CERT_CPP-OOP55-a | A cast shall not convert a pointer to a function to any other pointer type, including a pointer to function type | ||||||
| Parasoft Insure++ | 
| Runtime detection | |||||||||
| Polyspace Bug Finder | 
 | CERT C++: OOP55-CPP | Checks for pointers to member accessing non-existent class members (rule fully covered). | 
Related Vulnerabilities
Search for other vulnerabilities resulting from the violation of this rule on the CERT website.
...
This rule is a subset of EXP34-C. Do not dereference null pointers.
Bibliography
| [ISO/IEC 14882-2014] | Subclause 5.5, "Pointer-to-Member Operators" | 
...
...