Jahr-2038-Problem

aus Wikipedia, der freien Enzyklopädie
(Weitergeleitet von Jahr-2037-Problem)

Das Jahr-2038-Problem von EDV-Systemen (Numeronym: Y2K38) könnte zu Ausfällen von Software im Jahr 2038 führen. Dieses Problem ist auf EDV-Systeme beschränkt, die die Unixzeit benutzen und time_t als vorzeichenbehaftete 32-Bit-Ganzzahl definieren.

Darstellung des Jahr-2038-Problems:
1.: Zeitdarstellung im Binärsystem
2.: die dazugehörige Dezimalzahl
3.: Fehlerhafte Darstellung der Zeit
4.: Korrekte Zeitangabe

Hintergrund

Die Unixzeit zählt die seit dem 1. Januar 1970 abgelaufene Zeit in Sekunden.[1] Am Dienstag, dem 19. Januar 2038 um 03:14:07 Uhr UTC wird die Anzahl der vergangenen Sekunden die Kapazität einer vorzeichenbehafteten 32-Bit-Ganzzahl (Maximalwert 2.147.483.647, 231−1) überschreiten.[2] Das signifikanteste Bit (MSB, wie hier im Beispiel meist die linkeste Stelle) wird laut Konvention dazu verwendet, positive und negative Zahlen zu unterscheiden (Vorzeichen im Zweierkomplement), sodass die Zählung bei einer Überschreitung des Wertes 2.147.483.647 (binär 01111111 11111111 11111111 11111111) in den negativen Bereich springt (z. B. −2.147.483.648 binär 10000000 00000000 00000000 00000000). Das führt bei einer ungenügend implementierten Konvertierung von Unixzeit zu Datum und Uhrzeit ungewollt zur Interpretation des Wertes als 20:45:52 Uhr am Freitag, 13. Dezember 1901 UTC. Dieses Problem wird in der Softwareentwicklung als Zählerüberlauf bezeichnet.

Ohne Gegenmaßnahmen könnten die wirtschaftlichen Auswirkungen unter Umständen schädlich sein, zumal im Banken- und Versicherungsumfeld Unix-Systeme neben Mainframes zur Standardausstattung gehören. Neben den Unix-Servern arbeiten viele eingebettete Systeme mit Unix-artigen Betriebssystemen, deren Einsatzzeit oft ein Vielfaches von Desktop- und Serversystemen beträgt (z. B. Router und elektronische Messgeräte). Eine zumindest verzögerte, auf Dauer aber notwendige Anpassung bzw. Modernisierung entsprechender Rechnersysteme in Unternehmen und Institutionen in heutiger Zeit könnte die Ausfallwahrscheinlichkeit senken.

Beispiel

Ein Beispiel für Jahr-2038-Fehler ist die Gültigkeitsprüfung per Zeitstempel: hierzu wird beim Beginn eines Vorganges die aktuelle Zeit gespeichert. Mit dieser kann sichergestellt werden, dass bis zum Abschluss des Vorgangs nicht mehr Zeit verstreicht als vorgegeben (beispielsweise die automatische Abmeldung beim Onlinebanking nach wenigen Minuten zur Missbrauchsvermeidung). Springt innerhalb einer solchen Frist der vom System angegebene Zeitstempel auf das Jahr 1901, so ist die Differenz fortan immer negativ. Erwartet das Programm nun aber eine positive Zahl mit einer Mindestgröße (z. B. 5 Minuten nach Beginn des Vorganges), wartet es vergeblich darauf, dass die Zahl positiv wird – die Zahl bleibt somit immer kleiner als der Zielwert von beispielsweise 5 Minuten. Das kann zu unerwünscht lange offen bleibenden Sicherheitszugängen führen oder auch zu Endlosschleifen, was sich für den Endbenutzer wie ein Nichtreagieren des Programms äußern kann.

Abhilfe

Im Unixumfeld hat sich beim Übergang von 32-Bit- zu 64-Bit-Architekturen durchgesetzt, dass der Basistyp „long“ der Programmiersprache C von 32 Bit auf 64 Bit aufgeweitet wird (technisch: Umstellung von ILP32 auf LP64-Modell). Dieser Datentyp entspricht der traditionellen Definition von time_t als größtem verfügbaren Basistyp, bevor mit C99 und UNIX98 der „long long“ Basistyp standardgemäß eingeführt wurde.[3] Solche 64-Bit-Systeme sind damit auf einen POSIX-Zeitstempel mit 64-Bit-Sekunden seit 1. Januar 1970 umgestellt, womit sie für 292 Milliarden Jahre zuverlässig arbeiten.

Dennoch reicht eine Umstellung auf neue 64-Bit-Prozessorarchitekturen (x64 bzw. AMD64/EM64T, Itanium/IA-64, IBM Power 5, UltraSPARC, PA-RISC, MIPS) hier alleine nicht aus: Sie vereinfacht zwar die systemseitige Anpassung, das macht jedoch die Durchforstung und Neu-Übersetzung aller Programme mit starrer 32-Bit-Formatierung nicht überflüssig. Nicht alle Programme sind bereits 64-Bit-tauglich, und es ist leicht möglich, dass vom System gelieferte 64-Bit-Zeitstempel fälschlicherweise als 32-Bit-Werte weiterverarbeitet werden und somit nur die niederwertigen 32 Bits abgefragt werden, welche dann losgelöst wiederum am 19. Januar 2038 den Wert −231 = 13. Dezember 1901 annehmen.

Da Unixsysteme auch in eingebetteten Systemen verbreitet sind, haben einige Betriebssysteme auch für 32-Bit-Prozessorarchitekturen die Definition von time_t auf 64-Bit umgestellt. Dies ist bei NetBSD die Version 6.0 von 2012, bei OpenBSD die Version 5.5 von 2014 und bei Linux die Version 5.6 von 2020.[4][5][6] Allerdings verbleibt meist die alte Binärschnittstelle, sodass eine Neuübersetzung notwendig wird. Auf der Applikationsebene hatte man schon vorher die Verwendung von 64-Bit Alternativen vorgeschlagen.[7][8][9] Die GNU-C-Bibliothek hatte für die Umstellung entsprechend eine time64_t Definition eingeführt.[10] Eine ähnliche Definition __time64_t wird im Windows-Umfeld verwendet, und mit Visual C++ 2005 wurde der Default auf time64 geändert.[11]

Eine andere Abhilfe ist die Umstellung der Programme vom Unixzeit-Zähler auf eine neue Zeitbasis; schon verbreitet ist etwa die Zählung von Millisekunden oder Mikrosekunden mit 64-Bit-Zählern (die nicht notwendigerweise eine 64-Bit-Architektur erfordern), insbesondere in eingebetteten Systemen mit Echtzeitanforderungen in dieser Größenordnung. Neuere Zeit-APIs verwenden immer eine größere Genauigkeit und Spannweite als die Unixzeit, beispielsweise Java System.currentTimeMillis (64-Bit-Millisekunden seit 1. Januar 1970; ausreichend für 292 Millionen Jahre) und .NET System.DateTime.Now.Ticks (64-Bit-10tel Mikrosekunden seit 1. Januar 0001; ausreichend für 29227 Jahre). Die datenbankgestützten Transaktionen verwenden oft TIMESTAMP-Werte, die im Datenbankstandard SQL92 mit einer Genauigkeit in Mikrosekunden definiert sind (auch so zugreifbar in ODBC/JDBC) und deren Repräsentation in Datenbanken meist als Abstand zum Tageszähler (SQL DATE) erfolgt, wobei der Tageszähler auch in 32 Bit eine größere Spannweite besitzt (die zugrunde liegende Epoche des Tageszählers ist jedoch sehr verschieden). Sofern diese Datentypen für Zeitstempel im Programm durchgängig weiterverwendet werden, heben sich die Beschränkungen des Unixzeit-Zählers auf.

Eine weitere Abhilfemöglichkeit ist die Speicherung des Zeitstempels als Zeichenkette, so wie es gemäß ISO 8601 vorgesehen ist, als YYYYMMDDhhmmss-Zeitstempel, z. B. „20140823142216“. Diese bleiben mindestens bis zum 31. Dezember 9999 23:59:59 Uhr von Jahr-Überlauf-Problemen verschont, sofern nicht die internen Operationen (z. B. zur Berechnung der Differenz zwischen zwei Zeitstempeln) diese in ein problematisches Binärformat umwandeln.

Verwandtes Jahr-2036-Problem

Eng verwandt zum Jahr-2038-Problem ist das Jahr 2036 (Numeronym: Y2K36). Am 7. Februar 2036 um 06:28:16 Uhr UTC läuft der Zähler des ursprünglich für UNIX entwickelten Zeitsynchronisations-Protokolls NTP (Network Time Protocol) über. In modernen Implementierungen ist dieses Problem zwar behoben (siehe RFC 5905), doch sehr viele Geräte – besonders eingebettete Systeme – arbeiten noch nach dem alten Standard RFC 868.

Auch hier ist der Hintergrund, dass die Zeitübermittlung als 32-Bit-Zahl in Sekunden stattfindet, jedoch mit der Startzeit 1. Januar 1900, 00:00:00 Uhr UTC und nicht vorzeichenbehaftet. Bei sehr ordentlicher Implementierung der Systeme kommt es sogar hier zu keinem (größeren) Problem während der Berechnung, da die Zeitsynchronisation nach einer Differenz-Methode arbeiten sollte.[12][13]

Allerdings können ungültige Werte – implementierungsabhängig – auch dadurch auftreten, dass sowohl im NTP-, als auch UNIX-Format gearbeitet wird: Dies betrifft insbesondere die wachsende Zahl eingebetteter Systeme im Rahmen des Internet of Things, wo zwar mangels batteriegestützter Echtzeituhr die Ermittlung der Systemzeit nach jedem Start zunächst im NTP-Format über Zeitserver erfolgen muss, diese in der Folge dann aber zur weiteren Repräsentation in die übliche Unixzeit konvertiert wird (durch Abzug der Zeitdifferenz). Wird hier die Zeit nach (nicht selten) fehlgeschlagenen Verbindungsversuchen mit 0 angegeben, und dementsprechend mit 1900-01-01 00:00:00 UTC (in Unixzeit nur als negativer Wert darstellbar), würden nicht abgesicherte Konvertierungen zum UNIX-Format zu einem ungültigen und (wenn vorzeichenbehaftet) zudem negativen Wert führen, mit vergleichbaren Auswirkungen auf das System und sein Verhalten.

Siehe auch

Literatur

  • OpenBSD 5.5 mit 64-bittiger Systemzeit. In: c’t 2014, Heft 12, S. 50.

Einzelnachweise

  1. Seconds Since The Epoch. Abgerufen am 16. Dezember 2010 (englisch).
  2. https://www.heise.de/ct/artikel/Prozessorgefluester-285204.html
  3. Data Size Neutrality and 64-bit Support. The Open Group.
  4. Announcing NetBSD 6.0. 17. Oktober 2012. Abgerufen am 18. Januar 2016.
  5. OpenBSD 5.5 released (May 1, 2014). 1. Mai 2014. Abgerufen am 18. Januar 2016.
  6. LKML: Arnd Bergmann: [GIT PULL y2038: core, driver and file system changes]. In: lkml.org . Abgerufen am 30. Januar 2020.
  7. Linux Standard Base Core Specification 4.0. Abgerufen am 16. Dezember 2010 (englisch).
  8. man pages section 3: Library Interfaces and Headers. (Nicht mehr online verfügbar.) Ehemals im Original; abgerufen am 16. Dezember 2010 (englisch).@1@2Vorlage:Toter Link/docs.sun.com (Seite nicht mehr abrufbar, Suche in Webarchiven)
  9. HP-UX Reference Volume 5 of 5. types(5). Abgerufen am 16. Dezember 2010 (englisch).
  10. 64-bit time symbol handling in the GNU C Library. GNU.org.
  11. time, _time32, _time64. Microsoft.
  12. Vgl. englische Wikipedia NTP Timestamps
  13. NTP Timescale and Leap Seconds. Abgerufen am 30. November 2015 (englisch).