8

(This is like my other question but this one is for another thing, even if it's related)

I've got a big issue in my project. I've got a library which handle XML and can throw exception. And, using it for creating a configuration file class show my first bug : exceptions aren't handled in the library, at all, and with every exception.

In the library I wrote :

try {
    throw std::exception();
}
catch (...)
{
    printf("caught\n");
}

But, the exception isn't handled and call std::terminate immediately :

terminate called after throwing an instance of 'std::exception'
  what():  std::exception

The compilation flags are the simplest one : -fPIC -std=c++11 -g -Wall for the library, and -std=c++11 -g -Wall for the executable (plus the libraries and variant build defines). Also, I'm using G++ 5.4.0, under Linux (Linux Mint to be precise).

This is my main :

#include "ns/core/C_Configuration.hpp"

#include <iostream>

using namespace std;
using namespace ns;


int
main (int argc, char** argv)
{
    try {
        C_Configuration c ("test.xml");
        c.load ("test.xml");
    } catch (const std::exception& ex) {
        cout << ex.what () << endl;
    } catch (...) {
        cout << "Caught." << endl;
    }


    return 0;
}

The C_Configuration.hpp :

#include <string>
#include <exception>


namespace ns
{


    class C_Configuration
    {

    public:

        C_Configuration (std::string);


        bool load (std::string file);

    };


} // namespace ns

And, this is the C_Configuration.cpp :

#include "ns/core/C_Configuration.hpp"

#include <cstdio>

using namespace std;


namespace ns
{



C_Configuration::C_Configuration (string)
{ }



bool
C_Configuration::load (string file)
{

    try {
        throw exception();
    } catch (const exception& ex) {
        printf ("In C_Configuration : %s\n", ex.what ());
    } catch (...) {
        printf ("In C_Configuration : caught\n");
    }


    return true;
}


} // namespace ns

Buid commands :

g++ -m64 -g -shared -fPIC -std=c++11 -o libns_framework.so C_Configuration.cpp
g++ -m64 -g -L. -o exe main.cpp -lns_framework 

Note : I give this example, but it works as expected, the exception is caught in the library, not like in my main project. If you want to investigate more, you can check my project code here.

The problem is when :

  • The try-catch block is inside the library ;
  • The try-catch block is outside the library ;

In any case, the exception is thrown inside the library. But, exception thrown outside are caught in the executable code :

int
main (int argc, char** argv)
{
    try {
        throw 1;
    } catch (...) {
        cout << "Caught" << endl;
    }

    // Useless code

    return 0;
}

This code just write Caught in the output.

So, my question is simple : Is C++ exception not handled within libraries, or I just forgot a compilation flag ? I need to say in the executable code, the exceptions work fine.

Thanks for your help.

EDIT : Oh god, my bad. Problem solved. Into the deepest part of my build configuration, an ld took the place of g++. Now the exception is working fine. Thanks for you help.

Community
  • 1
  • 1
  • 4
    You mean "over shared library calls" not "within libraries" right? How, exactly, is the library built, the code that calls the library built, and can you generate a [MCVE] of a toy library that throws and a toy app that loads it and fails to catch? – Yakk - Adam Nevraumont Aug 10 '16 at 16:55
  • Done. I thought it was useless here since it isn't related to any "real" code. – Nils 'Linkpy' Reid Aug 10 '16 at 17:03
  • 1
    The example isn't complete. Your `main` has a reference to `C_Configuration` which isn't defined (except in the other source). You're at least missing an `#include`. Without being _Complete_ the example is not _Verifiable_. If I can't compile your code, I can't test it for myself. – davmac Aug 10 '16 at 17:08
  • I "think" it's done now. – Nils 'Linkpy' Reid Aug 10 '16 at 17:13
  • Nope. C_Configuration.cpp still declares a member of an undeclared class. Did you try to compile your own example? And what is the exact sequence of commands you use to compile and link both objects? – davmac Aug 10 '16 at 17:18
  • What are your link commands? – rustyx Aug 10 '16 at 17:19
  • Show complete command lines how you compile and link. – Maxim Egorushkin Aug 10 '16 at 17:23
  • And, just in case: check which library your program is linking against at run-time (use `ldd`). – davmac Aug 10 '16 at 17:27
  • Compile command : `g++ -IHeaders/ -ILibraries/ns_framework/Headers -ILibraries/osumax_shared/Headers -std=c++11 -g -Wall -DDEBUG -DLINUX -DX86_64 -m64 -c -o Objects/Main.o Sources/Main.cpp` And the link command : `g++ -L./Libraries/ -m64 Objects/Main.o -ltinyxml2 -lns_framework -lsfml-system -lsfml-window -lsfml-graphics -losumax_shared -o ./osumax` – Nils 'Linkpy' Reid Aug 10 '16 at 17:39
  • @davmac : I tried to build the example but.. The example works. The exception is caught in the library. – Nils 'Linkpy' Reid Aug 10 '16 at 17:40
  • @Nils'Linkpy'Reid then it's not a _Verifiable_ example. The idea is to reduce your program - which exhibits the behaviour - to the smallest possible (_Minimal_) program which is still compilable (_Complete_) and still exhibits the problem (_Verifiable_) - hence "MCVE". If your smaller example doesn't exhibit the problem, then it's something about your original program which is causing the issues. You need to reduce it piece by piece until you can discover what change makes it start/stop working. – davmac Aug 10 '16 at 23:47
  • @Nils'Linkpy'Reid I see you've found the problem and edited the solution into your question. I suggest you delete the question, or otherwise (if you think it could be useful to others) post the solution as an answer. – davmac Aug 10 '16 at 23:49

2 Answers2

6

Simple. Never use ld with C++. I changed all ld commands in my project to g++ but seems I forgot for this library.

In short, I was using ld for building my library but g++ for the main executable. So the exceptions worked in the executable but not in the library because ld does not includes the C++ libraries which handle the exception system.

5

According to gcc manual:

if a library or main executable is supposed to throw or catch exceptions, you must link it using the G++ or GCJ driver, as appropriate for the languages used in the program, or using the option -shared-libgcc, such that it is linked with the shared libgcc.

Shared libraries (in C++ and Java) have that flag set by default, but not main executables. In any case, you should use it on both.

Test Case:

lib.cpp:

#include "lib.hpp"
#include <string>
#include <iostream>

using namespace std;

int function_throws_int() {
    try {
        throw 2;
    }
    catch (...) {
        cout << "int throws lib" << endl;
        throw;
    }

    return -1;
}

int function_throws_string() {
    try {
        throw std::string("throw");
    }
    catch (...) {
        cout << "throws string lib" << endl;
        throw;
    }
}

lib.hpp:

int function_throws_int();
int function_throws_string();

Compile command line: g++ -m64 -g -shared-libgcc -shared -fPIC -std=c++11 -o libtest.so lib.cpp

main.cpp:

#include "lib.hpp"
#include <string>
#include <iostream>

using namespace std;

int main(int argc, char ** argv) {
    try {
        function_throws_int();
    }
    catch (const string & e) {
        cout << "string caught main" << endl;
    }
    catch (int i) {
        cout << "int caught main" << endl;
    }

    return 0;
}

Compile command line: g++ -m64 -g -shared-libgcc -o main -L. main.cpp -ltest

Execute: LD_LIBRARY_PATH=. ./main

Output:

int throws lib
int caught main
Bruno Ferreira
  • 1,621
  • 12
  • 19
  • Tried : `./osumax: error while loading shared libraries: ared-libgcc: cannot open shared object file: No such file or directory` And LDD says : `ared-libgcc => not found` – Nils 'Linkpy' Reid Aug 10 '16 at 17:37
  • And, in the link options page : `Therefore, the G++ and GCJ drivers automatically add -shared-libgcc whenever you build a shared library or a main executable, because C++ and Java programs typically use exceptions, so this is the right thing to do.` and LDD says : `libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1` – Nils 'Linkpy' Reid Aug 10 '16 at 17:44
  • Shared objects must go to /usr/lib on linux OR set the LD_LIBRARY_PATH env properly. See: http://serverfault.com/questions/279068/cant-find-so-in-the-same-directory-as-the-executable – Bruno Ferreira Aug 11 '16 at 18:45