C-Style casting causing SIGILL, dynamic_cast ok - c++

In a project of mine here I have a class that implements four interfaces:
class A : public B,
public C,
public D,
public E
{
----Implementation Code here----
};
these four interfaces contains only pure virtual functions, none of them compose the diamond problem (so I don't need to use the virtual keyword) so I spected no problem when doing something like this:
A* var = new A;
((C*)var)->method_from_interface();
Yet something ugly is happening, because the function is jumping around to a different method of the A class, and valgrind complains about an unhandled instruction. However, doing this:
A* var = new A;
(dynamic_cast<C*>(var))->method_from_interface();
works as suspected.
So I'm wondering if this is a G++ bug or some misuse of the language?
edit:
Maybe I've simplified too much my problem. I'm receiving the A class as a D* on a function call:
void do_something(provider* p) {
D* iface = p->recoverItemByName("nameThatReturnsClassA");
((B*) iface)->call_method_from_b_iface();
}
Note that I know that in this time the D* is in fact an A*, so casting doing a casting to B* isn't breaking any rules. I can't static_cast it, though, as D* and B* have no relation, but I can use reinterpret_cast successfully.

C-style cast is just doing a "basic" memory mapping of your pointer to your class. If your method is offset=42 in your class, it would make (*(A+42)) () (simplified, of course).
however, if you inherit from more than one class, you have to take into account the various classes and order in which the compiler puts them.
static_cast is taking into account multiple inheritance.
On your example, it would probably work with either B,C,D or E, but not with the other ones. However, you have no good reason to do that : you would call A->methodFromInterface() and it just works!
On C++, it's advised to use static_cast or dynamic_cast (note : second one relies on rtti which might not be available) and discard the old C-style cast.
EDIT
Tried to reproduce issue but couldn't, files can be found on
class2.hpp : http://pastebin.com/CBVykqcD
class2.cpp : http://pastebin.com/Vy2YsEGP
class.cpp : http://pastebin.com/wwHpe87g
Compiled with on MacOs 10.6:
g++ -fno-rtti -o truc ./class.cpp ./class2.cpp && ./truc

Note that I know that in this time the D* is in fact an A*, so casting
doing a casting to B* isn't breaking any rules.
Wrong.
You may know that it's actually an A*, but the compiler doesn't, at least at compile time when it's trying to figure out what code to emit to do the conversion.
A funny thing happens when you inherit from multiple classes with virtual methods. When you convert from the derived class to one of the interface classes, the pointer address changes! The compiler does adjustments to the pointer to make it valid for the pointer type you've declared. Try it yourself, start with an A* pointer and display its value, then cast to a B*, C*, and D* and display those. At most one of the base classes will be the same as the A*, the others will be different.
When you use a C-style cast you're telling the compiler "I don't care if you can't do the conversion properly, do it anyway." It duly treats the D* as a B* without doing the required fixups, so now the pointer is completely wrong. It isn't pointing to the class B vtable so the wrong methods get called.
A dynamic_cast works because it uses extra information available at run-time; it can trace the pointer to its most-derived A* and then back down to a B*.

The problem is in your function do_something.
This line is fine:
D* iface = p->recoverItemByName("nameThatReturnsClassA");
But this line is bad because B is not related to D, so you cannot cast safely. Try calling static_cast(iface) and you will see the compiler complaining - which should be a warning to you.
((B*) iface)->call_method_from_b_iface();
In the upper line you are coding knowledge that iface does not only point to a D, but to an A. Better store the a pointer to A and use that pointer. So do
A* iface = p->recoverItemByName("nameThatReturnsClassA");
iface->call_method_from_b_iface();
If you still want to stick to D* iface, then code it like this (with only one the both options):
D* iface = p->recoverItemByName("nameThatReturnsClassA");
static_cast<A*>(iface)->call_method_from_b_iface(); // option 1, easy to understand
dynamic_cast<B*>(iface)->call_method_from_b_iface(); // option 2, will do a cross-cast
For more information about dynamic_cast and it's cross cast capability see http://msdn.microsoft.com/en-us/library/cby9kycs.aspx.
Last but not least: try to avoid old C-style cast and always try to use the C++ style cast const_cast, static_cast/dynamic_cast and reinterpret_cast (in this order).

Related

Not a polymorphic type or why do we need virtual destructors here?

Currently I am learning about dynamic casting and thus I am testing out various code snippets.
I tested below's code with and without the virtual destructors marked in (2) and found that line (3) is only correct, if there is line (2). Without it, the code does not compile. But why? Interestingly line (1) doesn't seem to be needed at all.
struct A {
virtual ~A() = default; \\ (1)
};
struct B {
virtual ~B() = default; \\ (2)
};
struct D : A, B {};
B* pb = new D();
A* pa = dynamic_cast<A*>(pb); \\ (3)
In general
dynamic_cast requires to determine the behavior at run-time. Depending on the real type of the casted object, it will either return nullptr or a valid pointer of the target type.
For this to happen at run-time, the C++ implementation needs to have access to some additional information about the type at run-time. And managing this information require some additional operations to be performed. The overhead is minimal but it exist.
Dynamic casting is not always needed. The C++ language designer has decided not to create unnecessary overhead if it is not needed. So unless you say that polymorphism is needed, the compiler will try to solve all the type questions as much as possible at compile-time.
The way to say that polymorphism and dynamic typing is needed is to have at least one virtual member function in the class.
Your specific case
If you'd know in your program very well that the source object's type is compatible with the target object type, you could use static_cast as explained here.
But this will not work in your case, since pb is a *B (static type), because in general a *B cannot be casted to an *A because both types are completely unrelated.
But a *D (dynamic type) can be casted to an *A in view of its multiple inheritance. And this is why dynamic_cast is needed here: to keep track of the original D type of the objet that pb points to. And this requires the class to have at least a virtual function as explained above.

Multiple inheritance cast not working as expected

I recently had a problem with casts and multiple inheritance: I needed to cast a Base* to Unrelated*, because a specific Derived class derives the Unrelated class.
This is a short example:
#include <iostream>
struct Base{
virtual ~Base() = default;
};
struct Unrelated{
float test = 111;
};
struct Derived : Base,Unrelated{};
int main(){
Base* b = new Derived;
Unrelated* u1 = (Unrelated*)b;
std::cout << u1->test << std::endl; //outputs garbage
Unrelated* y = dynamic_cast<Unrelated*>(b);
std::cout << y->test << std::endl; //outputs 111
}
The first cast clearly doesnt work, but the second one did work.
My question is: Why did the second cast work? Shouldnt dynamic_cast only work for cast to a related class type? I thought there wasnt any information about Unrelated at runtime because it is not polymorphic.
Edit: I used colirus gcc for the example.
dynamic_cast works because the dynamic type of object pointed to by a pointer to its base class is related to Unrelated.
Keep in mind that dynamic_cast requires a virtual table to inspect the inheritance tree of the object at run-time.
The C-style cast (Unrelated*)b does not work because the C-style cast does const_cast, static_cast, reinterpret_cast and more, but it does not do dynamic_cast.
I would suggest avoiding C-style casts in C++ code because they do so many things as opposed to precise C++ casts. My colleagues who insist on using C-style cast still occasionally get them wrong.
The first cast (Unrelated*)b doesn't work because you're treating the Base class sub-object, containing probably just a vtable pointer, as an Unrelated, containing a float.
Instead you can cast down and up, static_cast<Unrelated*>( static_cast<Derived*>( b ) ).
And this is what dynamic_cast does for you, since Base is a polymorphic type (at least one virtual method) which allows dynamic_cast to inspect the type of the most derived object.
In passing, dynamic_cast<void*>( b ) would give you a pointer to the most derived object.
However, since you know the types there's no need to invoke the slight overhead of a dynamic_cast: just do the down- and up-casts.
Instead of the C style cast (Unrelated*)b you should use the corresponding C++ named cast or casts, because C style casts of pointers can do things you'd not expect, and because the effect can change completely when types are changed during maintenance.
The C style cast will maximum do 2 C++ named casts. In this case the C style cast corresponds to a reinterpret_cast. The compiler will not allow any other named cast here.
Which is a warning sign. ;-)
In contrast, the down- and up-casts are static_casts, which usually are benign casts.
All that said, the best is to almost completely avoid casts by using the top secret technique:
Don't throw away type information in the first place.
I.e., in the example code, just use Derived* as the type of the pointer.
With multiple inheritance, the Derived object consists of two sub-objects, one Base and one Unrelated. The compiler knows how to access whichever part of the object it needs, typically by adding an offset to the pointer (but that's an implementation detail). It can only do that when it knows the actual type of a pointer. By using a C-style cast, you've told the compiler to ignore the actual type and treat that pointer value as a pointer to something else. It no longer has the information necessary to properly access the sub-object you desire, and it fails.
dynamic_cast allows the compiler to use run-time information about the object to locate the proper sub-object contained within it. If you were to output or examine the pointer values themselves, you'd see that they are different.

static_cast from Derived* to void* to Base*

I would like to cast a pointer to a member of a derived class to void* and from there to a pointer of the base class, like in the example below:
#include <iostream>
class Base
{
public:
void function1(){std::cout<<"1"<<std::endl;}
virtual void function2()=0;
};
class Derived : public Base
{
public:
virtual void function2(){std::cout<<"2"<<std::endl;}
};
int main()
{
Derived d;
void ptr* = static_cast<void*>(&d);
Base* baseptr=static_cast<Base*>(ptr);
baseptr->function1();
baseptr->function2();
}
This compiles and gives the desired result (prints 1 and 2 respectively), but is it guaranteed to work? The description of static_cast I found here: http://en.cppreference.com/w/cpp/language/static_cast
only mentions conversion to void* and back to a pointer to the same class (point 10).
In the general case, converting a base to void to derived (or vice versa) via static casting is not safe.
There will be cases where it will almost certainly work: if everything involved is a pod, or standard layout, and only single inheritance is involved, then things should be fine, at least in practice: I do not have chapter and verse from the standard, but the general idea is that the base in that case is guaranteed to be the prefix of the derived, and they will share addresses.
If you want to start seeing this fail, mix in virtual inheritance, multiple inheritance (both virtual and not), and multiple implementation inheritance that are non trivial. Basically when the address of the different type views of this differ, the void cast from and back to a different type is doomed. I have seen this fail in practice, and the fact it can fail (due to changes in your code base far away from the point of casting) is why you want to be careful about always casting to and from void pointer with the exact same type.
In general, no, it is not safe.
Suppose that casting Derived* directly to Base* results in a different address (for example, if multiple inheritance or virtual inheritance is involved).
Now if you inserted a cast to void* in between, how would the compiler know how to convert that void* to an appropriate Base* address?
If you need to cast a Derived* to a void*, you should explicitly cast the void* back to the original Derived* type first. (And from there, the cast from Derived* to Base* is implicit anyway, so you end up with the same number of casts, and thus it's not actually less any convenient.)
From the link you supplied yourself
9) A pointer to member of some class D can be upcast to a pointer to member of its base class B. This static_cast makes no checks to ensure the member actually exists in the runtime type of the pointed-to object.
Meaning as long as you know that the upcast is safe before you do it it is guaranteed to work. That's why you should be using dynamic_cast which returns nullptr if unsuccessful.
Think of it this way if you have.
Type * t1;
static_cast of t1 to one of the classes deriving from it cannot be known at compile time, without in depth analysis of your program (which obviously it is not and should not be doing), so even if it ends up being correct you have no way of checking. dynamic_cast does extra work at runtime to check if the conversion was successful hence the prefix dynamic.

c++ casting derived to void* and restoring base

I have:
class A {...};
class B : public A {...};
class C : public B {...};
Then I'm storing C instance as void*:
C *instance = new C();
void *pC = instance;
Is it ok to make this:
B *pB = reinterpret_cast<B*>(pC);
Or I have to cast to C* only?
PS: I have more classes derived from B in my program and I'm not sure if's ok to cast like i'm doing (to B*).
Why void*: I'm using void *userdata' field of physical body class in box2d engine. I can't store my class there in other way
I would suggest casting it back to the original C* then do a dynamic_cast to B* in order to follow the rules of C++ - although you should avoid casting to void* in the first place and instead use a base pointer (A*) instead of void ptr.
The general rule is that when you cast from a pointer to void * you should always cast back to the one you originally came from.
Casting to void* is sometimes a necessary evil because of old APIs.
And sometimes it is done by design to create a "light" template. A light template is where you write code that handles a collection of pointers to objects, which are all handled in the same way, and this prevents code having to be generated for every type.
Around this code you have a strongly typed template that does the simple thing of casting back and forth (likely to be inlined anyway) so the users get strongly typed code but the implementation is less bloated.
For the code you shown it should be ok to cast directly to B* and you can use static_cast for this. However, in general, pointers to base and derived classes might be different and you'll have to cast to the original type first and only then cast it to the pointer to base.
Edit: that should be ok in practice for single inheritance, but in general it's UB.
This will work fine. You'll only get access to methods of A and B in this case though. (You'll simply "hide" methods of C.)
Casting to void* is always a bad idea and so is doing a dynamic_cast. If you have to, it mostly means your code requires re-factoring as it is an object design flaw.

Can't downcast because class is not polymorphic?

Is it possible to have inheritance with no virtual methods? The compiler is saying that the following code is not polymorphic.
Example:
class A {
public:
int a;
int getA(){return a;};
}
class B : public A {
public:
int b;
int getB(){return b;};
}
In another class we are trying to downcast from an A object to a B object:
A *a = ...;
B *b = dynamic_cast<B*>(a)
but this gives the following compile-time error:
cannot dynamic_cast ... (source type is not polymorphic)
Syntax errors non-withstanding, you cannot dynamic_cast a non-polymorphic type. static_cast is the cast you would use in this case, if you know that it is in fact an object of the target type.
The reason why: static_cast basically has the compiler perform a check at compile time "Could the input be cast to the output?" This is can be used for cases where you are casting up or down an inheritance hierarchy of pointers (or references). But the check is only at compile time, and the compiler assumes you know what you are doing.
dynamic_cast can only be used in the case of a pointer or reference cast, and in addition to the compile time check, it does an additional run time check that the cast is legal. It requires that the class in question have at least 1 virtual method, which allows the compiler (if it supports RTTI) to perform this additional check. However, if the type in question does not have any virtual methods, then it cannot be used.
The simplest case, and probably worthwhile if you're passing pointers around like this, is to consider making the base class's destructor virtual. In addition to allowing you to use dynamic cast, it also allows the proper destructors to be called when a base class pointer is deleted.
You need at least one virtual method in a class for run-time type information (RTTI) to successfully apply dynamic_cast operator.
just make A destructor virtual (always do for any class just for safety).
yes, dynamic_cast for non-polymorphic types are not allowed. The base class shall have at least one virtual method. Only then that class can be called as polymorphic.
This article explains a similar example: http://www.cplusplus.com/doc/tutorial/typecasting/
A a;
B *b = dynamic_cast<B*>(a)
Here a is an object and b is a pointer.
Actually, upcasting and downcasting are both allowed in C++. But when using downcasting, 2 things should be pay attention to:
The superclass should has at least one virtual method.
Since superclass is "smaller" than subclass, one should use memory object carefully.