Evil Casts

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.)

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s