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?