[C++/Linux] Signals en exceptions catchen

Pagina: 1
Acties:

  • Radiant
  • Registratie: Juli 2003
  • Niet online

Radiant

Certified MS Bob Administrator

Topicstarter
Het volgende is mijn probleem:
In windows kan je access violations afvangen dmv een simpele try {} catch, in Linux kan dit echter niet, je krijgt gelijk een SIGSEGV en er wordt geen exception gethrowed. Je kan vanuit signal handlers ook geen exceptions throwen.
Voorbeeldje:
C++:
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

int main(void) {
  try {
    char *bla = 0;
    *bla = 1;
  }
  catch (...) {
    printf("Gevangen");
  }
}


Gevolg: Linux gooit een SIGSEGV, signal handler (als die er is) wordt gecalled, ipv dat er gewoon een exception wordt gethrowed.

Het probleem is namelijk dat ik bezig ben met het porten van een programma dat veel gebruik maakt van exceptions catchen voor vanalles. In windows gaat dat allemaal prima, exception gevangen, geeft netjes een melding en draait verder. Ookal vang ik in Linux het signal netjes af met een signal handler blijft hij na het afhandelen in dezelfde functie, dus blijven er segfaults komen.

Dus, nu is mijn vraag: hoe kan ik ervoor zorgen dat linux óf netjes een exception throwt ipv een signal óf hoe kan ik na het afhandelen van het signal een exception throwen ipv terug te keren naar de function die de exception veroorzaakte?

Verwijderd

Een segmentation fault is slecht en zou nooit moeten gebeuren.

  • Radiant
  • Registratie: Juli 2003
  • Niet online

Radiant

Certified MS Bob Administrator

Topicstarter
Verwijderd schreef op donderdag 24 februari 2005 @ 19:32:
Een segmentation fault is slecht en zou nooit moeten gebeuren.
Ik weet het, ik geef ook toe dat het programma aardig slecht gedesigned is op deze manier (komt niet van mij ;)), maar het moet nou eenmaal. Een null pointer geeft dus een segmentation fault en dat is niet een probleem dat gelijk je geheugen corrupt en kan veilig genegeerd worden, alleen moet je wel een exception kunnen gooien zodat je er niet mee door gaat.

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Microsoft zelf vindt het al ongewenst gedrag, en het gaat in de toekomst ook niet meer werken. Dan moet je ook op win32 een handler maken. Kortom, tijd om de oorzaak te fixen. Gooi zelf een std::exception als een pointer 0 is.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • igmar
  • Registratie: April 2000
  • Laatst online: 12-05 15:46

igmar

ISO20022

Radiant schreef op donderdag 24 februari 2005 @ 19:27:
Het volgende is mijn probleem:
In windows kan je access violations afvangen dmv een simpele try {} catch, in Linux kan dit echter niet, je krijgt gelijk een SIGSEGV en er wordt geen exception gethrowed.
En terecht. Excepties zijn iets van de c++ runtime, niet van het OS. sigsegv's afvangen en d'r ook nog wat mee doen is zowiezo not-done als je het mij vraagt.
Gevolg: Linux gooit een SIGSEGV, signal handler (als die er is) wordt gecalled, ipv dat er gewoon een exception wordt gethrowed.
de POSIX specs zeggen dat een sigsegv een signal stuurt. Excepties zijn een onderdeel van de C++ runtime.
Het probleem is namelijk dat ik bezig ben met het porten van een programma dat veel gebruik maakt van exceptions catchen voor vanalles. In windows gaat dat allemaal prima, exception gevangen, geeft netjes een melding en draait verder. Ookal vang ik in Linux het signal netjes af met een signal handler blijft hij na het afhandelen in dezelfde functie, dus blijven er segfaults komen.
Het gedrag van een programma na een sigsegv is undefined, en het is zeker niet de bedoeling dat het daarna verder draait. Vaak wordt de signalhandler gebruikt om een melding op het scherm te zetten, en een stackdump te genereren.
Dus, nu is mijn vraag: hoe kan ik ervoor zorgen dat linux óf netjes een exception throwt ipv een signal óf hoe kan ik na het afhandelen van het signal een exception throwen ipv terug te keren naar de function die de exception veroorzaakte?
Geen van beide zover ik weet. Je originele code is gebaseerd op een non-portable iets, en dat werkt gewoon op andere platformen anders.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:41

.oisyn

Moderator Devschuur®

Demotivational Speaker

igmar schreef op vrijdag 25 februari 2005 @ 10:22:
[...]


En terecht. Excepties zijn iets van de c++ runtime, niet van het OS. sigsegv's afvangen en d'r ook nog wat mee doen is zowiezo not-done als je het mij vraagt.
Beetje kort door de bocht, als je een stabiele applicatie wilt maken die bijv. gebruik maakt van plugins dan wil je die plugins guarden zodat ze niet het hele systeem omlaag halen. Of je wilt de boel nog even proberen weg te schrijven naar disk zodat je je dat iig niet kwijt bent.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • igmar
  • Registratie: April 2000
  • Laatst online: 12-05 15:46

igmar

ISO20022

.oisyn schreef op vrijdag 25 februari 2005 @ 10:49:
Beetje kort door de bocht, als je een stabiele applicatie wilt maken die bijv. gebruik maakt van plugins dan wil je die plugins guarden zodat ze niet het hele systeem omlaag halen. Of je wilt de boel nog even proberen weg te schrijven naar disk zodat je je dat iig niet kwijt bent.
Maar wel correct. Het is vrij simpel : Na een segfault is de huidige status van je proces undefined. Verder is een groot gedeelte van de libc functies niet threadsafe, en die mag je dus eigenlijk niet gebruiken in een signalhandler.

Dit probleem is oplosbaar door je bugs te fixen, niet door te gaan kloten met exceptions / signals.

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Threadsafe is niet het probleem. libc is niet reentrant. Ik heb een collega zien modderen met de gevolgen van een signalhandler die I/O deed (onvoorspelbare crashes eens elke zoveel uur). Het is dus meer dan een theoretisch probleem, laat het "eigenlijk" maar achterwege.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:41

.oisyn

Moderator Devschuur®

Demotivational Speaker

igmar schreef op vrijdag 25 februari 2005 @ 13:16:
Verder is een groot gedeelte van de libc functies niet threadsafe, en die mag je dus eigenlijk niet gebruiken in een signalhandler.
Wie verplicht je die functies te gebruiken dan?
Dit probleem is oplosbaar door je bugs te fixen, niet door te gaan kloten met exceptions / signals.
Klinkt leuk in theorie, in de praktijk kun je er feitelijk vanuit gaan dat er bugs in zitten, en is het voor de eindgebruiker een stuk fijner als ie niet al z'n werk kwijt is.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
1) Hoe wil je iets saven zonder libc?

2) Deze specifieke klasse bugs is relatief eenvoudig op te lossen - desnoods door alle relevante pointers te vervangen door smart pointers met een operator* die de throw-on-null implementeert. Werkt in Linux, Windows en waar je verder naar toe port.

[ Voor 9% gewijzigd door MSalters op 25-02-2005 17:38 ]

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:41

.oisyn

Moderator Devschuur®

Demotivational Speaker

MSalters schreef op vrijdag 25 februari 2005 @ 17:37:
1) Hoe wil je iets saven zonder libc?
CreateFile & friends, op Windows. Hoe het op linux werkt weet ik niet en kan me bovendien niets schelen ;)
2) Deze specifieke klasse bugs is relatief eenvoudig op te lossen - desnoods door alle relevante pointers te vervangen door smart pointers met een operator* die de throw-on-null implementeert. Werkt in Linux, Windows en waar je verder naar toe port.
Nogmaals, dat garandeert niet dat mijn app niet crasht als ik een plugin van iemand anders laadt. Bovendien garandeert het sowieso niet dat een app niet gaat crashen, er bestaan wel meer bugs dan segmentation faults dmv nullpointers :)

Leuk hoor, dat puristische geneuzel over dat je dat soort dingen eigenlijk niet zou moeten afvangen en dat je beter kan zorgen dat je gewoon geen bugs hebt, de praktijk is echter anders. Bugvrije apps bestaan niet maar ze moeten wel werkbaar zijn, en de eindgebruiker wordt bepaald niet blij als de app crasht en hij is z'n data kwijt alleen maar omdat je de fout "niet op hoort te vangen". 8)7

[ Voor 34% gewijzigd door .oisyn op 25-02-2005 17:48 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Radiant
  • Registratie: Juli 2003
  • Niet online

Radiant

Certified MS Bob Administrator

Topicstarter
Mja ik wil inderdaad gewoon alle events nog even doorlopen tot het eind en een save afmaken als die bezig was, en dan netjes afsluiten (of het object dat de segv veroorzaakte gewoon removen).
Dat smart pointer verhaal klinkt goed, maar om alle pointers te gaan vervangen is een enorme klus. En zoals .oisyn zegt, het hoeft natuurlijk niet altijd een null pointer te zijn, maar in mijn geval zijn het toch meestal null pointers. Ik zal er in ieder geval eens naar kijken.

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Mag je een exception gooien vanuit een handler? Of klopt je stack dan niet meer? Weet ik eigenlijk niet...

Oh en, als je een space shuttle maakt, dan kan je beter een segfault opvangen en afhandelen, door de module te restarten, dan simpelweg een vrij letterlijke bsod tevoorschijn toveren...(ook als je code bug vrij is, kan een memory link door brand verwoest worden, en zo een null pointer opleveren oid)

[ Voor 17% gewijzigd door Zoijar op 25-02-2005 20:45 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Nee. Waarheen zou die exception gaan? Erger, de signal handler is in dit verband een POSIX handler. POSIX en C++ zijn geen ideale combinatie. De POSIX groep is uit ISO gestapt, negeert C++ en is eigenlijk alleen een C groepje. Dat zie je bijvoorbeeld bij de voorstellen voor standaard C++ threadng en DLLs. Dat is geen POSIX pthreads of dlopen. Het POSIX idee van error handling is nog steeds errno.

Oh, en als je een space shuttle maakt, of iets anders op CMM nivo 5, dan heb je geen segfaults. Bewijsbaar. Einde discussie. Als er iets hardwarematigs faalt, dan heb je misschien wel een trap, maar daar ga je geen segfault of zoiets van maken. Alle onverwachte gebeurtenissen leidden tot een shutdown, en je vertrouwt op een watchdog die een failover doet naar hopelijk wel betrouwbare hardware. Zie bijvoorbeeld Ariane 5. Die software was niet niet geverifieerd (voor Ariane 5), faalde en er was simpelweg geen poging tot lokale error handling. De eerste controller faalde met een overflow, en error handling was simpelweg het gebruik van controller 2. Die faalde natuurlijk ook, waarop de hele raket werd opgeblazen. Het lijkt me duidelijk dat je dit soort ongecheckte code niet gebruikt voor bemande ruimtevaart.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Een segfault is toch een trap? Een trap is toch een fault die je op kan vangen en dan kan herstarten; je kernel segfault regelmatig, en laad dan de correcte pagina in, en probeert het opnieuw...meestal met succes. Je software bewijs is dat je pre en post condities kloppen, maar hardware kan altijd falen,daar kan je in software niets aan doen. Het blijft dus nuttig om dit soort dingen af te vangen. Tsja Ariane 5...het voorbeeld voor code reuse :P hehe... :(
Pagina: 1