longjmp() aus signal-handler
Ich bin mit dem folgenden code, um zu versuchen, zum Lesen einer Eingabe von Benutzer und-timeout und beendet, wenn mehr als 5 Sekunden vergehen. Dies wird erreicht durch eine Kombination von setjmp/longjmp-und das SIGALRM-signal.
Hier der code:
#include <stdio.h>
#include <setjmp.h>
#include <unistd.h>
#include <string.h>
#include <sys/signal.h>
jmp_buf buffer;
//this will cause t_gets() to return -2
void timeout() {
longjmp(buffer, 1);
}
int t_gets(char* s, int t)
{
char* ret;
signal(SIGALRM, timeout);
if (setjmp(buffer) != 0)
return -2; //<--- timeout() will jump here
alarm(t);
//if fgets() does not return in t seconds, SIGALARM handler timeout()
//will be called, causing t_gets() to return -2
ret = fgets(s, 100, stdin);
alarm(0);
if (ret == NULL ) return -1;
return strlen(s);
}
int main()
{
char s[100];
int z=t_gets(s, 5);
printf("%d\n", z);
}
Nun, meine Frage ist, ob es etwas gibt, die schief gehen können mit dieser Funktion. Ich habe gelesen, dass der Aufruf von longjmp() von einem signal-handler kann ein Undefiniertes Verhalten, was ist es genau refferring zum?
Auch, was passiert, wenn der alarm ausgelöst wird direkt nach der Funktion fgets() gibt, aber bevor alarm(0) aufgerufen wird? Wird es dazu führen, dass die Funktion return -2, selbst wenn der Benutzer hat die Eingabe etwas?
SPÄTER EDIT:
Ich bin nicht daran interessiert, Möglichkeiten, den code zu verbessern. Ich möchte nur wissen, wie könnte es scheitern.
ret
ist nicht initialisiert, so der Aufruffgets
wird eine Speicherbeschädigung verursachen.ret
zugewiesen bekommt, mit dem Ergebnis, dasfgets()
Aufruf der Funktion.- fgets() liefert den ersten parameter, bei Erfolg oder NULL im Falle eines Fehlers. Ich sehe nicht, wie das könnte dazu führen, Speicher Korruption. Die Inhalte sind gespeichert in en.
- Never mind--Magermilch zu schnell. Misread "fgets(s, ...)".
Du musst angemeldet sein, um einen Kommentar abzugeben.
Auf der man-Seite für longjmp:
Deiner zweiten Frage: ja, die Funktion gibt -2, weil
longjmp()
dazu, dass es gehen, um diesetjmp(buffer)
Teil, aber das timing muss sehr genau sein.longjmp()
wird die Funktion zurückgeben und nicht mehr Signale erforderlich sein, wird für den alarm.main
beendet. Die Tatsache, dass eine Funktion hat eine unerwünschte Nebenwirkung von Stress für die signal-Maske ist ein problem im Allgemeinen.Wenn es darum geht, was schief gehen könnte, wenn das Verhalten nicht definiert ist, ist die einzige Antwort, die Sie sich verlassen können ist "nichts, auch nichts". Vielleicht nichts schief geht, vielleicht bekommen Sie einen segfault, vielleicht bekommen Sie die Nasen-daemons.
Mehr spezifische Antworten hängen davon ab, welches system und Version, mit der Sie arbeiten. Zum Beispiel, auf Linux Distributionen (zumindest alle seit 2000), der kernel führt einige Aufgaben, die nach der signal-handler zurückgibt. Wenn Sie longjmp, Sie werden wahrscheinlich verlassen junk auf dem kernel-stack, die Probleme verursachen können später, wie irrtümlich Rückkehr in die code-Programm ausgeführt wurde, wenn das signal wurde gefangen (der Aufruf von 'fgets' im Beispiel). Oder nicht.
Aufruf von longjmp in einem signal-handler kann auch (im Allgemeinen, aber wahrscheinlich nicht in deinem Beispiel) Einführung eines security-Loch.
longjmp
aus einem signal-handler wenn können Sie sicherstellen, dass der signal-handler unterbricht nicht ein async-signal-unsichere Funktion. Leiderfgets
ist async-signal-unsicher, so OP ' s code ist falsch.Anderen schön (oder hässlich, je nach Ihrer Sicht) Weg, um
fgets
- bail-out wäre:Und im signal-handler:
Vermutlich das funktioniert auch auf alten Systemen ohne
sigaction
und mit BSDsignal
Semantik.Ich glaube nicht, dass Sie brauchen, um zu verwenden
setjmp
/longjmp
.fgets
sollten unterbrochen werden durch Signale (errno auf EINTR), obwohl Sie wahrscheinlich benötigen, um verwendensigaction(...)
eher alssignal(...)
zu gewährleisten SA_RESTART ist klar.fgets()
ausfallen sollte nacht
Sekunden, unabhängig davon, ob ein signal gesendet wurde.fgets
können ausfallen, ohne ein signal zu senden. Bist du nicht mit den alarm-signal, um die Fehler verursachen?sigaction
tatsächlich Ursachefgets
zu scheitern. Danke für deine Antwort. Allerdings (wenn du auch meine später Bearbeiten), ich bin mehr daran interessiert, die Möglichkeiten, die der Ansatz, den ich gepostet fehlschlagen könnte.Über Ihre zweite Frage, die Sie hinzufügen können, eine Sperre, die blockiert die Rückkehr -2, wenn der Haupt-thread übergeben, der fgets nennen.
Könnten Sie initialisieren
ret
(NULL, möglicherweise) und überprüfen, dass im Körper derif(setjmp())
Aussage:Können Sie ersetzen die longjmp/setjmp mit siglongjmp/sigsetjump und dann nicht die Ausgabe des Signals Kontext wird nicht definiert nach dem jmp. Sie können nicht wirklich hier, da Sie nicht explizit ändern Sie die Maske. Ich vergessen, wenn die Maske geändert durch das signal an sich selbst aufrufen.
Was vielleicht das größere Problem ist es, sicherzustellen, dass Ihr code-signal sicher. Zum Beispiel, tut der Funktion fgets() zu erwerben mutex (vielleicht implizit als Teil eines malloc-Aufruf)? Wenn es ist und den timer geht zwar Los, dass mutex ist gehalten, Ihr Programm toast nächste mal, wenn Sie versuchen, eine heap-allocation.