UCONTEXT Puffergröße

Meine Tests liefen alle super am PC. Doch unter ARM64 krachte es gehörig.

Sieht so aus, als wären (wieder mal) die Koroutinen Schuld.

Aber warum?


Im GATE Projekt herrscht in den öffentlich Headern striktes Include-Verbot für System-spezifische Header.
Bibliotheken wie boost versauen einem schon alleine wegen ihrer Includes von windows.h und unter Linux von allen Posix-, Netzwerk und Kernel-Headern ein performantes Ergebnis.

Doch … wie kann man eine öffentliche Datenstruktur schaffen, die systemspezifische Typen wie jmp_buf oder ucontext beinhaltet ohne dass die Typen definiert sind?

Ein Antwort wären Heap-Allokationen … doch diese fragmentieren den Speicher und erfordern ein zusätzliches Aufräum-Management.

Die Alternative sind Puffer, die als kleinster gemeinsamer Nenner aller möglichen Puffergrößen entsprechend groß sind um “alles” fressen zu können.

Mit der Strategie bin ich bisher gut gefahren, bis sie mich neulich in den Arsch biss.

ARM64 Stack-Status

Ich messe Puffer für native Datenstrukturen gerne in void* Einheiten. Hat eine Struktur 5 Member, sind die selten größer als 5 Pointer, und mit dem Doppelten kann die Obergrenze nicht überschitten werden … so der Gedanke.

Bei meinen X86 Systemen kam ich vermutlich bei der Durchsicht der System- Header auf den Wert 64 und legte damit fest, dass ein Stack-Kontext nie größer als 512 Bytes (bei 64-bit: 8 Bytes * 64 Einheiten) sein wird. Kein Prozessor hat mehr als 32 Register … also warum Speicher verschwenden.

Tja … ARM64 sprengt diese Grenze vielfach, und damit auch alle meine Prozesse mit Koroutinen-Code.
Wer in /usr/include/aarch64-linux-gnu/sys/ucontext.h nachsieht, stellt fest, dass neben den CPU-Registern noch 4 KByte für FP/SIMD Zustände reserviert werden.

Und genau hier haben die ucontext Funktionen in meinen viel zu kleinen Puffer Daten im anliegenden Speicher auf dem Stack überschrieben.

Neue Größenordnung

Die neue Implementierung geht von 1 KByte für “übliche” Prozessoren aus, sowie 4.5 KByte für ARM64. Ab sofort kann für jede Architektur ein Makro gesetzt werden, dass die interne Puffergröße anpasst.

Kaum war der Patch implementiert, liefen auch wieder alle Tests auf der ARM64 Plattform problemlos durch.

Fazit

4.5 KByte … W-T-F ?

Tja, hier merkt man, dass ich ein Kind der 90er Jahre bin. Das Speichern aller CPU-Zustände ging sich damals in wenigen Bytes aus. 64 Bytes waren da schon “viel”.

Doch heute ist ein Prozessor das, was früher 8 unterschiedliche Prozessoren waren. Kein Wunder also, dass Linux “zur Sicherheit” gleich mehrere Kilobyte reserviert.

Also Augen auf bei neuen Plattformen!
Wieviele Bytes mögen die wohl für einen Kontextstatus brauchen?

📧 📋 🐘 | 🔗 🔔
 

Meine Dokus über:
 
Weitere externe Links zu:
Alle extern verlinkten Webseiten stehen nicht in Zusammenhang mit opengate.at.
Für deren Inhalt wird keine Haftung übernommen.



Wenn sich eine triviale Erkenntnis mit Dummheit in der Interpretation paart, dann gibt es in der Regel Kollateralschäden in der Anwendung.
frei zitiert nach A. Van der Bellen
... also dann paaren wir mal eine komplexe Erkenntnis mit Klugheit in der Interpretation!