Chrono Mock
МоваУкраїнська

Тестування проблеми 2038 року у Windows

19 січня 2038 року о 03:14:07 UTC закінчується 32-розрядний знаковий лічильник секунд з 1970 року. Годинник Windows іде далі — а програми, формати файлів і бібліотеки, що зберегли власну 32-розрядну копію, ні. Ось як знайти їх в одному застосунку, не виставляючи на всій машині дату 2038 року.

Де помилка все ще може ховатися

Годинник Windows — це 64-розрядний лічильник кроків по 100 наносекунд з 1601 року, тож 2038 року в ньому немає. Тип time_t у бібліотеці часу виконання C за замовчуванням 64-розрядний починаючи з Visual Studio 2005. Лишається код, який обрав 32-розрядний час або загубив старшу половину дорогою:

  • 32-розрядні збірки, скомпільовані з _USE_32BIT_TIME_T, або такі, що напряму викликають _time32 і __time32_t. Документація Microsoft попереджає, що такий застосунок може відмовити після 18 січня 2038 року.
  • 64-розрядний час, збережений у int чи long. У Windows обидва 32-розрядні, навіть у 64-розрядній програмі.
  • Бібліотеки, формати файлів, мережеві протоколи й стовпці баз даних, що зберігають секунди з 1970 року в 32 бітах.
  • Код, що додає роки. Двадцятирічна ліцензія, тридцятирічний графік кредиту чи сертифікат, дійсний до 2040 року, перетинають межу задовго до настання 2038 року.

Перетин межі в одному застосунку

Межу задано в UTC, а --at читається в поясі сесії, тож під час ручного запису моменту зафіксуйте пояс як UTC. Готовий сценарій уже несе абсолютний момент у UTC і в поясі не потребує.

# Сценарій: сесія стартує просто на межі, 03:14:07 UTC
chrono run "C:\apps\test.exe" --preset year-2038 --report session.txt

# Стартувати за сімнадцять секунд до неї й дати застосунку перетнути межу на ходу
chrono run "C:\apps\test.exe" --at 2038-01-19T03:13:50 --zone +00:00 --report session.txt

# Стартувати раніше й іти вшестеро швидше — межа настане приблизно за 14 секунд
chrono run "C:\apps\test.exe" --at 2038-01-19T03:00:00 --zone +00:00 --mode x60

# Або йти з сьогоднішньою датою й перестрибнути межу, поки застосунок відкрито
chrono run "C:\apps\test.exe" --jump-after 5:2038-01-19T03:14:05 --zone +00:00

Через секунду після межі 32-розрядний знаковий лічильник стає рівним -2 147 483 648, що читається як 13 грудня 1901 року, 20:45:52 UTC. Дата 1901 року, від’ємне число, елемент, що раптом прострочився чи опинився першим у сортуванні, виняток із коду роботи з датами — так переповнення виглядає зовні.

Виставити справжній годинник на 2038 рік — інший шлях сюди, і він ламає найбільше. Що відбувається, коли ви змінюєте системну дату →

Перевірка, що межа дійшла до програми

Тест, що проходить лише тому, що програма так і не побачила 2038 рік, гірший за відсутність тесту. Звіт наприкінці кожної сесії повідомляє, який годинник програма читала і скільки разів:

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)

Рядок session підтверджує, що годинник застосунку перейшов межу. Вердикт works із лічильниками викликів означає, що програма читала годинник і отримала дату 2038 року; works partially називає канали, які вона читала іншим шляхом. Що означають вердикти →

Чого пройдений тест не доводить

  • Зсунувся лише власний годинник програми. Дата, яку вона завантажує з файлу чи бази даних, — та, що там записана, тож дата 2038 року всередині даних — це окремий тест. Калькулятор дат обчислить такі дати за вас: chrono calc --base 2038-01-19T03:14:07 --zone +00:00 --shift +1s
  • Сервер, з яким спілкується програма, як і раніше живе в справжній даті. 32-розрядна межа з того боку недосяжна, а сесія попереджає, коли бачить, що програма відкриває мережеве з’єднання.

Спробуйте