Chrono Mock
JęzykPolski

Testowanie problemu roku 2038 w Windows

O 03:14:07 UTC 19 stycznia 2038 kończy się 32-bitowy licznik sekund od 1970 roku ze znakiem. Zegar Windows biegnie dalej - programy, formaty plików i biblioteki, które zachowały własną 32-bitową kopię, nie. Tak znajdziesz je w jednej aplikacji, bez ustawiania daty całej maszyny na rok 2038.

Gdzie ten błąd może jeszcze siedzieć

Zegar Windows to 64-bitowy licznik kroków po 100 nanosekund liczony od 1601 roku, więc nie ma w nim roku 2038. Typ time_t w bibliotece uruchomieniowej C jest domyślnie 64-bitowy od Visual Studio 2005. Zostaje kod, który wybrał 32-bitowy czas albo po drodze zgubił jego górną połowę:

  • Kompilacje 32-bitowe z _USE_32BIT_TIME_T albo wywołujące wprost _time32 i __time32_t. Dokumentacja Microsoftu ostrzega, że taka aplikacja może przestać działać po 18 stycznia 2038.
  • 64-bitowy czas zapisany w int albo long. W Windows oba mają 32 bity, nawet w programie 64-bitowym.
  • Biblioteki, formaty plików, protokoły sieciowe i kolumny w bazach danych, które trzymają sekundy od 1970 roku w 32 bitach.
  • Kod, który dodaje lata. Dwudziestoletnia licencja, trzydziestoletni harmonogram kredytu albo certyfikat ważny do 2040 przekraczają tę granicę na długo przed nadejściem roku 2038.

Przekroczenie granicy w jednej aplikacji

Granica jest zdefiniowana w UTC, a --at czyta się w strefie sesji, więc przy ręcznie wpisanej chwili ustaw strefę na UTC. Gotowy scenariusz niesie już bezwzględną chwilę UTC i strefy nie potrzebuje.

# Scenariusz: sesja startuje na samej granicy, 03:14:07 UTC
chrono run "C:\apps\test.exe" --preset year-2038 --report session.txt

# Start siedemnaście sekund przed granicą - aplikacja przekracza ją na żywo
chrono run "C:\apps\test.exe" --at 2038-01-19T03:13:50 --zone +00:00 --report session.txt

# Start wcześniej i tempo 60 razy szybsze - granica nadchodzi po około 14 sekundach
chrono run "C:\apps\test.exe" --at 2038-01-19T03:00:00 --zone +00:00 --mode x60

# Albo praca na dzisiejszej dacie i skok przez granicę, gdy aplikacja jest otwarta
chrono run "C:\apps\test.exe" --jump-after 5:2038-01-19T03:14:05 --zone +00:00

Sekundę za granicą 32-bitowy licznik ze znakiem staje się -2 147 483 648, co czyta się jako 13 grudnia 1901, 20:45:52 UTC. Data z 1901 roku, liczba ujemna, pozycja, która nagle wygasła albo wylądowała na początku listy, wyjątek rzucony z kodu dat - tak przepełnienie wygląda z zewnątrz.

Ustawienie prawdziwego zegara na 2038 to drugi sposób, żeby się tu dostać, i ten psuje najwięcej. Co się dzieje, gdy zmieniasz datę systemową →

Sprawdzenie, że to dotarło do programu

Test, który przechodzi, bo program nigdy nie zobaczył 2038, jest gorszy niż brak testu. Raport na końcu każdej sesji mówi, który zegar program czytał i ile razy:

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 potwierdza, że zegar aplikacji przeszedł granicę. Werdykt works z licznikami wywołań oznacza, że program czytał zegar i dostał datę z roku 2038; works partially wymienia kanały, które odczytał inną drogą. Co znaczą werdykty →

Czego zaliczony test nie dowodzi

  • Przesunął się tylko zegar samego programu. Data wczytana z pliku albo z bazy jest taka, jaka tam zapisana, więc data z roku 2038 w danych to osobny test. Kalkulator dat wylicza takie daty za ciebie: chrono calc --base 2038-01-19T03:14:07 --zone +00:00 --shift +1s
  • Serwer, z którym program rozmawia, nadal żyje w prawdziwej dacie. 32-bitowy limit po tamtej stronie jest poza zasięgiem, a sesja ostrzega, gdy widzi, że program otwiera połączenie sieciowe.

Wypróbuj