exceptions not caught from shared libraries loaded with dlopen

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I have a real serious problem with g++ version 4.2.1 and lower.
When I compile the attached code, the exception from the last loaded shared library will not be caught correctly.

So basically if I have a shared library that has a function throwing a custom exception and two more shared libraries are linked against it and loaded in an application with dlopen, only the exception thrown in the first loaded library will be caught correctly. The exception from the library loaded second will not be caught with correct type.

I attached a simple testcase that shows this behaviour.


The output is:
Wrapper: caught exception
ERROR: caught unknown exception, expected type Exception


The expected output is:
Wrapper: caught exception
Wrapper: caught exception


Is it a bug in g++ or do I miss something really important? I searched the web but only found a problem related to a similar problem when throwing an exception from one shared library. This has been resolved by adding the "-Wl,-E" option to the compiler and does not fix my problem.

Thanks,
Jan


--- attachement ------

[classes.h]
#ifndef _classes_h_
#define _classes_h_

class ClassA {
	public:
		ClassA() {}
		virtual ~ClassA() {}

		virtual const char* className() { return "ClassA"; }
};

class ClassB : public ClassA {
	public:
		ClassB() {}
		virtual ~ClassB() {}

		virtual const char* className() { return "ClassB"; }
};


ClassA* testClass();
ClassA* testAnotherClass();

#endif

[exception.h]
#ifndef _exception_h_
#define _exception_h_

#include <exception>

class MyException {
};

typedef MyException Exception;
//typedef std::exception Exception;

typedef void* (*Func)();

void testException() throw(Exception);
void testAnotherException() throw(Exception);

#endif

[libtest_a.cpp]
#include <stdio.h>
#include "exception.h"
#include "classes.h"

extern "C" {

void* wrapTestException() {
  try {
    testException();
  }
  catch(Exception &_e) {
    printf("Wrapper: caught exception\n");
  }
  catch(...) {
    printf("ERROR: caught unknown exception, expected type Exception\n");
  }

  return NULL;
}


void* wrapTestClass() {
    return testClass();
}

}

[libtest_b.cpp]
#include <stdio.h>
#include "exception.h"
#include "classes.h"

extern "C" {

void* wrapTestAnotherException() {
  try {
    testAnotherException();
  }
  catch(Exception &_e) {
    printf("Wrapper: caught another exception\n");
  }
  catch(...) {
    printf("ERROR: caught unknown exception, expected type Exception\n");
  }

  return NULL;
}

void* wrapTestAnotherClass() {
  return testAnotherClass();
}

}

[libutils.cpp]
#include "exception.h"
#include "classes.h"

void testException() throw(Exception) {
	throw Exception();
}

void testAnotherException() throw(Exception) {
	throw Exception();
}

ClassA* testClass() {
	return new ClassB();
}

ClassA* testAnotherClass() {
	return new ClassB();
}


[main.cpp]
#include <iostream>
#include <dlfcn.h>
#include "exception.h"
#include "classes.h"

using namespace std;

Func initFunc(const char *path, const char *funcName) {
    void *handle;
    Func proc = NULL;
    if (!(handle=dlopen(path ,RTLD_LAZY))) {
            cerr << "Can't open " << path << endl;
            return NULL; 
    }

    if (!(proc=(Func)dlsym(handle,funcName))) {
            cerr << "Can't bind '" << funcName << "'" << endl;
            return NULL;
    }

    return proc;
}


void testFunc(const char *path, const char *funcName) {
    Func func = initFunc(path, funcName);
    if ( func ) {
      ClassA* c = (ClassA*)func();
      if ( c ) {
        cout << c->className() << endl;
	if ( dynamic_cast<ClassB*>(c) )
	  cout << "dynamic_cast<ClassB*> passed" << endl;
	else
	  cout << "dynamic_cast<ClassB*> failed" << endl;
      }
    }
}


int main(int, char **) {
    testFunc("libtest_a.so", "wrapTestException");
    //testFunc("libtest_a.so", "wrapTestClass");
    
    testFunc("libtest_b.so", "wrapTestAnotherException");
    //testFunc("libtest_b.so", "wrapTestAnotherClass");
}

[Makefile]
GPP=g++
GXX_OPTS=-Wall -v -save-temps

all: libutils.so libtest_a.so libtest_b.so testcase

testcase: main.cpp libutils.so libtest_a.so libtest_b.so
	$(GPP) $(GXX_OPTS) -ldl -Wl,-E -o testcase main.cpp

libutils.so: libutils.cpp exception.h classes.h
	$(GPP) $(GXX_OPTS) -fPIC -shared -Wl,-soname,libutils.so -o libutils.so libutils.cpp

libtest_a.so: libtest_a.cpp libutils.so
	$(GPP) $(GXX_OPTS) -fPIC -shared -Wl,-soname,libtest_a.so -L. -o libtest_a.so libtest_a.cpp -lutils

libtest_b.so: libtest_b.cpp libutils.so
	$(GPP) $(GXX_OPTS) -fPIC -shared -Wl,-soname,libtest_b.so -L. -o libtest_b.so libtest_b.cpp -lutils

clean:
	rm -f *.o lib*.so core* a.out testcase

-- 
GMX FreeMail: 1 GB Postfach, 5 E-Mail-Adressen, 10 Free SMS.
Alle Infos und kostenlose Anmeldung: http://www.gmx.net/de/go/freemail

[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux