Subclassing class from shared library compiled with -fno-rtti
Asked Answered
I

2

8

I am trying to subclass from a shared library which was compiled with -fno-rtti. Unfortunately other libraries in my code base require -frtti. As a result I am getting link errors because the superclass does not have a typeinfo struct.

Error received in a normal compilation:

out.o: in function typeinfo for MyClass:myclass.cpp(.data.rel.ro.<cpp magic>): error: undefined reference to 'typeinfo for NetlinkListener'

The class I want to subclass is an android class in libsysutils (snipped a little for space):

class NetlinkListener : public SocketListener {
    char mBuffer[64 * 1024];
    int mFormat;

public:
    static const int NETLINK_FORMAT_ASCII = 0;
    static const int NETLINK_FORMAT_BINARY = 1;

    NetlinkListener(int socket);
    NetlinkListener(int socket, int format);
    virtual ~NetlinkListener() {}

protected:
    virtual bool onDataAvailable(SocketClient *cli);
    virtual void onEvent(NetlinkEvent *evt) = 0;
};

My stub looks like:

class MyClass: public NetlinkListener {

public:
    MyClass();
    virtual ~MyClass();

    int start();
    int stop();

protected:
    virtual void onEvent(NetlinkEvent *evt);
};

All the methods in MyClass are implemented (as empty stubs)

I cannot compile the shared library -frtti. Is there any way to work around this?

Immesh answered 27/2, 2013 at 0:4 Comment(2)
Can you post a sample code on how you're trying to subclass a superclass ?Amphi
@Amphi Added the headers. There is not implementation of the subclass (just stubs). The code for the super class is open source ASOP.Immesh
B
5

1) For simple cases, you could just create a C wrapper of the interface (built with no RTTI). Then you can use the C interface in RTTI enabled programs, provided you treat them as abstract C types from your RTTI enabled program.

2) Compiling the library with RTTI is exactly what you should do (or request of the vendor), unless there is a very good reason for RTTI to be disabled (e.g. you're working in a domain where exceptions should not be used, such as a kernel, drivers, or some other no exception zone -- or where memory is tight).

3) Alter your library to not use dynamic_cast, exceptions, typeid operator, or whatever it is that causes the issue and rebuild with RTTI disabled. Similar to 1, you can make this a separate abstraction library, depending on how the program is organized.

4a) The next option is to never reference the type info for the object (e.g. do not dynamic_cast or throw it) -- and this can be a pain. That will remove linker errors of referenced type infos.

4b) It may be easiest to create an inner class (suppose there are methods you must override, and there are types you must interface with your rtti-dependent programs). You can create a type (inner) which inherits from their lib's type and performs the necessary overrides, but then calls back through some other class hierarchy (the other hierarchy is free to use rtti). Now the inner class' virtual exports are placed in a TU with rtti disabled (because it will otherwise implicitly reference its base class' type info). Then you can easily quarantine the type info dependence and build out a hierarchy which uses things like exceptions -- this hierarchy uses that inner type as a value. Of course, if that works, it's all implementation defined -- you would need to understand how RTTI and vtables are structured for your targeted platforms (see ABI refs). Even omission of RTTI is deviation from standard C++. There is no information that states that the presence of a symbol will result in proper construction of your vtables and type info of a base which was compiled without those features.

That said, 1 and 2 are your safe options, 3 is within the domain of the no-rtti platform extension (safe), and 4 is an approach which is free to work on no or only some systems.

Illustrating 4b

class MyClass // << cast me. throw/catch me. get my mangled name,
              //    but put my family's virtual exports in a TU with RTTI enabled
: public MyRTTIEnabledFamily {
public:
    MyClass() : d_inner(*this) {}
    virtual ~MyClass();
private:
    void cb_onEvent(NetlinkEvent * evt) {
        // no-rtti suggests exceptions may not be available,
        // so you should be careful if your program throws.
        someInfo = evt->getInfo();
    }
private:
    // non-rtti hierarchy
    class t_inner : public NetlinkListener {
    public:
        t_inner(MyClass& pMyClass) : NetlinkListener(), d_myClass(pMyClass) {
        }

        virtual ~t_inner(); // << put your virtual exports in a TU with RTTI disabled.
                            //    one out of line virtual definition is necessary for most compilers
    private:
        virtual void onEvent(NetlinkEvent * evt) {
            // how the callback to your imp actually happens
            this->d_myClass.cb_onEvent(evt);
        }
    private:
        MyClass& d_myClass;
    };
private:
    t_inner d_inner; // << don't do anything with my type info -- it does not exist.
};
Behaviorism answered 5/3, 2013 at 0:30 Comment(4)
I looked into solution 1, but the issue is that there is a virtual void onEvent(...) method that my subclass needs to override, and will be called by a superclass defined method (onDataAvailable). How can I write a wrapper, but succeed in getting this call back?Immesh
Your solution 4b seems to deal with this situation. Can you give me some stub code of how exactly I would setup this kind of inheritance?Immesh
@JonL right -- you still have to subclass behind the C interface, then you just create a basic callback interface. the basic form of a callback to the client is typedef void (*t_netlink_event_callback)(void* pContextInfo, NetlinkEvent * pEvent); -- so you then call the client's C function pointer in your override, using the context info they have passed. ill.code:Behaviorism
(cont) class t_my_subclass : NetlinkListener { \n virtual void onEvent(NetlinkEvent* pEvent) { \n this->d_netlinkEventCallbackProc(this->d_netlinkEventCallbackProcContextInfo, pEvent); \n } \n \n private: \n t_netlink_event_callback d_netlinkEventCallbackProc; \n void* d_netlinkEventCallbackProcContextInfo; \n }; of course, the client would also need a way to specify the proc and context info.Behaviorism
A
0

Passing -fno-rtti only disables the dynamic_cast and typeid functionality as per gcc's documentation. You should be able to derive classes and use virtual methods without any issues.

The undefined reference to typeinfo for class error usually appears if you declare a function as virtual without providing a defintion for it.

In fact I see NetlinkHandler.h and NetlinkHandler.cpp in the AOSP doing exactly what you're trying to do and I do not find any difference between those file and the code snippets you've posted.

Amphi answered 5/3, 2013 at 0:32 Comment(1)
My code needs to compile with -frtti because of another library which needs the dynamic_cast functions. The AOSP NetlinkHandler in vold (libvold) compiles -fno-rtti which matches the libsysutils, so it doesn't have this issue.Immesh

© 2022 - 2024 — McMap. All rights reserved.