Spot the difference in
#include <iostream> struct S1 { int s1 = 2; }; struct S2; S2 * f(S1 * s) { return (S2 *) s; } struct T { int t = 1; }; struct S2: T, S1 {}; int main() { S2 s2; std::cout << f(s2)->t << '\n'; }
vs.
#include <iostream> struct S1 { int s1 = 2; }; struct T { int t = 1; }; struct S2: T, S1 {}; S2 * f(S1 * s) { return (S2 *) s; } int main() { S2 s2; std::cout << f(s2)->t << '\n'; }
The latter will print “1”, as would be expected. The former will probably print “2”. Or “1”.
The trouble is that in C++ a C-style cast involving a pointer to an incomplete type will “resolve” to a reinterpret_cast
. (Or, at the compiler’s discretion, to a static_cast
, if the type later becomes complete within this translation unit.) With no incomplete types involved, the C-style cast will consistently resolve to a static_cast
.
“Broken cast” shows how such C-sytle casts on incomplete types are the worst of the worst. (The reason it went unnoticed for 10+ years is that the corrupted pFact
member happens to always contain a null pointer when that code is executed, so writing false
into it doesn’t really hurt. But also doesn’t reset bVisible
from true
to false
, so that hot hack of yore is probably not needed so desparately after all…)
Noel Grandin wrote a Clang plugin to flag many of the clearly bad uses of C-style casts across the LibreOffice code base. Since “loplugin:cstylecast: warn about casts involving incomplete types” it now also flags “the worst kind of all.” (And unearthed the above WTF.)
Image may be NSFW.
Clik here to view.

Clik here to view.
