Das Jahr-2038-Problem unter Windows testen
Am 19. Januar 2038 um 03:14:07 UTC geht ein vorzeichenbehafteter 32-Bit-Zähler für Sekunden seit 1970 zu Ende. Die Windows-Uhr läuft darüber hinaus weiter - die Programme, Dateiformate und Bibliotheken, die ihre eigene 32-Bit-Kopie behalten haben, nicht. So finden Sie diese in einer einzelnen Anwendung, ohne das Datum des ganzen Rechners auf 2038 zu stellen.
Wo der Fehler noch stecken kann
Die Windows-Uhr ist ein 64-Bit-Zähler in Schritten von 100 Nanosekunden ab 1601, also kennt sie
kein 2038. Der Typ time_t der C-Laufzeitbibliothek ist seit Visual Studio 2005
standardmäßig 64 Bit breit. Übrig bleibt Code, der eine 32-Bit-Zeit gewählt hat oder die obere
Hälfte unterwegs verloren hat:
- 32-Bit-Builds, die mit
_USE_32BIT_TIME_Tkompiliert wurden, oder die_time32und__time32_tdirekt aufrufen. Die Dokumentation von Microsoft warnt, dass eine solche Anwendung nach dem 18. Januar 2038 ausfallen kann. - Eine 64-Bit-Zeit, die in einem
intoderlonggespeichert wird. Unter Windows sind beide 32 Bit breit, auch in einem 64-Bit-Programm. - Bibliotheken, Dateiformate, Netzwerkprotokolle und Datenbankspalten, die Sekunden seit 1970 in 32 Bit ablegen.
- Code, der Jahre addiert. Eine zwanzigjährige Lizenz, ein dreißigjähriger Tilgungsplan oder ein bis 2040 gültiges Zertifikat überschreiten die Grenze lange bevor 2038 da ist.
Die Grenze in einer einzelnen Anwendung überschreiten
Die Grenze ist in UTC definiert, und --at wird in der Sitzungszone gelesen, also
legen Sie die Zone auf UTC fest, wenn Sie den Zeitpunkt selbst schreiben. Das fertige Szenario
trägt bereits einen absoluten UTC-Zeitpunkt und braucht keine Zone.
# Das Szenario: Die Sitzung beginnt genau an der Grenze, 03:14:07 UTC chrono run "C:\apps\test.exe" --preset year-2038 --report session.txt # Siebzehn Sekunden davor starten und die Anwendung die Grenze live überschreiten lassen chrono run "C:\apps\test.exe" --at 2038-01-19T03:13:50 --zone +00:00 --report session.txt # Früher starten und mit 60-facher Geschwindigkeit laufen - die Grenze kommt nach etwa 14 Sekunden chrono run "C:\apps\test.exe" --at 2038-01-19T03:00:00 --zone +00:00 --mode x60 # Oder mit dem heutigen Datum laufen und über die Grenze springen, während die Anwendung offen ist chrono run "C:\apps\test.exe" --jump-after 5:2038-01-19T03:14:05 --zone +00:00
Eine Sekunde nach der Grenze wird ein vorzeichenbehafteter 32-Bit-Zähler zu -2.147.483.648, was als 13. Dezember 1901, 20:45:52 UTC gelesen wird. Ein Datum im Jahr 1901, eine negative Zahl, ein Eintrag, der plötzlich abgelaufen ist oder ganz vorn einsortiert wird, eine Ausnahme aus dem Datumscode - so sieht der Überlauf von außen aus.
Die echte Uhr auf 2038 zu stellen ist der andere Weg hierher, und der, der am meisten kaputt macht. Was passiert, wenn Sie das Systemdatum ändern →
Prüfen, dass es das Programm erreicht hat
Ein Test, der besteht, weil das Programm 2038 nie gesehen hat, ist schlimmer als kein Test. Der Bericht am Ende jeder Sitzung sagt, welche Uhr das Programm gelesen hat und wie oft:
Chrono Mock - session report
target: .\build\test.exe
verdict: WORKS - time substitution took effect (processes: 1)
every process that read time saw the session clock
session: fake clock reached 2038-01-19T03:14:08
real elapsed 1.3s, fake elapsed 1.3s
covered channels (substituted, with call counts, 10 calls in all):
- pid 21240: GetSystemTimeAsFileTime (5 calls)
- pid 21240: GetLocalTime (5 calls)
Die Zeile session bestätigt, dass die Uhr der Anwendung die Grenze überschritten hat. Ein Urteil works mit Aufrufzahlen heißt, dass das Programm die Uhr gelesen und das Datum aus 2038 erhalten hat; works partially nennt die Kanäle, die es auf anderem Weg gelesen hat. Was die Urteile bedeuten →
Was ein bestandener Test nicht beweist
- Nur die eigene Uhr des Programms hat sich verschoben. Ein Datum, das es aus
einer Datei oder Datenbank lädt, ist das, was dort gespeichert ist, also ist ein Datum aus 2038
in den Daten ein eigener Test. Der Datumsrechner berechnet solche Daten für Sie:
chrono calc --base 2038-01-19T03:14:07 --zone +00:00 --shift +1s - Ein Server, mit dem das Programm spricht, läuft weiter im echten Datum. Eine 32-Bit-Grenze auf dieser Seite ist außer Reichweite, und die Sitzung warnt, wenn sie sieht, dass das Programm eine Netzwerkverbindung öffnet.