Chrono Mock
TaalNederlands

Het jaar-2038-probleem testen in Windows

Op 19 januari 2038 om 03:14:07 UTC raakt een 32-bits teller met teken voor seconden sinds 1970 op. De Windows-klok loopt er gewoon doorheen - de programma's, bestandsformaten en bibliotheken die hun eigen 32-bits kopie hielden, niet. Zo vind je die in één applicatie, zonder de datum van de hele machine op 2038 te zetten.

Waar de bug nog kan zitten

De Windows-klok is een 64-bits teller van stappen van 100 nanoseconden sinds 1601, dus hij kent geen 2038. Het type time_t van de C-runtimebibliotheek is sinds Visual Studio 2005 standaard 64 bits. Wat overblijft is code die een 32-bits tijd koos of onderweg de bovenste helft kwijtraakte:

  • 32-bits builds die met _USE_32BIT_TIME_T zijn gecompileerd, of die _time32 en __time32_t rechtstreeks aanroepen. De documentatie van Microsoft waarschuwt dat zo'n applicatie na 18 januari 2038 kan uitvallen.
  • Een 64-bits tijd opgeslagen in een int of long. In Windows zijn beide 32 bits, ook in een 64-bits programma.
  • Bibliotheken, bestandsformaten, netwerkprotocollen en databasekolommen die seconden sinds 1970 in 32 bits bewaren.
  • Code die jaren optelt. Een licentie van twintig jaar, een aflossingsschema van dertig jaar of een certificaat dat tot 2040 geldt, passeren de grens lang voordat 2038 aanbreekt.

De grens oversteken in één applicatie

De grens is gedefinieerd in UTC en --at wordt gelezen in de sessiezone, dus zet de zone op UTC wanneer je het moment zelf schrijft. Het kant-en-klare scenario bevat al een absoluut UTC-moment en heeft geen zone nodig.

# Het scenario: de sessie start op de grens zelf, 03:14:07 UTC
chrono run "C:\apps\test.exe" --preset year-2038 --report session.txt

# Zeventien seconden ervoor starten en de applicatie hem live laten oversteken
chrono run "C:\apps\test.exe" --at 2038-01-19T03:13:50 --zone +00:00 --report session.txt

# Eerder starten en op x60 snelheid draaien - de grens komt na ongeveer 14 seconden
chrono run "C:\apps\test.exe" --at 2038-01-19T03:00:00 --zone +00:00 --mode x60

# Of draaien op de datum van vandaag en eroverheen springen terwijl de applicatie open staat
chrono run "C:\apps\test.exe" --jump-after 5:2038-01-19T03:14:05 --zone +00:00

Een seconde voorbij de grens wordt een 32-bits teller met teken -2.147.483.648, wat gelezen wordt als 13 december 1901, 20:45:52 UTC. Een datum in 1901, een negatief getal, een item dat plotseling verlopen is of vooraan gesorteerd staat, een uitzondering uit de datumcode - zo ziet de overflow er van buiten uit.

De echte klok op 2038 zetten is de andere manier om hier te komen, en de manier die het meeste kapotmaakt. Wat er gebeurt als je de systeemdatum wijzigt →

Controleren dat het het programma bereikte

Een test die slaagt omdat het programma 2038 nooit zag, is erger dan geen test. Het rapport aan het einde van elke sessie zegt welke klok het programma las en hoe vaak:

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)

De regel session bevestigt dat de klok van de applicatie voorbij de grens ging. Een oordeel works met aantallen aanroepen betekent dat het programma de klok las en de datum uit 2038 kreeg; works partially noemt de kanalen die het op een andere manier las. Wat de oordelen betekenen →

Wat een geslaagde test niet bewijst

  • Alleen de eigen klok van het programma is verschoven. Een datum die het uit een bestand of database laadt, is wat daar is opgeslagen, dus een datum uit 2038 in de gegevens is een aparte test. De datumrekenmachine rekent zulke datums voor je uit: chrono calc --base 2038-01-19T03:14:07 --zone +00:00 --shift +1s
  • Een server waarmee het programma praat, draait nog op de echte datum. Een 32-bits limiet aan die kant is onbereikbaar, en de sessie waarschuwt wanneer ze ziet dat het programma een netwerkverbinding opent.

Probeer het