Ich habe eine Anwendung, die ich verwende, um Segmentierungsfehler oder Strg-C abzufangen. Mit dem folgenden Code kann ich den Segmentierungsfehler abfangen, aber der Handler wird immer wieder aufgerufen. Wie kann ich sie aufhalten. Zu Ihrer Information, ich möchte meine Bewerbung nicht beenden. Ich kann mich nur darum kümmern, alle beschädigten Puffer freizugeben.
void mysighandler()
{
MyfreeBuffers(); /*related to my applciation*/
}
Hier wird der Handler für das Segmentierungsfehlersignal mehrmals aufgerufen, und offensichtlich gibt MyfreeBuffers() mir Fehler zum Freigeben von bereits freigegebenem Speicher. Ich möchte nur einmal freigeben, aber die Anwendung trotzdem nicht beenden.
Bitte helfen Sie.
Pavan Manjunath
Die Standardaktion für Dinge wie SIGSEGV ist, Ihren Prozess zu beenden, aber da Sie einen Handler dafür installiert haben, ruft er Ihren Handler auf und überschreibt das Standardverhalten. Das Problem ist jedoch, dass die Segfaulting-Anweisung möglicherweise wiederholt wird, nachdem Ihr Handler fertig ist, und wenn Sie keine Maßnahmen ergriffen haben, um den ersten Segmentfehler zu beheben, wird die wiederholte Anweisung erneut fehlerhaft und es geht weiter und weiter.
Suchen Sie also zuerst die Anweisung, die daraus resultierte SIGSEGV und versuchen Sie es zu beheben (Sie können so etwas nennen wie backtrace() im Handler und sehen Sie selbst, was schief gelaufen ist)
Außerdem sagt der POSIX-Standard, dass
Das Verhalten eines Prozesses ist undefiniert, nachdem er normal von einer signalfangenden Funktion für a zurückkehrt [XSI] SIGBUS-, SIGFPE-, SIGILL- oder SIGSEGV-Signal, das nicht von kill() generiert wurde, [RTS] sigqueue() oder raise().
Das Beste, was Sie tun können, ist also, Ihren Segfault überhaupt erst zu beheben. Der Handler für segfault soll die zugrunde liegende Fehlerbedingung nicht umgehen
Der beste Vorschlag wäre also Nicht fangen SIGSEGV. Lassen Sie es Kern entleeren. Analysiere den Kern. Korrigieren Sie die ungültige Speicherreferenz und los geht’s!
Das Abfangen von Segmentierungsverletzungen ist manchmal nützlich, da der Programmierer dann in der Lage ist, zu melden, wo der Fehler in stderr, einer Protokolldatei oder einem entfernten Server aufgetreten ist, bevor er das Programm zum Absturz bringt. Ich stelle mir das so vor: Der Programmierer behält globale Variablen, speichert den Namen der aktuell verarbeiteten Funktion (anderes Zeug für Multi-Thread-Programme) und die aktuelle Zeilennummer (die Zeilennummer-Variablen-Update-Anweisungen (auf Kosten der Rechenleistung) wären automatisch in jede Zeile eingefügt). Wenn ein Segfault auftritt, kann der Programmierer „SIGSEGV in tois()@main.c:492“ an das Protokoll melden.
– sij
13. Oktober 2020 um 5:32 Uhr
Champignac
Ich stimme der Aussage überhaupt nicht zu “Fang nicht den SIGSEGV”.
Das ist eine ziemlich gute Praxis, damit umzugehen unerwartet Bedingungen. Und das ist viel sauberer zu bewältigen NULL Zeiger (wie durch Malloc-Ausfälle gegeben) mit zugehörigem Signalmechanismus setjmp/longjmpals die Verwaltung von Fehlerbedingungen über Ihren gesamten Code zu verteilen.
Beachten Sie jedoch, dass, wenn Sie ”sigaction” verwenden, on SEGVdarfst du nicht vergessen zu sagen SA_NODEFER in sa_flags – oder einen anderen Weg finden, mit der Tatsache umzugehen SEGV wird Ihren Handler nur einmal auslösen.
Dies ist eine gute Lösung. Das „abstürzen lassen und dann Core-Dump analysieren“ gefiel mir nicht besonders.
– dturvene
3. November 2017 um 21:10 Uhr
Beachten Sie, dass Sie tun Fehlerüberprüfungen müssen immer noch mit diesem Stil verbreitet werden, aber auf andere Weise. Hier muss der aufrufende Code wissen, wie er im Fehlerfall alle Ressourcen für den gesamten aufgerufenen Code bereinigen kann. Im traditionellen Stil prüft jeder Codeabschnitt auf Fehler und bereinigt dann nur seine eigenen Ressourcen. IMO ist letzteres vorzuziehen, da jedes Stück weniger über die anderen wissen muss.
– gntskn
20. Juli 2020 um 16:49 Uhr
Super nützliche Antwort, danke. Siehe auch Abschnitt „Normsignale“. hier… Sieht so aus, als müsste ich eine Reihe von Signalen manuell angeben, wenn ich alles erfassen möchte …
– Andreas
10. November 2020 um 5:27 Uhr
Okay, wenn Sie dies tun, können Sie verwenden strsignal um eine Zeichenfolgendarstellung des Signals zu erhalten, und dann können Sie diese Zeichenfolge und die ausdrucken/protokollieren sigint selbst generisch. Dann können Sie diesen Code für eine ganze Reihe von Signalen wiederverwenden, mit nur 1 handler() Funktion!
– Andreas
10. November 2020 um 5:43 Uhr
Wenn die SIGSEGV feuert wieder, die offensichtliche Schlussfolgerung ist, dass der Anruf an MyfreeBuffers(); hat nicht das zugrunde liegende Problem behoben (und wenn diese Funktion wirklich nur funktioniert free() etwas zugewiesener Speicher, ich bin mir nicht sicher, warum Sie das glauben würden).
Grob, a SIGSEGV wird ausgelöst, wenn versucht wird, auf eine unzugängliche Speicheradresse zuzugreifen. Wenn Sie die Anwendung nicht beenden möchten, müssen Sie entweder diese Speicheradresse zugänglich machen oder den Ausführungspfad mit ändern longjmp().
Sie sollten nicht versuchen, danach fortzufahren SIG_SEGV. Es bedeutet im Grunde, dass die Umgebung Ihrer Anwendung in irgendeiner Weise beschädigt ist. Es könnte sein, dass Sie gerade einen Nullzeiger dereferenziert haben, oder es könnte sein, dass ein Fehler dazu geführt hat, dass Ihr Programm seinen Stack oder den Heap oder eine Zeigervariable beschädigt hat, Sie wissen es einfach nicht. Das nur sicher ist, das Programm zu beenden.
Es ist vollkommen legitim, mit Control-C umzugehen. Viele Anwendungen tun dies, aber Sie müssen wirklich genau aufpassen, was Sie in Ihrem Signal-Handler tun. Sie können keine Funktion aufrufen, die nicht wiedereintrittsfähig ist. Das heißt also, wenn Ihr MyFreeBuffers() ruft die stdlib auf free() Funktion, Sie sind wahrscheinlich geschraubt. Wenn der Benutzer Strg-C drückt, während sich das Programm in der Mitte befindet malloc() oder free() und daher werden Sie nach der Hälfte der Bearbeitung der Datenstrukturen, die sie zum Verfolgen von Heap-Zuweisungen verwenden, mit ziemlicher Sicherheit den Heap beschädigen, wenn Sie anrufen malloc() oder free() im Signalhandler.
Das einzig Sichere, was Sie in einem Signal-Handler tun können, ist das Setzen eines Flags, das besagt, dass Sie das Signal empfangen haben. Ihre App kann dann das Flag in Intervallen abfragen, um zu entscheiden, ob sie eine Aktion ausführen muss.
Nun, Sie könnten eine Zustandsvariable setzen und nur Speicher freigeben, wenn sie nicht gesetzt ist. Der Signalhandler wird jedes Mal aufgerufen, Sie können das AFAIK nicht kontrollieren.
neueLogik
Ich sehe einen Fall für die Wiederherstellung nach einem SIG_SEGV. Wenn Sie Ereignisse in einer Schleife behandeln und eines dieser Ereignisse eine Segmentierungsverletzung verursacht, möchten Sie nur dieses Ereignis überspringen und die Verarbeitung der verbleibenden Ereignisse fortsetzen. In meinen Augen ähnelt SIG_SEGV der NullPointerException in Java. Ja, der Status wird nach beiden inkonsistent und unbekannt sein, aber in einigen Fällen möchten Sie die Situation handhaben und weitermachen. Zum Beispiel würden Sie beim Algo-Handel die Ausführung einer Order anhalten und einem Händler erlauben, manuell zu übernehmen, ohne das gesamte System zum Absturz zu bringen und alle anderen Orders zu ruinieren.
Gemeinschaft
Sieht so aus, als könnte zumindest unter Linux der Trick mit der Option -fnon-call-exceptions die Lösung sein. Es bietet die Möglichkeit, das Signal in eine allgemeine C++-Ausnahme zu konvertieren und auf allgemeine Weise zu behandeln. Schauen Sie sich linux3/gcc46: “-fnon-call-exceptions” an, welche Signale sind Trapping-Anweisungen? zum Beispiel.
14032800cookie-checkBehandlung von Segmentierungsfehlernyes