2 Stimmen

Warum bricht GLib bei rekursiven Protokollen ab?

Die meiste Zeit läuft mein GLib-Programm gut. Wenn jedoch Protokolle wie

** (Prozess: pid ): Nachricht (rekursiv): blah blah blah

erscheint, wird das Programm abgebrochen.

Laut GLib-Handbuch wird G_LOG_FLAG_RECURSION standardmäßig als fatal angesehen.

Aber ich kann einfach nicht verstehen, was "rekursive Nachrichten" bedeuten? Wann wird eine rekursive Meldung auftreten?

Danke

3voto

sarnold Punkte 99402

Beim Durchblättern von glib/gmessages.c habe ich den starken Eindruck, dass G_LOG_FLAG_RECURSION gesetzt ist, wenn g_logv() muss selbst einen Fehler protokollieren.

Wenn ein Versuch, Speicher zuzuweisen, fehlschlägt, wird das Programm versuchen, den Fehler bei der Speicherzuweisung zu protokollieren, und sich wahrscheinlich beenden. Wenn die Protokollierungsroutine versucht, Speicher zuzuweisen, um die Meldung zu protokollieren, wird sie wahrscheinlich scheitern. Die Protokollierungsroutinen behalten also im Auge, wie "tief" sie aufgerufen wurden, und wechseln die Speicherzuweisungsstrategie (sie weisen den Speicher auf dem Stack statt auf dem Heap zu), wenn es sich um einen rekursiven Protokollierungsaufruf handelt.

Immer wenn die Protokollierungsroutinen eine Fehlermeldung erhalten und den Fehler protokollieren wollen, muss etwas まったくもって Es macht also Sinn, zu versuchen, sich mit einem anderen Mechanismus anzumelden und dann zu beenden.

Sie sehen also wahrscheinlich nur ein weit entferntes Symptom des eigentlichen Problems. Sie könnten verwenden ltrace(1) um zu versuchen, das Problem zu erkennen, oder Sie könnten Kernspeicherauszüge aktivieren ( ulimit -c unlimited ) und versuchen Sie, die Aufrufkette zu finden, die das Programm zum Absturz bringt, indem Sie gdb's bt Befehl.

3voto

alexei Punkte 1761

Beachten Sie, dass ein rekursiver Aufruf einer g_*-Protokollierungsroutine auch vorkommen kann, wenn Sie einen benutzerdefinierten Handler registrieren (mit g_log_set_handler ) und dieser Handler (oder einer seiner Aufrufe) versucht, einen Fehler mit einem Aufruf einer g_*-Routine zu protokollieren.

Beachten Sie auch, dass glib beschlossen hat, dass jede Rekursion auch fatal sein sollte (selbst wenn sie nicht unendlich oder nur eine Ebene tief ist). Dies macht sicherlich Sinn für den in sarnolds Antwort beschriebenen Fall der Rekursion bei internem Versagen, könnte aber nicht offensichtlich sein, wenn man versucht, das Problem im Fall eines wiederkehrenden benutzerdefinierten Handlers zu beheben. Glib erkennt also Rekursion bereits beim ersten rekursiven Aufruf von g_*; es wird nicht einmal geprüft, ob der eigene Handler angehängt ist. Daher werden Sie niemals einen rekursiven Aufruf in Ihrem Handler sehen. All dies bedeutet, dass Bemühungen wie die sorgfältige Aufhebung der Registrierung des Handlers im Körper des Handlers (und ähnliche Dinge) vergeblich sind.

Sie müssen absolut sicher sein, dass nichts auf dem Aufrufstapel Ihres benutzerdefinierten Handlers jemals eine g_*-Routine aufruft (was schwierig werden kann, wenn Ihr Handler externen Code aufruft und Dinge wie den Versuch, die Protokollnachricht an ein entferntes Ziel zu liefern, verkompliziert).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X