Excepții peste granița binară

Știu, această întrebare a fost întrebată de câteva ori, dar nu găsesc o soluție pentru problema mea.

Am următoarea situație:

   A
 /\
/  \
B <-- C
  • A is a shared library which contains the class EException
  • B and C link against A
  • C is a shared library as well
  • B dynamically loads C at runtime

La un moment dat C aruncă o instanță de EException :

void doSometing() {
    throw EException("test-message");
}

în B Aș dori să capturez această excepție:

try {
    doSomething();
} catch (const EException& ex) {
   //Not reached
} catch (...) {
   //Not reached
}

dar după cum se menționează în cod, niciuna dintre clauzele de captură nu este chemată. În schimb, firul, acest cod este executat, este avortat.

Am incercat urmatoarele lucruri:

  • Atributul de vizibilitate al EException este setat la "default" atunci când compilați A
  • Fișierul de antet EException conține doar declarații
  • Folosesc opțiunea linker -fvisibility = ascuns în A, B și C
  • Folosesc opțiunea linker -E în C

Folosind nm primesc pentru A :

0000000000066260 T EException::EException(QString const&)
0000000000066306 T EException::EException(EException const&)
00000000000661d0 T EException::EException() 
0000000000066260 T EException::EException(QString const&) 
0000000000066306 T EException::EException(EException const&) 
00000000000661d0 T EException::EException() 
00000000000664de T EException::~EException()
000000000006641e T EException::~EException() 
000000000006641e T EException::~EException() 
00000000000663b6 T EException::operator=(EException const&)
<...>
000000000028de40 V typeinfo for EException
000000000028dd80 V typeinfo for EException*
000000000007342b V typeinfo name for EException
0000000000072ab7 V typeinfo name for EException*
000000000028de00 V vtable for EException

pentru B :

U EException::EException(QString const&)
U EException::~EException()
<...>
0000000000726f60 V typeinfo for EException

și pentru C :

U EException::EException(QString const&)
U EException::~EException()
<...>
U typeinfo for EException

Dacă B utilizează propriul tip de informație de tip EException , atunci C utilizează codul A ? Cum aș rezolva asta?

Mediul meu:

  • gcc 4.6.3 pe x86_64-linux-gnu
  • utilizând Qt

Vă mulţumesc pentru ajutor!

0
Consultați de asemenea dinamic_cast, aruncați, typeid nu funcționează cu bibliotecile partajate din FAQ-ul GCC . Acesta vă spune să să evitați opțiunea linker -Bsymbolic code> -E linker. De asemenea, presupun că B /i> .
adăugat autor jww, sursa
Pe linia aruncării, se citează constructorul de copiat al EException . Nu există nici o eroare în constructorul de copiatoare și după terminarea firului se întrerupe.
adăugat autor Sämy, sursa
Acest cod (<) nu pare să presupună că eroarea dvs. nu este legată de clasa de excepție în sine (sau de o eroare în ctor). Ați încercat să o depanați și să vedeți ce se întâmplă pe acea linie de aruncare?
adăugat autor edA-qa mort-ora-y, sursa

5 răspunsuri

B utilizează propria definire a clasei EException V typeinfo pentru EException , în timp ce C pare să folosească una nerezolvată (U înseamnă că tipul este nedefinit în unitatea de traducere curentă și trebuie rezolvat de încărcător și linker dinamic ).

Verificați dacă B este încă o bibliotecă partajată și nu este legată în mod static cu A, dar dinamic, împiedicând C să găsească materialele lui A, deoarece nu pot să văd că B nu va lega același tip cu A. Aveți grijă de antetul dvs. ^ ^.

0
adăugat
Înțeleg prima dvs. parte. Dar B este aplicația mea principală și nici o bibliotecă partajată. Atât codurile B cât și C leagă A timpul de compilare. În măsura în care o înțeleg, ar trebui să împiedic B să utilizeze propriul typeinfo de tip EException , deoarece B și C se încarcă automat A în timpul rulării și ar trebui să utilizeze apoi tipul de informație A .
adăugat autor Sämy, sursa

I had similar problems with gcc < 4.5 with RTTI symbols used across shared library boundaries, but not with gcc 4.6. However, you might still find the following information useful.

As already mentioned, the vtable (containing an entry to the typeinfo object) for EException seems to be duplicated in some translation units which was definitely a problem with gcc < 4.5 (well, it is an issue of libsupc++, as far as I know, not merging the type_info objects). Anchoring the vtable of EException by defining a virtual out-of-line destructor (it must be the first virtual function declaration in the header) in A did the trick for me.

Postarea fișierului antet complet pentru EException ar putea fi, de asemenea, de ajutor.

0
adăugat

Puteți încerca să compilați A , B și C cu

Pagina man-ului GCC spune despre:

Treceți pavilionul -export-dinamic la link-ul ELF, pe obiectivele care îl susțin. Aceasta instruiește linkerul să adauge toate simbolurile, nu numai cele utilizate, în tabela simbolurilor dinamice. Această opțiune este necesară pentru unele utilizări ale " dlopen " sau pentru a permite obținerea de backtraces dintr-un program.

0
adăugat

Verifica pentru

-fvisibility = ascuns

în setările linkerului. Dacă este setat, schimbați-l

-fvisibility = default

0
adăugat

IMHO, asta nu are nimic de-a face cu steagurile compilatorului.

Declarați obiectul de excepție ca fiind extern și nu furnizați nicio implementare oriunde, cu excepția principalului dvs. binar.

Aceasta va obliga linkerul (linkerul dinamic BTW) să utilizeze singura implementare posibilă.

Nu se generează niciun tip de informație numai pe definiție externă.

0
adăugat