2

I have some code which expects type_index instances for a particular type created in a shared library and instances created in an executable (for the same particular type) to compare equal.

However, I have encountered a case where this does not work on QNX 7:

// idxlib.h

#include <typeindex>
#include <string>
#include <iostream>

#ifdef BUILD_LIB
#define LIB_EXPORT __attribute__((visibility("default")))
#else
#define LIB_EXPORT 
#endif

template <typename T>
class Templ 
{
};

class LIB_EXPORT LibType 
{
public:
    LibType();

    template <typename T=int>
    void templateMethod(int arg = 0) const
    {

#ifndef REMOVE_INSTANTIATION
        if (arg == 42)
        {
            // arg is never 42. This code path is not taken, but it instantiates the template
            templateMethod();
        }
#endif

        if (mti == std::type_index(typeid(Templ<int>)))
            std::cout << "Type indexes the same" << std::endl;
        else
            std::cout << "Type indexes NOT the same" << std::endl;
    }

    void normalMethod();

protected:
    std::type_index mti;
};

// idxlib.cpp

#include "idxlib.h"

LibType::LibType() : mti(std::type_index(typeid(Templ<int>))) {}

void LibType::normalMethod()
{
    templateMethod();
}
// sharedidx.cpp

#include "idxlib.h"

int main(int argc, char* argv[])
{
    LibType lt;

    if (argc == 65)
        // argc is not 65, so don't call it, just instantiate it
        lt.templateMethod();
    lt.normalMethod();
    return 0;
}

Build, scp and run:

QCC -Vgcc_ntox86_64 -g -fPIC -o idxlib.cpp.o -c idxlib.cpp -DBUILD_LIB -fvisibility=hidden -fvisibility-inlines-hidden
QCC -Vgcc_ntox86_64 -g -shared  -o libidx.so idxlib.cpp.o 
QCC -Vgcc_ntox86_64 -g -o sharedidx libidx.so  sharedidx.cpp

scp -i ~/qnxinstall/id_rsa_qnx sharedidx libidx.so qnxuser@${QNXBOX}:/home/qnxuser/test

echo
echo "comparison fails:"
ssh -i ~/qnxinstall/id_rsa_qnx -t qnxuser@${QNXBOX} "cd /home/qnxuser/test && LD_LIBRARY_PATH=/home/qnxuser/test ./sharedidx"

QCC -Vgcc_ntox86_64 -g -shared -fPIC -o idxlib.cpp.o -c idxlib.cpp -DREMOVE_INSTANTIATION -DBUILD_LIB -fvisibility=hidden -fvisibility-inlines-hidden
QCC -Vgcc_ntox86_64 -g -shared  -o libidx.so idxlib.cpp.o 
QCC -Vgcc_ntox86_64 -g -o sharedidx libidx.so -DREMOVE_INSTANTIATION sharedidx.cpp -fvisibility=hidden  -fvisibility-inlines-hidden

scp -i ~/qnxinstall/id_rsa_qnx sharedidx libidx.so qnxuser@${QNXBOX}:/home/qnxuser/test

echo
echo "comparison works:"
ssh -i ~/qnxinstall/id_rsa_qnx -t qnxuser@${QNXBOX} "cd /home/qnxuser/test && LD_LIBRARY_PATH=/home/qnxuser/test ./sharedidx"

Output:

Type indexes NOT the same
Type indexes the same

So, the type_index comparison fails when there is a template instantiation which contains a template instantiation of itself.

Is it a bug in QNX 7, or is my expectation (that it should ever work) wrong?

Is this code relying on implementation-defined behavior? Or undefined behavior?

QNX 7 QCC compiler is based on GCC 5.4 and uses a standard library based on libc++ from the same era. I have tested GCC 5.4 (and clang with libc++ and libstdc++) on Linux and I do not get the same behavior. I have also tried with and without _LIBCPP_NONUNIQUE_RTTI_BIT defined.

So, I'm assuming this is a result of the linker rather than the compiler. Could that be true?

Are the GCC compilers just "too helpful" in making this work on Linux across shared library boundaries?

steveire
  • 10,694
  • 1
  • 37
  • 48
  • You need to make sure the type's rtti info is exported from one of the shared libraries so that each library doesn't end up with its own copy – Alan Birtles Sep 21 '20 at 17:41
  • See https://stackoverflow.com/questions/19496643/using-clang-fvisibility-hidden-and-typeinfo-and-type-erasure for example – Alan Birtles Sep 21 '20 at 17:44

1 Answers1

1

I would never assume that RTTI works correctly on an embedded systems targeting toolchain. It might be supposed to work correctly, but almost nobody enables RTTI nor exceptions for embedded systems, so it'll get zero testing nor attention from support.

I'd suggest that you use a library based RTTI emulation, such as https://www.boost.org/doc/libs/1_74_0/doc/html/boost_typeindex.html which works on systems without RTTI, and is also fully deterministic and bounded in space and time unlike language RTTI.

Niall Douglas
  • 9,212
  • 2
  • 44
  • 54