Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > de.comp.lang.iso-c++ > #1956 > unrolled thread

Exception mit Durchfall?

Started byEdzard Egberts <news@edzeg.net>
First post2016-11-18 14:23 +0100
Last post2016-11-28 17:49 +0100
Articles 8 — 2 participants

Back to article view | Back to de.comp.lang.iso-c++


Contents

  Exception mit Durchfall? Edzard Egberts <news@edzeg.net> - 2016-11-18 14:23 +0100
    Re: Exception mit Durchfall? Stefan Reuther <stefan.news@arcor.de> - 2016-11-20 11:18 +0100
      Re: Exception mit Durchfall? Edzard Egberts <news@edzeg.net> - 2016-11-23 13:11 +0100
        Re: Exception mit Durchfall? Stefan Reuther <stefan.news@arcor.de> - 2016-11-24 19:15 +0100
          Re: Exception mit Durchfall? Edzard Egberts <news@edzeg.net> - 2016-11-25 08:11 +0100
            Re: Exception mit Durchfall? Stefan Reuther <stefan.news@arcor.de> - 2016-11-25 18:07 +0100
              Re: Exception mit Durchfall? Edzard Egberts <news@edzeg.net> - 2016-11-28 08:21 +0100
                Re: Exception mit Durchfall? Stefan Reuther <stefan.news@arcor.de> - 2016-11-28 17:49 +0100

#1956 — Exception mit Durchfall?

FromEdzard Egberts <news@edzeg.net>
Date2016-11-18 14:23 +0100
SubjectException mit Durchfall?
Message-ID<o0mvct$30v$1@news2.open-news-network.org>
Ich verwende die OpenCV und bei Out-Of-Memory wirft die eine
cv::Exception (die ist von std::exception abgeleitet), zur Sicherheit
möchte ich aber alles fangen. Das sieht so aus:

try 		{ Update_Results(); }
catch (...)	// alternativ "catch (cv::Exception& e)" geht auch nicht
{
	Message_Error();
	Clear_Mem();
}

Funktioniert nicht - im Debugfenster sehe ich zwar eine Ausgabe, dass
die OpenCV eine Exception geworfen hat, die wird aber nicht vollständig
abgefangen:

Unter Linux beendet das Programm kommentarlos, unter Windows erscheint
die Message_Error() aus dem catch-Zweig und ein Fenster "Microsoft
Visual C++ Runtime Library" "This application has requested the runtime
to terminate in an unusual way". Das erscheint mir widersprüchlich.

Wenn ich statt dessen so etwas mache (Test geht auch mit std::nothrow):

char* pMem= nullptr;
try { pMem= char[100*1024*1240]; }
catch (...)
{
	Message_Error();
	Clear_Mem();
	pMem= nullptr;
}
delete[] pMem;
Update_Results();

Läuft die Sache durch und lässt sich auch mehrfach auslösen.

Lokal funktioniert die Exception also. Was habe ich da nicht verstanden,
warum wird die nicht aus der OpenCV durchgereicht und abgefangen,
sondern beendet die Laufzeitumgebung?

[toc] | [next] | [standalone]


#1958

FromStefan Reuther <stefan.news@arcor.de>
Date2016-11-20 11:18 +0100
Message-ID<o0s0q8.2so.1@stefan.msgid.phost.de>
In reply to#1956
Am 18.11.2016 um 14:23 schrieb Edzard Egberts:
> Funktioniert nicht - im Debugfenster sehe ich zwar eine Ausgabe, dass
> die OpenCV eine Exception geworfen hat, die wird aber nicht vollständig
> abgefangen:
> 
> Unter Linux beendet das Programm kommentarlos, unter Windows erscheint
> die Message_Error() aus dem catch-Zweig und ein Fenster "Microsoft
> Visual C++ Runtime Library" "This application has requested the runtime
> to terminate in an unusual way". Das erscheint mir widersprüchlich.

Das klingt, als ob irgendwo mittendrin 'abort', wahrscheinlich ausgelöst
von 'terminate', aufgerufen wird. Dass das unter Linux kommentarlos
wegfliegt, könnte an restriktiv eingestellten ulimits liegen.

Hast du schon mal einen Debugger drangehängt? Wenn der dich (unter
Linux) nicht direkt mit der Nase draufstößt ("Programm von SIGABRT
angehalten, hier ist der Backtrace"), setze einen Breakpoint auf
__cxa_throw, das ist die Library-Funktion fürs Exception-Werfen.

Blind raten würde ich, dass da irgendwo ein Destruktor rumhängt, der
wieder eine Exception wirft.


  Stefan

[toc] | [prev] | [next] | [standalone]


#1971

FromEdzard Egberts <news@edzeg.net>
Date2016-11-23 13:11 +0100
Message-ID<o14123$9bf$1@news2.open-news-network.org>
In reply to#1958
Stefan Reuther wrote:
> Am 18.11.2016 um 14:23 schrieb Edzard Egberts:
>> Funktioniert nicht - im Debugfenster sehe ich zwar eine Ausgabe, dass
>> die OpenCV eine Exception geworfen hat, die wird aber nicht vollständig
>> abgefangen:
>>
>> Unter Linux beendet das Programm kommentarlos, unter Windows erscheint
>> die Message_Error() aus dem catch-Zweig und ein Fenster "Microsoft
>> Visual C++ Runtime Library" "This application has requested the runtime
>> to terminate in an unusual way". Das erscheint mir widersprüchlich.
> 
> Das klingt, als ob irgendwo mittendrin 'abort', wahrscheinlich ausgelöst
> von 'terminate', aufgerufen wird.

Dazu habe ich nichts im Quelltext gefunden. Ansonsten kann ich also zu
Recht davon ausgehen, dass eine Exception nicht irgendwo den Ausgang
nimmt, sondern immer durchgereicht wird? Ich habe das gesamte Programm
in einer try-catch(...), aber da ist noch nie ein Absturz angekommen.

> angehalten, hier ist der Backtrace"), setze einen Breakpoint auf
> __cxa_throw, das ist die Library-Funktion fürs Exception-Werfen.

Aha, funktioniert blendend, fängt unter Linux aber trotzdem nicht das
Programmende ab. IMHO bedeutet das, der Prozess wurde von außen beendet.
Mein Test fängt das wahrscheinlich ab, da damit noch ein wenig Speicher
übrig ist.

> Blind raten würde ich, dass da irgendwo ein Destruktor rumhängt, der
> wieder eine Exception wirft.

Wäre das ein neuer Pfad, der nicht abgefangen wird?

[toc] | [prev] | [next] | [standalone]


#1972

FromStefan Reuther <stefan.news@arcor.de>
Date2016-11-24 19:15 +0100
Message-ID<o17e8r.4ng.1@stefan.msgid.phost.de>
In reply to#1971
Am 23.11.2016 um 13:11 schrieb Edzard Egberts:
> Stefan Reuther wrote:
>> Am 18.11.2016 um 14:23 schrieb Edzard Egberts:
>>> Unter Linux beendet das Programm kommentarlos, unter Windows erscheint
>>> die Message_Error() aus dem catch-Zweig und ein Fenster "Microsoft
>>> Visual C++ Runtime Library" "This application has requested the runtime
>>> to terminate in an unusual way". Das erscheint mir widersprüchlich.
>>
>> Das klingt, als ob irgendwo mittendrin 'abort', wahrscheinlich ausgelöst
>> von 'terminate', aufgerufen wird.
> 
> Dazu habe ich nichts im Quelltext gefunden.

Natürlich nicht, das macht ja auch die Runtime.

> Ansonsten kann ich also zu Recht davon ausgehen, dass eine Exception
> nicht irgendwo den Ausgang nimmt, sondern immer durchgereicht wird?
> Ich habe das gesamte Programm in einer try-catch(...), aber da ist
> noch nie ein Absturz angekommen.

try-catch ist kein magisches "du kommst hier nicht raus außer an mir
vorbei". Neben exit(), assert() o.ä. sowie den Syscalls der Wahl (z.B.
kill()) ist da eben noch die Möglichkeit, dass während des Aufräumens
auf dem Weg zum catch eine weitere Exception geworfen wird. Und dann ist
halt Ende.

>> angehalten, hier ist der Backtrace"), setze einen Breakpoint auf
>> __cxa_throw, das ist die Library-Funktion fürs Exception-Werfen.
> 
> Aha, funktioniert blendend, fängt unter Linux aber trotzdem nicht das
> Programmende ab. IMHO bedeutet das, der Prozess wurde von außen beendet.
> Mein Test fängt das wahrscheinlich ab, da damit noch ein wenig Speicher
> übrig ist.

Was heißt denn "funktioniert blendend" praktisch? Ich hätte jetzt nicht
erwarten, dass das Setzen des Breakpoints scheitert :-)

>> Blind raten würde ich, dass da irgendwo ein Destruktor rumhängt, der
>> wieder eine Exception wirft.
> 
> Wäre das ein neuer Pfad, der nicht abgefangen wird?

Das ist ein Pfad, der nicht abgefangen werden kann. Das Programm kann ja
schlecht sagen "whoops, das Zerstören dieses Objektes beim Verlassen der
Funktion schlug fehl. Bauen wir das Objekt halt wieder hin und bleiben
in der Funktion". Und deswegen wird da das Programm beendet (terminate,
abort).


  Stefan

[toc] | [prev] | [next] | [standalone]


#1973

FromEdzard Egberts <news@edzeg.net>
Date2016-11-25 08:11 +0100
Message-ID<o18o8d$4c6$1@news2.open-news-network.org>
In reply to#1972
Stefan Reuther wrote:
> Am 23.11.2016 um 13:11 schrieb Edzard Egberts:
>> Ansonsten kann ich also zu Recht davon ausgehen, dass eine Exception
>> nicht irgendwo den Ausgang nimmt, sondern immer durchgereicht wird?
>> Ich habe das gesamte Programm in einer try-catch(...), aber da ist
>> noch nie ein Absturz angekommen.
> 
> try-catch ist kein magisches "du kommst hier nicht raus außer an mir
> vorbei". Neben exit(), assert() o.ä. sowie den Syscalls der Wahl (z.B.
> kill()) ist da eben noch die Möglichkeit, dass während des Aufräumens
> auf dem Weg zum catch eine weitere Exception geworfen wird. Und dann ist
> halt Ende.

Na ja, das ist dann wohl der Punkt, wo lokale Fehlerbearbeitung den
Exceptions überlegen ist.

>>> angehalten, hier ist der Backtrace"), setze einen Breakpoint auf
>>> __cxa_throw, das ist die Library-Funktion fürs Exception-Werfen.
>>
>> Aha, funktioniert blendend, fängt unter Linux aber trotzdem nicht das
>> Programmende ab.
> 
> Was heißt denn "funktioniert blendend" praktisch?

Dass da Exceptions aufschlagen, die ich vorher nicht gesehen habe, weil
die korrekt bearbeitet wurden.

> Ich hätte jetzt nicht
> erwarten, dass das Setzen des Breakpoints scheitert :-)

Hast Du eine Ahnung, das mit der .gdbinit war geradezu ein Geistesblitz,
ich habe nicht den leisesten Schimmer, in welchem Code __cxa_throw zu
finden ist. ;o)

>> Wäre das ein neuer Pfad, der nicht abgefangen wird?
> 
> Das ist ein Pfad, der nicht abgefangen werden kann. Das Programm kann ja
> schlecht sagen "whoops, das Zerstören dieses Objektes beim Verlassen der
> Funktion schlug fehl.

Einfach abkacken ist aber auch nicht die feine Art, zumindest der
Debugger sollte da anhalten. Na ja, dann muss ich das Problem wohl
irgendwie anders lösen und die Exception mit einer anderen Art der
Speicherüberwachung von vorneherein vermeiden.

[toc] | [prev] | [next] | [standalone]


#1974

FromStefan Reuther <stefan.news@arcor.de>
Date2016-11-25 18:07 +0100
Message-ID<o19ulo.5ek.1@stefan.msgid.phost.de>
In reply to#1973
Am 25.11.2016 um 08:11 schrieb Edzard Egberts:
> Stefan Reuther wrote:
>> Am 23.11.2016 um 13:11 schrieb Edzard Egberts:
>>> Ansonsten kann ich also zu Recht davon ausgehen, dass eine Exception
>>> nicht irgendwo den Ausgang nimmt, sondern immer durchgereicht wird?
>>> Ich habe das gesamte Programm in einer try-catch(...), aber da ist
>>> noch nie ein Absturz angekommen.
>>
>> try-catch ist kein magisches "du kommst hier nicht raus außer an mir
>> vorbei". Neben exit(), assert() o.ä. sowie den Syscalls der Wahl (z.B.
>> kill()) ist da eben noch die Möglichkeit, dass während des Aufräumens
>> auf dem Weg zum catch eine weitere Exception geworfen wird. Und dann ist
>> halt Ende.
> 
> Na ja, das ist dann wohl der Punkt, wo lokale Fehlerbearbeitung den
> Exceptions überlegen ist.

Nein, das ist der Punkt, wo man prüfen sollte, ob man nicht doch im
Destruktor auf Exceptions verzichten sollte. Gefährlicher Code steht da
ja meist aus Bequemlichkeit, z.B. der automatische flush eines Streams.
Und wenn's doch nicht ohne geht, dann im Destruktor wenigstens ein
try/catch drum.

>>> Wäre das ein neuer Pfad, der nicht abgefangen wird?
>>
>> Das ist ein Pfad, der nicht abgefangen werden kann. Das Programm kann ja
>> schlecht sagen "whoops, das Zerstören dieses Objektes beim Verlassen der
>> Funktion schlug fehl.
> 
> Einfach abkacken ist aber auch nicht die feine Art, zumindest der
> Debugger sollte da anhalten.

Windows weiß ich nicht, aber unixoide Debugger tun das: terminate() ruft
abort() auf, abort() generiert SIGABRT, und das Signal fängt der Debugger.

Cygwin:
$ cat x.cpp
class foo {
public:
  ~foo() { throw "bar"; }
};

int main()
{
  foo f;
}
$ g++ x.cpp
$ gdb ./a.exe
GNU gdb (GDB) 7.8
[...]
Reading symbols from ./a.exe...done.
(gdb) r
Starting program: /cygdrive/e/home/a.exe
[New Thread 2724.0x1454]
[New Thread 2724.0xa30]
[New Thread 2724.0x14ac]
[New Thread 2724.0x518]
terminate called after throwing an instance of 'char const*'

Program received signal SIGABRT, Aborted.
0x0028dd58 in ?? ()
(gdb) bt
#0  0x0028dd58 in ?? ()
#1  0x761e1194 in WaitForSingleObjectEx () from /cygdrive/c/Windows/syswow64/kernel32.dll
#2  0x761e1148 in WaitForSingleObject () from /cygdrive/c/Windows/syswow64/kernel32.dll
#3  0x610f0500 in sig_send(_pinfo*, siginfo_t&, _cygtls*) () from /usr/bin/cygwin1.dll
#4  0x610ed41c in _pinfo::kill(siginfo_t&) () from /usr/bin/cygwin1.dll
#5  0x610ed928 in kill0(int, siginfo_t&) () from /usr/bin/cygwin1.dll
#6  0x610edb02 in raise () from /usr/bin/cygwin1.dll
#7  0x610eddc3 in abort () from /usr/bin/cygwin1.dll
#8  0x5ff8470a in cygstdc++-6!_ZN9__gnu_cxx27__verbose_terminate_handlerEv () from /usr/bin/cygstdc++-6.dll
#9  0x5ff7dcd9 in cygstdc++-6!_ZN10__cxxabiv111__terminateEPFvvE () from /usr/bin/cygstdc++-6.dll
#10 0x5ffd8a00 in cygstdc++-6!_ZSt9terminatev () from /usr/bin/cygstdc++-6.dll
#11 0x5ffde822 in cygstdc++-6!.cxa_throw () from /usr/bin/cygstdc++-6.dll
#12 0x00401790 in foo::~foo() ()
#13 0x004011ba in main ()
(gdb)


  Stefan

[toc] | [prev] | [next] | [standalone]


#1975

FromEdzard Egberts <news@edzeg.net>
Date2016-11-28 08:21 +0100
Message-ID<o1glul$m01$1@news2.open-news-network.org>
In reply to#1974
Stefan Reuther wrote:
> Am 25.11.2016 um 08:11 schrieb Edzard Egberts:
>> Na ja, das ist dann wohl der Punkt, wo lokale Fehlerbearbeitung den
>> Exceptions überlegen ist.
> 
> Nein, das ist der Punkt, wo man prüfen sollte, ob man nicht doch im
> Destruktor auf Exceptions verzichten sollte. Gefährlicher Code steht da
> ja meist aus Bequemlichkeit, z.B. der automatische flush eines Streams.
> Und wenn's doch nicht ohne geht, dann im Destruktor wenigstens ein
> try/catch drum.

Okay, man kann zur lokalen Fehlerbearbeitung auch Exceptions nutzen. ;o)

>> Einfach abkacken ist aber auch nicht die feine Art, zumindest der
>> Debugger sollte da anhalten.
> 
> Windows weiß ich nicht, aber unixoide Debugger tun das:

In meinem Fall nicht, deshalb dieser Thread. Ich glaube aber, ich weiß
inzwischen warum: Aus der Ubuntu-Doc: "Hat man allerdings keinen Swap
und das RAM läuft voll, so beendet der Linux-Kernel nach eigenem
Ermessen Programme, um RAM frei zu machen.". Das passiert scheinbar
auch, wenn man Swap hat, der aber ebenfalls voll ist. Das Programm wird
also tatsächlich von außen beendet, da bin ich mir jetzt ziemlich sicher.

Sorry, war also die falsche Gruppe. Allerdings war mir die Sache mit dem
Destruktor vorher nicht so bewusst, noch einmal ganz langsam für mich:
Wenn während der Bearbeitung ("Abwicklung") einer Exception eine weitere
Exception auftritt, kann die nicht mehr abgefangen werden und beendet
das Programm. Das kann ich mir so merken?

Das Memory-Leak habe ich auch gefunden - die OpenCV hat Löcher wie ein
Sieb! ;o(

[toc] | [prev] | [next] | [standalone]


#1976

FromStefan Reuther <stefan.news@arcor.de>
Date2016-11-28 17:49 +0100
Message-ID<o1hqne.44s.1@stefan.msgid.phost.de>
In reply to#1975
Am 28.11.2016 um 08:21 schrieb Edzard Egberts:
> Sorry, war also die falsche Gruppe. Allerdings war mir die Sache mit dem
> Destruktor vorher nicht so bewusst, noch einmal ganz langsam für mich:
> Wenn während der Bearbeitung ("Abwicklung") einer Exception eine weitere
> Exception auftritt, kann die nicht mehr abgefangen werden und beendet
> das Programm. Das kann ich mir so merken?

So wie du es formuliert hast, stimmt es nicht, aber vielleicht meinst du
das richtige. Als Merksatz vielleicht formuliert: "es dürfen niemals
zwei Exceptions gleichzeitig unterwegs sein." Und als noch einfacheren
Merksatz: "sorge dafür, dass deine Destruktoren niemals direkt oder
indirekt Exceptions werfen".

Beispiel:
   #include <iostream>
   void foo()
     { throw "ho"; }
   class X {
   public:
     ~X() { foo(); }
   };
   int main() {
     try  {
       X x;
       throw "hi";
     }
     catch (const char* p) {
       std::cout << p << "\n";
     }
   }
Mit der Zeile 'throw "hi"' wirfst du eine Exception. Auf dem Stack liegt
noch das 'X'-Objekt, also wird die Exception kurz gefangen und der
Destruktor aufgerufen. Der Destruktor wirft dummerweise eine Exception.
Wenn der Compiler nun die Exception weiterwerfen will, hat er auf einmal
zwei davon ("hi" und "ho") --> boom.

Ändern wir den Destruktor '~X' in
    ~X() {
      try { foo(); }
      catch (...) { }
    }
wird die "ho"-Exception durch den catch-Block final "behandelt" und nach
dem Verlassen des Destruktors ist wieder nur eine Exception unterwegs.

Aber "während der Bearbeitung der Exception" war auch mal kurz eine
zweite Exception aktiv.

Alternativ vielleicht hier schauen:
http://stackoverflow.com/questions/3318887/what-happens-when-an-exception-is-thrown-while-unwinding-the-stack-from-another


  Stefan

[toc] | [prev] | [standalone]


Back to top | Article view | de.comp.lang.iso-c++


csiph-web