exception, -fvisibility=hidden and shared object

This is the common main.cpp for the first and second version.

main.cpp:

#include <iostream>
#include <stdexcept>

int my_object();

int main()
{
try{
my_object();
}
catch(std::exception & e)
{
std::cout << e.what() << std::endl;
}
return 0;
}

Version 1

shared1.cpp:

#include <stdexcept>

int __attribute__ ((visibility("default"))) my_object()
{
throw std::runtime_error("my_object throw");
}

compile it with

g++ -shared -o libshared.so shared1.cpp -fvisibility=hidden


and

g++ -o main main.cpp -lshared -L. -fvisibility=hidden

in this case: WORKS
The first version shows that throw a std::exception and capture it, works.
In fact GCC uses std::exception RTTI symbols stored in GLIBC and does not need to export it again.

Version 2

shared2.cpp:
#include <stdexcept>

class my_exception : public std::exception {
public:
virtual ~my_exception() throw() { }
virtual const char*
what() const throw() { return "my_exception"; }
};

int __attribute__ ((visibility("default"))) my_object()
{
throw my_exception();
}


in this case: WORKS.
my_exception's RTTI is not exported, however the parent one continues to be stored in GLIBC and, in such way, available.

Version 3

my_hidden_exception.h

class my_exception {
public:
virtual ~my_exception() throw() { }
virtual const char*
what() const throw() { return "my_exception"; }
};


main3.cpp:

#include <iostream>
#include "my_hidden_exception.h"

int my_object();

int main()
{
try{
my_object();
}
catch(my_exception & e)
{
std::cout << e.what() << std::endl;
}
return 0;
}

shared3.cpp:

#include "my_hidden_exception.h"

int __attribute__ ((visibility("default"))) my_object()
{
throw my_exception();
}

In this case it does NOT WORK!

# ./main
terminate called after throwing an instance of 'my_exception'
Abort

my_exception's RTTI in this case is not exposed: in main and shared exist two different RTTI version for my_exception.

For example:
(main)   RTTI address: 0x08048b4e
(shared) RTTI address: 0xb77b7a0c

Version 4

my_exception.h
class __attribute__ ((visibility("default")))  my_exception {
public:
virtual ~my_exception() throw() { }
virtual const char*
what() const throw() { return "my_exception"; }
};

main4.cpp
#include <iostream>
#include "my_exception.h"

int my_object();

int main()
{
try{
my_object();
}
catch(my_exception & e)
{
std::cout << e.what() << std::endl;
}
return 0;
}

shared4.cpp
#include "my_exception.h"

int __attribute__ ((visibility("default"))) my_object()
{
throw my_exception();
}

In this case WORKS.
Is important to underline that the exception HAVE to be visible in both object file (main and shared). Otherwise it does not work!

See Also

Why is the new C++ visibility support so useful?