Chrono Mock
LimbaRomână

Testarea problemei anului 2038 pe Windows

Pe 19 ianuarie 2038, la 03:14:07 UTC, se termină un contor cu semn pe 32 de biți al secundelor de la 1970. Ceasul Windows merge mai departe - programele, formatele de fișiere și bibliotecile care și-au păstrat propria copie pe 32 de biți, nu. Iată cum le găsești într-o singură aplicație, fără să pui pe 2038 data întregii mașini.

Unde mai poate sta bug-ul

Ceasul Windows este un contor pe 64 de biți de pași de 100 de nanosecunde de la 1601, deci nu are un 2038. Tipul time_t din biblioteca de execuție C este implicit pe 64 de biți încă de la Visual Studio 2005. Rămâne codul care a ales o oră pe 32 de biți sau a pierdut jumătatea superioară pe drum:

  • Build-urile pe 32 de biți compilate cu _USE_32BIT_TIME_T, sau care apelează direct _time32 și __time32_t. Documentația Microsoft avertizează că o asemenea aplicație poate cădea după 18 ianuarie 2038.
  • O oră pe 64 de biți stocată într-un int sau long. Pe Windows ambele au 32 de biți, chiar și într-un program pe 64 de biți.
  • Bibliotecile, formatele de fișiere, protocoalele de rețea și coloanele din baze de date care țin secundele de la 1970 pe 32 de biți.
  • Codul care adună ani. O licență de douăzeci de ani, un grafic de rambursare pe treizeci de ani sau un certificat valabil până în 2040 trec de limită cu mult înainte să vină 2038.

Trecerea limitei într-o singură aplicație

Limita este definită în UTC, iar --at se citește în fusul sesiunii, așa că fixează fusul pe UTC când scrii tu momentul. Scenariul gata făcut poartă deja un moment UTC absolut și nu are nevoie de fus.

# Scenariul: sesiunea pornește chiar de la limită, 03:14:07 UTC
chrono run "C:\apps\test.exe" --preset year-2038 --report session.txt

# Pornește cu șaptesprezece secunde înainte și lasă aplicația să treacă limita în direct
chrono run "C:\apps\test.exe" --at 2038-01-19T03:13:50 --zone +00:00 --report session.txt

# Pornește mai devreme și rulează la viteza x60 - limita vine în vreo 14 secunde
chrono run "C:\apps\test.exe" --at 2038-01-19T03:00:00 --zone +00:00 --mode x60

# Sau rulează cu data de azi și sari peste ea cât timp aplicația e deschisă
chrono run "C:\apps\test.exe" --jump-after 5:2038-01-19T03:14:05 --zone +00:00

La o secundă după limită, un contor cu semn pe 32 de biți devine -2.147.483.648, ceea ce se citește 13 decembrie 1901, 20:45:52 UTC. O dată din 1901, un număr negativ, un element care a expirat deodată sau a ajuns primul la sortare, o excepție aruncată din codul de date - așa arată depășirea văzută din exterior.

Setarea ceasului real pe 2038 este cealaltă cale de a ajunge aici, și cea care strică cel mai mult. Ce se întâmplă când schimbi data sistemului →

Verificarea că a ajuns la program

Un test care trece pentru că programul n-a văzut niciodată 2038 e mai rău decât niciun test. Raportul de la sfârșitul fiecărei sesiuni spune ce ceas a citit programul și de câte ori:

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)

Linia session confirmă că ceasul aplicației a trecut de limită. Un verdict works cu numărul de apeluri înseamnă că programul a citit ceasul și a primit data din 2038; works partially numește canalele pe care le-a citit pe altă cale. Ce înseamnă verdictele →

Ce nu dovedește un test trecut

  • S-a mutat doar ceasul programului însuși. O dată pe care o încarcă dintr-un fișier sau dintr-o bază de date este cea stocată acolo, așa că o dată din 2038 în date este un alt test. Calculatorul de date calculează astfel de date pentru tine: chrono calc --base 2038-01-19T03:14:07 --zone +00:00 --shift +1s
  • Un server cu care vorbește programul rulează în continuare pe data reală. O limită de 32 de biți de acea parte este în afara razei, iar sesiunea avertizează când vede programul deschizând o conexiune de rețea.

Încearcă-l