Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Adding another NCCE/CS pair

...

In this noncompliant code example, a nonstandard-layout type object is passed across execution boundaries. The object type is defined in a header file used by both a library and an application. The application creates an instance of the object, then passes a reference to the object to a function defined by the library. However, if the layout is not guaranteed to be compatible across execution boundaries because the compilers do not conform to the same ABI, it is a portability issue likely resulting in unexpected behavior.

Code Block
bgColor#FFCCCC
langcpp
// library.h
struct S {
  virtual void f() { /* ... */ }
};
 
void func(S &s); // Implemented by the library, calls S::f()
 
// application.cpp
#include "library.h"
 
void f() {
  S s;
  func(s);
}

Compliant Solution

If the library and the application conform to the same ABI, either explicitly through vendor documentation, or implicitly by virtue of using the same compiler version to compile both the library and the application, then the noncompliant code example is instead a compliant solution. However, if the library and application do not conform to the same ABI, the compliant solution requires modification of the library and application to work with a standard-layout type.

Page properties
hiddentrue

This CS is incredibly unsatisfying, but is still true.

Code Block
bgColor#ccccff
langcpp
// library.h
#include <type_traits>

struct S {
  void f() { /* ... */ } // No longer virtual
};
static_assert(std::is_standard_layout<S>::value, "S is required to be a standard layout type");

void func(S &s); // Implemented by the library, calls S::f()

// application.cpp
#include "library.h"

void f() {
  S s;
  func(s);
}

Noncompliant Code Example

In this noncompliant code example, std::memset() is used to clear the internal state of an object that is not of a standard-layout type. An implementation may store a vtable within the object instance, which is subsequently overwritten by the call to std::memset(), leading to undefined behavior when virtual method dispatch is required.

Code Block
bgColor#FFCCCC
langcpp
#include <cstring>

struct S {
  int i, j, k;
 
  // ...

  virtual void f();
};

void f() {
  S *s = new S;
  // ...
  std::memset(s, 0, sizeof(S));
  // ...
  s->f();
}

Compliant Solution

In this compliant solution the data members of S are cleared explicitly instead of calling std::memset():

Code Block
bgColor#ccccff
langcpp
struct S {
  int i, j, k;
 
  // ...

  virtual void f();
  void clear() { i = j = k = 0; }
};

void f() {
  S *s = new S;
  // ...
  s->clear();
  // ...
  s->f();
}

Noncompliant Code Example

In this noncompliant code example, a pointer to an object of nonstandard-layout type is passed to a function that has a "Fortran" language linkage. Language linkages other than "C" and "C++" are conditionally-supported with implementation-defined semantics [ISO/IEC 14882-2014]. If the implementation does not support this language linkage, the code is ill-formed. Assuming that the language linkage is supported, any operations performed on the object passed may result in indeterminate behavior, which could have security implications.

Code Block
bgColor#FFCCCC
langcpp
struct B {
  int i, j;
};
 
struct D : B {
  float f;
};
 
void f(D *d) {
  extern "Fortran" void func(void *);
  func(d);
}

Compliant Solution

In this compliant solution, the nonstandard-layout type object is serialized into a local standard-layout type object, that is then passed to the Fortran function:

...