Try-catch doesn't work in shared library? - c++

(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.

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.

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

Related

dlopen Segmentation fault error when get a instance from shared library's exported function

I have been stuck in a problem for several days when using dlopen/dlsym to deal with the shared object. I desperately need your help!
There are three headers/source files: Animal.h, Animal.cpp and test.cpp, and two products: libanimal.so and a.out.
Here is the source code:
Animal.h:
// Animal.h
#ifndef STDLIB_ANIMAL_H
#define STDLIB_ANIMAL_H
#include <string>
class Animal {
public:
Animal();
std::string shout();
};
extern "C" Animal* createAnimal();
#endif //STDLIB_ANIMAL_H
Animal.cpp
// Animal.cpp
#include "Animal.h"
Animal::Animal() = default;
std::string Animal::shout() {
return "WOW";
}
Animal* createAnimal() {
return new Animal();
}
and the last one test.cpp which contained the main entry of the application:
// test.cpp
#include <cstdio>
#include <cstdlib>
#include <string>
#include <dlfcn.h>
#include <iostream>
#include "Animal.h"
int main(int argc, char** argv)
{
void *handle;
// Open shared library
handle = dlopen("./libanimal.so", RTLD_LAZY);
if (!handle) {
/* fail to load the library */
fprintf(stderr, "Handle Error: %s\n", dlerror());
return EXIT_FAILURE;
}
auto spawnAnimal = reinterpret_cast<Animal* (*)()>(dlsym(handle, "createAnimal"));
if (!spawnAnimal) {
/* no such symbol */
fprintf(stderr, "No Such Symbol Error: %s\n", dlerror());
dlclose(handle);
return EXIT_FAILURE;
}
auto animal = spawnAnimal();
std::cout << "call animal shout, the address of animal : " << animal <<std::endl;
std::cout << animal->shout() << std::endl;
std::cout << "after calling" << std::endl;
dlclose(handle);
return EXIT_SUCCESS;
}
First, I built libanimal.so shared library by the following command:
$ g++ -shared -fPIC -Wall -o libanimal.so Animal.cpp -std=c++0x
Then I built the executable, a.out:
$ g++ -Wall test.cpp -ldl -std=c++0x -Wl,--unresolved-symbols=ignore-in-object-files
# --unresolved-symbols=ignore-all: tell linker to stop complaining about missing symbols
Both the above commands ran well without any error, but when I execute a.out, errors came out:
$ ./a.out
call animal shout, the address of animal : 0x7fffe97a4520
Segmentation fault (core dumped)
I have searched lots of blogs/documentations, but all of them just post a really simple example:
The function they export always return like a std::string or char or int which is built-in type, not something like a object of a user-defined class, just like the showcase above (the createAnimal function).
So what's wrong with this? Could you please help me figuring out ?
Thank you !
BTW, my environment is:
$ g++ --version
g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Ok, my suspicion from the comment has confirmed itself. The problem is with the early binding on animal->shout() which resolves at compile time to a call to _ZN6Animal5shoutB5cxx11Ev and this symbol is nowhere to be found.
If I change it to virtual (late binding, resolved at runtime through a vtable):
// Animal.h
#ifndef STDLIB_ANIMAL_H
#define STDLIB_ANIMAL_H
#include <string>
class Animal {
public:
Animal();
virtual std::string shout();
virtual ~Animal() {} // always put a virtual destructor if you have any virtual methods
};
extern "C" Animal* createAnimal();
#endif //STDLIB_ANIMAL_H
Now it runs.
You have an unresolved symbol in your main executable. Do not ignore these error messages.
./tmp/cchZxfAz.o: In function `main':
test.cpp:(.text+0x112): undefined reference to `Animal::shout[abi:cxx11]()'
collect2: error: ld returned 1 exit status

SIGSEGV on C++/Glade/gtkmm

I'm creating my first GUI application with C++ using gtkmm and Glade.
I had to merge various tutorials, because none I found is supporting Glade in combination with Gtk::Application and various classes.
See the code below:
main.cpp
int main(int argc, char **argv)
{
std::cout << "Start" << std::endl;
auto app = Gtk::Application::create(argc,argv,"org.gtkmm.ex");
auto builder = Gtk::Builder::create();
builder->add_from_file("gui02.glade");
HelloWorld* helloworld;
std::cout << "helloworld compl." << std::endl;
app->run(*helloworld);
return 0;
}
helloworld.hpp
#include <gtkmm.h>
class HelloWorld : public Gtk::Window
{
protected:
Glib::RefPtr<Gtk::Builder> builder;
Gtk::Button *btn1;
Gtk::Label *lb1;
public:
HelloWorld(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refGlade);
protected:
void on_button1_clicked();
};
helloworld.cpp
#include "helloworld.hpp"
using namespace std;
using namespace Gtk;
HelloWorld::HelloWorld(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refGlade) :
Gtk::Window(cobject), builder(refGlade)
{
builder->get_widget("label1", lb1);
builder->get_widget("button1", btn1);
btn1->signal_clicked().connect(sigc::mem_fun(*this, &HelloWorld::on_button1_clicked));
}
void HelloWorld::on_button1_clicked()
{
lb1->set_text("HW!");
}
Compiling using:
g++ main.cpp helloworld.cpp -o main `pkg-config gtkmm-3.0 --cflags --libs`
Result in the command line:
Start
helloworld compl.
Segmentation fault (core dumped)
Debugging with gdb (relevant extract, you get the full output if neccessary)
Glib::RefPtr::operator-> (this=0x7fffffffdd10) at /usr/include/glibmm-2.4/glibmm/refptr.h:260
260 return pCppObject_;
Thread 1 "main" received signal SIGSEGV, Segmentation fault.
0x00007ffff7a4799e in Gtk::Widget::signal_hide() () from /usr/lib/x86_64-linux-gnu/libgtkmm-3.0.so.1
Because I'm quite new to C++ (having some experience with C#), I'm not so used to pointers. Where is the error in this case?
Using a different code, where I create a Window* and use "app->run(*window)" works pretty fine, so the error occurs somewhere in the new app->run() and the outsourcing in class "HelloWorld".
Your code crashes here app->run(*helloworld);
You try to dereference an empty pointer. That pointer does not point to an object in memory.
Do it like this:
HelloWorld* helloworld = new HelloWorld();
std::cout << "helloworld compl." << std::endl;
app->run(*helloworld);

Calling function in shared library (Linux) get Segmentation Fault

I was trying to write a basic example of shared library opening and function calling for practice, but it turns out that I always get "segmentation fault" when the exectuable is actually running. Here are the source code:
main.cpp:
#include<iostream>
#include<dlfcn.h>
using namespace std;
typedef void (*API)(unsigned int);
int main(int argc,char** argv){
void* dl;
API api;
unsigned int tmp;
//...
dl=dlopen("pluginA.so",RTLD_LAZY);
api=(API)dlsym(dl,"API");
cin>>tmp;
(*api)(tmp);
dlclose(dl);
//...
return 0;
}
pluginA.cpp:
#include<iostream>
using namespace std;
extern "C" void API(unsigned int N){switch(N){
case 0:cout<<"1\n"<<flush;break;
case 1:cout<<"2\n"<<flush;break;
case 2:cout<<"4\n"<<flush;break;
case 4:cout<<"16\n"<<flush;break;}}
I compiled the two part with the following command:
g++ -shared -o pluginA.so -fPIC plugin.cpp
g++ main.cpp -ldl
Here is the output
Segmentation fault (core dumped)
BTW, I also tried directly call api(tmp) rather than (*api)(tmp), that also don't work. Since api is a pointer, (*api) makes more sense?
I'm not sure what should I do. There are many totorials about calling function in shared library online, but most of them aren't fully coded, or they actually don't work.
And also I'm not sure what should I do with "attribute((visibility("default")))". Should I even write it down?
EDT1
Thanks for giving me so much advice. I finally find out that actually everything is a typo in compiling command... I mistakenly typed pluginA.so to pluginA.o, and that's the reason why it don't work...
Anyway, here is my revised program, with error handling added, and more "full" system added:
main.cpp:
#include<dirent.h>
#include<dlfcn.h>
#include<iostream>
#include<cstring>
using namespace std;
typedef bool (*DLAPI)(unsigned int);
int main(){
DIR* dldir=opendir("dl");
struct dirent* dldirf;
void* dl[255];
DLAPI dlapi[255];
unsigned char i,dlc=0;
char dldirfname[255]="./dl/";
unsigned int n;
while((dldirf=readdir(dldir))!=NULL){
if(dldirf->d_name[0]=='.')continue;
strcat(dldirfname,dldirf->d_name);
dl[dlc]=dlopen(dldirfname,RTLD_LAZY);
if(!dl[dlc])cout<<dlerror()<<endl;else{
dlapi[dlc]=(DLAPI)dlsym(dl[dlc],"API");
if(!dlapi[dlc])cout<<dlerror()<<endl;else dlc++;}
dldirfname[5]='\0';}
if(dlc==0){
cerr<<"ERROR:NO DL LOADED"<<endl;
return -1;}
while(true){
cin>>n;
for(i=0;i<dlc;i++)if((*dlapi[i])(n))break;
if(i==dlc)cout<<"NOT FOUND"<<endl;}
for(i=0;i<dlc;i++)dlclose(dl[i]);
return 0;}
You should read documentation of dlopen(3) and dlsym and you should always handle failure. So code
dl=dlopen("./pluginA.so",RTLD_LAZY);
if (!dl) { fprintf(stderr, "dlopen failure: %s\n", dlerror());
exit (EXIT_FAILURE); };
api=(API)dlsym(dl,"API");
if (!api) { fprintf(stderr, "dlsym failure: %s\n", dlerror());
exit (EXIT_FAILURE); };
The documentation of dlopen is explaining why you want to pass ./pluginA.so with a ./ prefix
At last, you should always compile with all warnings and debug info, so:
g++ -Wall -Wextra -g -shared -o pluginA.so -fPIC plugin.cpp
g++ -Wall -Wextra -g -rdynamic main.cpp -ldl
(It is useful to link the main program with -rdynamic so that the plugin could access its symbols)
You could want to dlclose(dl) just before the end of main ... (calling or returning from a dlsym-ed function will crash your program if you dlclose too early). You might even avoid the dlclose (i.e. accept some resource leak). By experience you usually can dlopen many hundreds of thousands shared objects (see my manydl.c)
Only once your program is debugged you could add some optimization flag like -O or -O2 (and perhaps remove the debugging flag -g, but I don't recommend that for beginners).
You should perhaps read Drepper's paper: How To Write Shared Libraries.
I correted your code a bit and use the error checking. Try that and get the idea what's going on:
#include<iostream>
#include<dlfcn.h>
using namespace std;
typedef void (*API)(unsigned int);
int main(int argc,char** argv)
{
API api;
unsigned int tmp;
//...
void* handle = dlopen("pluginA.so", RTLD_LAZY);
if (!handle)
{
std::cerr << dlerror() << std::endl;
return 1;
}
dlerror();
api = reinterpret_cast<API>(dlsym(handle, "API"));
if (!api)
{
std::cerr << dlerror() << std::endl;
return 2;
}
cin>>tmp;
(*api)(tmp);
dlclose(handle);
//...
return 0;
}
At last: why it is failed? Use the right path: "./pluginA.so", not "pluginA.so" or put the full path to your plugin.

dlopen() gives unresolved symbol error when .so tries to use a class from the main executable. Why?

I'm on Linux, the question is concerning shared objects of C++ classes.
The problem comes when my shared objects try to use resources linked into the main executable. I have the following codes:
loader.cpp:
#include <dlfcn.h>
#include <iostream>
#include "CommonInfo.h"
using namespace std;
int main(int argc, char** argv) {
for(int i=1; i<argc; ++i) {
string pth = "./";
pth.append(argv[i]);
void* dh = dlopen(pth.c_str(), RTLD_NOW);
if(dh==NULL) {
cerr << dlerror() << endl;
return 1;
}
CommonInfo::GetInfoFunc getInfo = (CommonInfo::GetInfoFunc)(dlsym(dh,"getInfo"));
if(getInfo==NULL) {
cerr << dlerror() << endl;
return 1;
}
CommonInfo* info = getInfo();
cout << "INFO: " << info->getX() << endl;
delete info;
}
return 0;
}
CommonInfo.h:
#include <string>
class CommonInfo {
public:
typedef CommonInfo* (*GetInfoFunc)();
private:
std::string x;
public:
CommonInfo(const std::string& nx);
std::string getX() const;
};
EDIT:
I accidentaly forgot to ctrl-c + ctrl-v the source of CommonInfo.cpp here. Of course, it is there during compilation, so CommonInfo.cpp:
#include "CommonInfo.h"
CommonInfo::CommonInfo(const std::string& nx) : x(nx) {
}
std::string CommonInfo::getX() const {
return x;
}
A Plugin.h header:
#include "CommonInfo.h"
extern "C" CommonInfo* getInfo();
A very simple Plugin.cpp:
#include <iostream>
#include "Plugin.h"
#include "CommonInfo.h"
using namespace std;
CommonInfo* getInfo() {
return new CommonInfo("I'm a cat!");
}
Compiling is done with:
g++ -rdynamic -ldl -Werror CommonInfo.cpp loader.cpp -o loader
g++ -shared -fPIC -Werror Plugin.cpp -o Plugin.so
Running:
./loader Plugin.so
And there goes the error:
./loader: symbol lookup error: ./Plugin.so: undefined symbol: _ZN10CommonInfoC1ERKSs
Indeed, looking inside Plugin.so with nm Plugin.so | grep -i CommonInfo it gives an 'U' for this symbol (unresolved), which is perfectly ok.
Also, looking inside the binary of loader with nm loader.so | grep -i CommonInfo I could find the symbol with 'T', which is also ok.
Question is, shouldn't dlfcn.h unresolve the symbol in question from the main binary? Without this feature it becomes quite hard to use these stuff... Do I have to write a class factory function for CommonInfo, load it with dlfcn from the plugin and call that?
Thanks in advance,
Dennis
I haven't looked closely at your code, but I have in the past found behavior like you describe in the title when I did not link the executable with -E. (Or -Wl,-E when linking with gcc rather than ld.)
Note that not all platforms let the shared libraries take symbols from the calling binary. Linux and the *BSDs allow you to. But if you ever want to port to, say, Windows, you will not be able to use this pattern. I believe there are also some Unix-type OS's that won't let you do this. (It's been a while so I don't remember... Maybe it was Solaris?)

C++ compiling problem; class methods

I have started writing a very simple class, and all kinds of class methods seem to give me problems. I hope the problem is me and the solution is simple.
The command g++ -o main main.cpp gives the folowing output:
/usr/bin/ld: Undefined symbols:
Lexer::ConsoleWriteTokens()
collect2: ld returned 1 exit status
main.cpp:
#include<iostream>
#include"lexer.h"
int main(){
Lexer lexhnd = Lexer();
std::cout << "RAWR\n";
lexhnd.ConsoleWriteTokens();
std::cout << "\n\n";
return 0;
}
lexer.h:
#ifndef __SCRIPTLEXER
#define __SCRIPTLEXER
#include <iostream>
#include <string>
#include <vector>
#define DEF_TOKEN_KEYWORD 0
struct token{
int flag;
std::string data;
};
class Lexer
{
public:
// bool IsTrue();
// bool AddLine(char * line);
void ConsoleWriteTokens(void);
private:
std::vector<token> TOK_list;
};
#endif
lexer.cpp:
bool Lexer::IsTrue(){
return true;
};
bool Lexer::AddLine(char * line){
token cool;
cool.data = line;
TOK_list.push_back(cool);
string = line;
return true;
};
void Lexer::ConsoleWriteTokens(void){
for (int i = 0; i < TOK_list.size(); i++){
std::cout << "TOKEN! " << i;
}
return 0;
};
I am using g++ in xcode btw.
Thankyou very much in advance, I have been on this problem for a few hours.
EDIT:
g++ -o main lexer.h main.cpp
or
g++ -o main lexer.cpp main.cpp
or
g++ -o main main.cpp lexer.cpp
do NOT work either.
-Hyperzap
Your not compiling the lexer.cpp code.
Try
g++ -o main main.cpp lexer.cpp
as your compilation command.
PROBLEMS IN THE lexer.cpp
You probably want to include the lexer header in the lexer.cpp file
#include "lexer.h"
Also, you don't want to return an integer from void functions.
void Lexer::ConsoleWriteTokens(void){
for (int i = 0; i < TOK_list.size(); i++){
std::cout << "TOKEN! " << i;
}
//This function is void - it shouldn't return something
//return 0;
};
Finally, you have some problems withs this function
bool Lexer::AddLine(char * line){
token cool;
cool.data = line;
TOK_list.push_back(cool);
//what is this next line trying to achieve?
//string = line;
return true;
};
I'm not sure what you are trying to achieve with the line I commented out,
it doesn't seem to do anything and string isn't defined (did you mean std::string mystring = line;)
Finally, don't forget to uncomment the functions declaired in lexer.h that you are defining in lexer.cpp.
Include all the .cpp files in the command line, like this:
g++ -o main main.cpp lexer.cpp
When your project grows, it becomes wise to manage your project in some automatic way: Makefiles, ant, or some IDE-integrated project file.
Well g++ -o main main.cpp lexer.cpp sould do the trick. However I suggest making makefile files. When having a multiple amount of file they come in handy.
I would also suggest adding some optimization to your compilation like -O3 or -O2 (O is a letter o not zero digit!). The difference in execution speed is very noticable. Also if you are goig to make libraries out of your files, why not using --shared option that will create a liked library. I find making shared libraries very useful.