views:

263

answers:

3

My program needs to make use of void* in order to transport data or objects in dynamic invocation situation, so that it can reference data of arbitrary types, even primitive types. However, I recently discovered that the process of down-casting these void* in case of classes with multiple base classes fails and even crashes my program after invoking methods on these down casted pointers even if the memory addresses seem to be correct. The crash happens during access to "vtable".

So I have created a small test case, environment is gcc 4.2 on Mac OS X:

class Shape {
public:
    virtual int w() = 0;
    virtual int h() = 0;
};

class Square : public Shape {
public:
    int l;
    int w() {return l;}
    int h() {return l;}
};

class Decorated {
public:
    int padding;
    int w() {return 2*padding;}
    int h() {return 2*padding;}
};

class DecoratedSquare : public Square, public Decorated {
public:
    int w() {return Square::w() + Decorated::w();}
    int h() {return Square::h() + Decorated::h();}
};


#include <iostream>

template <class T> T shape_cast(void *vp) {
//    return dynamic_cast<T>(vp);   // not possible, no pointer to class type
//    return static_cast<T>(vp);
//    return T(vp);
//    return (T)vp;
    return reinterpret_cast<T>(vp);
}

int main(int argc, char *argv[]) {
    DecoratedSquare *ds = new DecoratedSquare;
    ds->l = 20;
    ds->padding = 5;
    void *dsvp = ds;

    std::cout << "Decorated (direct)" << ds->w() << "," << ds->h() << std::endl;

    std::cout << "Shape " << shape_cast<Shape*>(dsvp)->w() << "," << shape_cast<Shape*>(dsvp)->h() << std::endl;
    std::cout << "Square " << shape_cast<Square*>(dsvp)->w() << "," << shape_cast<Square*>(dsvp)->h() << std::endl;
    std::cout << "Decorated (per void*) " << shape_cast<Decorated*>(dsvp)->w() << "," << shape_cast<Decorated*>(dsvp)->h() << std::endl;
    std::cout << "DecoratedSquare " << shape_cast<DecoratedSquare*>(dsvp)->w() << "," << shape_cast<DecoratedSquare*>(dsvp)->h() << std::endl;
}

produces the following output:

Decorated (direct)30,30
Shape 30,30
Square 30,30
Decorated (per void*) 73952,73952
DecoratedSquare 30,30

As you can see, the "Decorated (per void*)" result is completely wrong. It should also be 30,30 like in the first line.

Whatever cast method I use in shape_cast() I will always get the same unexpected results for the Decorated part. Something is completely wrong with these void *.

From my understanding of C++ this should be actually working. Is there any chance to get this to work with the void*? Can this be a bug in gcc?

Thanks

+2  A: 

A static_cast or a dynamic_cast in presence of multiple inheritance may change the representation of the pointer by offsetting it so that it designate the correct address. static_cast determines the correct offset by considering static typing information. dynamic_cast does it by checking the dynamic type. If you go throw void*, you are loosing all static typing information and the possibility to get dynamic typing information, so the reinterpret_cast you are using is assuming that the offset is null, failing some times.

AProgrammer
so does this effectively mean that void* are not feasible in multiple inheritance situations?
Andre Pareis
It is feasible, as long as you always cast to the actual type of the object, not a base class.
Mike Seymour
see my comment on Mike's answer
Andre Pareis
More precisely, you have to cast the void* to the static type the value had before being casted to void*.
AProgrammer
+4  A: 

It's not a compiler bug - it's what reinterpret_cast does. The DecoratedSquare object will be laid out in memory something like this:

Square
Decorated
DecoratedSquare specific stuff

Converting a pointer to this to void* will give the address of the start of this data, with no knowledge of what type is there. reinterpret_cast<Decorated*> will take that address and interpret whatever is there as a Decorated - but the actual memory contents are the Square. This is wrong, so you get undefined behaviour.

You should get the correct results if you reinterpret_cast to the correct dynamic type (that is DecoratedSquare), then convert to the base class.

Mike Seymour
That explains it but it would mean that without knowledge of the concrete subclass I can not produce code that works on pointers to one of the base classes in a polymorphic way like it would be possible in single inheritance situations, where the caller doesn't need to know the concrete subclass. In other words, it would not be possible to compile a framework and use that later when the concrete subclasses are known? That would means multiple inheritance in C++ is not complete.
Andre Pareis
MI in C++ is complete, unless you throw away the type information. You can use `virtual` functions to get polymorphic behaviour without knowing concrete subclasses if you don't cast wildly to wrong types.
Georg Fritzsche
To me, as I just don't know the concrete sub type in that part of the framework, it just means I can not use void* there. I have to carry type information somehow using an "any" or the like. Not nice and not what I had expected :( but at least you gave me an good explanation. Thanks everybody
Andre Pareis
@Andre, it isn't a problem of multiple inheritance, it is a problem of casting things to void*. What works is casting a pointer to void* and then back to its original *static* type (not dynamic like Mike seems to imply). Casting a void* to something else is undefined (well, there are some exceptions)
AProgrammer
You might be able to do what you want with a `reinterpret_cast` to `Shape` followed by a `dynamic_cast` to `Decorated`. I'm not 100% sure though, so I won't add it to the answer. It may well give undefined behaviour.
Mike Seymour
The natural ways of building a framework is either using templates or abstract types. void* is a way of doing low level stuff and should not be visible in your framework.
AProgrammer
@Mike, here the original static type is DecoratedSquare, so the void* should be casted to DecoratedSquare. If the original static type was Shape*, the void* should be casted to Shape* (and eventually then dynamically casted to DecoratedSquare).
AProgrammer
Mike you are my hero! Not it works: dynamic_cast<T>(reinterpret_cast<Shape*>(vp)); does it and gives me: Decorated (per void*) 10,10I have to see how this can be used in the framework but I think it should be possible, as I always know the first base class there. Thanks
Andre Pareis
@Andre, are you sure you can't transport stuff around as Shape* instead of void*? As you are now, though how do you know a pointer is a Shape* and not int* (or other primitive type)?
quamrana
@quamrana I could but with much more effort, especially i would need to wrap all primitives with objects and give everything a common base class. This framework part is generated code which takes a few void* and translates these to parameters to a normal method call. This way I get dynamic method invocation, an essential feature of my framework. it is very similar to the Qt signal/slots concept, they use the same methods (void*) there.
Andre Pareis
+4  A: 

Repeat ten times - the only thing you can safely do with a reinterpret_cast pointer is reinterpret_cast it back to the same pointer type it came from. The same applies with conversions to void*: you must convert back to the original type.

So, if you cast a DecoratedSquare* to void*, you must cast it back to DecoratedSquare*. Not Decorated*, not Square*, not Shape*. Some of them might work on your machine, but this is a combination of good luck and implementation-specific behaviour. It usually works with single-inheritance, because there's no obvious reason to implement object pointers in a way which would stop it working, but this is not guaranteed, and it can't work in general for multiple inheritance.

You say that your code accesses "arbitrary types, including primitive types" via a void*. There's nothing wrong with this - presumably whoever receives the data knows to treat it as a DecoratedSquare* and not as, say, int*.

If whoever receives it only knows to treat it as a base class, such as Decorated*, then whoever converts it to void* should static_cast it to the base class first, then to void*:

void *decorated_vp = static_cast<Decorated*>(ds);

Now when you cast decorated_vp back to Decorated*, you'll get the result of static_cast<Decorated*>(ds), which is what you need.

Steve Jessop
Steve thanks for this. I very much sums it up. Indeed, it is always ensured that in the calling part of the framework there is a known base pointer type which is cast to void* and then transported to the receiving end, which knows 2 things: the topmost base class and some subclass where a method is defined. It does not know, however, the concrete subclass. But this seems to be ok now, as the receiving end always reinterpret_casts to the same topmost base class as the sending end did and then does a dynamic_cast or static_cast to the intermediate subclass where it invokes the desired method.
Andre Pareis