...
A special instance of this guidance involves non-C++ code compiled by a different compiler, such as C standard library implementations that are exposed via the C++ standard library. C standard library functions are exposed with C++ signatures, and the type system frequently assists in ensuring that types match appropriately. This disallows passing a pointer to a C++ object to a function expecting a char *
without additional work to suppress the type mismatch. However, some C standard library functions accept a void *
, for which any C++ pointer type will suffice. Passing a pointer to a nonstandard-layout type in this situation results in unspecified indeterminate behavior, as it depends on the behavior of the other language as well as the layout of the given object.
...
Code Block | ||||
---|---|---|---|---|
| ||||
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 | ||||
---|---|---|---|---|
| ||||
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:
Code Block | ||||
---|---|---|---|---|
| ||||
struct B { int i, j; }; struct D : B { float f; }; void f(D *d) { struct { int i, j; float f; } temp; temp.i = d->i; temp.j = d->j; temp.f = d->f; extern "Fortran" void func(void *); func(&temp); } |
Risk Assessment
The effects of passing objects of nonstandard-layout type across execution boundaries depends on what operations are performed on the object within the callee as well as what subsequent operations are performed on the object from the caller, and can range from correct or benign behavior to undefined behavior.
...
[ISO/IEC 14882-2014] | Clause 9, "Classes" 7.5, "Linkage Specifications" |
...