setjmp/longjmp und lokale Variablen

Lesezeit: 3 Minuten

Meine Fragen zielen auf das Verhalten von setjmp/longjmp in Bezug auf lokale Variablen ab.

Beispielcode:

jmp_buf env;


void abc()
{
  int error;

  ... 
  if(error)
    longjmp(env);
}


void xyz() {
  int v1;           // non-volatile; changed between setjmp and longjmp
  int v2;           // non-volatile; not changed between setjmp and longjmp
  volatile int v3;  // volatile;     changed between setjmp and longjmp
  volatile int v4;  // volatile;     not changed between setjmp and longjmp 

  ...

  if(setjmp(env)) {
    // error handling
    ...
    return;
  }

  v1++; // change v1
  v3++; // change v3

  abc();
}


int main(...) {
  xyz();
}

Die Dokumentation von setjmp/longjmp sagt:

„Alle zugänglichen Objekte haben Werte ab dem Zeitpunkt, an dem longjmp() aufgerufen wurde, außer dass die Werte von Objekten mit automatischer Speicherdauer, die lokal für die Funktion sind, die den Aufruf des entsprechenden setjmp() enthält, die keinen volatile-qualifizierten Typ haben und die zwischen dem Aufruf von setjmp() und dem Aufruf von longjmp() geändert werden, sind unbestimmt.”

Ich sehe folgende zwei mögliche Interpretationen:

Interpretation1:

Lokale Variablen werden wiederhergestellt, außer denen, die beides sind

  • nicht flüchtig u
  • geändert

Interpretation2:

Lokale Variablen werden wiederhergestellt, außer

  • diejenigen, die nicht flüchtig sind und
  • diejenigen, die geändert werden

Laut Interpretation1 ist nach longjmp nur v1 undefiniert. v2, v3, v4 sind definiert. Laut Interpretation2 ist nach longjmp nur v4 definiert. v1, v2, v3 sind undefiniert.

Welcher ist richtig?

Übrigens: Ich brauche eine allgemeine (“portable”) Antwort, die für alle Compiler gilt, dh das Ausprobieren mit einem bestimmten Compiler hilft nicht.

  • Hinweis zur Implementierung: Variablen, die geändert und nichtflüchtig sind, können je nach Codegenerierung so sein, wie sie zum Zeitpunkt von longjmp waren, oder auf den Stand zum Zeitpunkt von setjmp zurückgesetzt werden. Also „unbestimmt“. Also, wenn sie es wären nicht geändert, sind diese beiden Werte gleich und deshalb sind unveränderte Variablen sicher.

    – Gregor

    13. April 2012 um 21:27 Uhr

Benutzer-Avatar
Werden

setjmp/longjmp wird implementiert, indem die Register (einschließlich Stapel- und Codezeiger usw.) beim ersten Durchgang gespeichert und beim Springen wiederhergestellt werden.

Automatische (auch bekannt als “lokale”, Stack-zugewiesene) Variablen, die nicht “flüchtig” sind kann in Registern statt auf dem Stack gespeichert werden.

Unter diesen Umständen stellt longjmp diese Registervariablen auf ihren Wert zu dem Zeitpunkt zurück, an dem setjmp() zum ersten Mal aufgerufen wurde.

Außerdem könnte ein besonders cleverer Compiler Variablen vermeiden, die aus dem Zustand einer anderen Variablen abgeleitet werden können, und sie bei Bedarf berechnen.

Wenn die Variable jedoch automatisch ist, aber keinem Register zugewiesen wurde, kann sie durch Code zwischen setjmp und longjmp geändert werden.

Volatile weist den Compiler ausdrücklich an, die Variable nicht in einem Register zu speichern.

Wenn Sie also nicht ausdrücklich sagen, dass eine Variable flüchtig ist, hängt ihr Wert, wenn Sie die Variable zwischen setjmp/longjmp geändert haben, von den Entscheidungen ab, die der Compiler trifft, und ist daher nichts, worauf Sie sich verlassen sollten (“unbestimmt”).

  • Und ich denke umgekehrt, automatische Variablen, die als ‘register’ deklariert sind kann in Registern gespeichert werden, aber der Compiler ignoriert möglicherweise den Hinweis, sodass dies auch nicht garantieren kann, dass sie wiederhergestellt werden.

    – Michael

    17. April 2015 um 17:33 Uhr

  • @Michael Eigentlich gibt es nicht einmal eine Garantie, dass etwas “wiederhergestellt” wird. Der ‘normale’ Fall ist, dass Variablen den Wert haben, den sie hatten, bevor Sie die Funktion aufgerufen haben, die zu longjmp geführt hat. In einigen Fällen, wie oben besprochen, können sie durch die blinde Wiederherstellung aller aufrufgespeicherten Register durch setjmp/longjmp “überfordert” werden. In der Praxis bedeutet dies, dass sie, wenn sie verstopft werden, wahrscheinlich auf den Wert „setjmp“ zurückgesetzt werden, aber die Sprache gibt nur an, dass sie unbestimmt sind, und nicht, was Sie zuletzt eingestellt haben.

    – Gregor

    4. November 2016 um 15:07 Uhr


Deutung 1 ist richtig. Wenn Interpretation 2 beabsichtigt gewesen wäre, hätte der Originaltext „oder die geändert werden” statt “und”.

1371500cookie-checksetjmp/longjmp und lokale Variablen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy