Chrono Mock
Ngôn ngữTiếng Việt

Kiểm thử lỗi năm 2038 trên Windows

Vào 03:14:07 UTC ngày 19 tháng 1 năm 2038, bộ đếm giây có dấu 32 bit tính từ năm 1970 sẽ hết. Đồng hồ Windows vẫn chạy tiếp qua mốc đó - còn các chương trình, định dạng tệp và thư viện giữ bản sao 32 bit riêng thì không. Dưới đây là cách tìm chúng trong một ứng dụng, mà không phải đặt ngày của cả máy về năm 2038.

Lỗi vẫn có thể nằm ở đâu

Đồng hồ Windows là bộ đếm 64 bit các bước 100 nano giây tính từ năm 1601, nên nó không có năm 2038. Kiểu time_t của thư viện thời gian chạy C mặc định là 64 bit từ Visual Studio 2005. Phần còn lại là mã đã chọn thời gian 32 bit hoặc đánh mất nửa cao trên đường đi:

  • Bản dựng 32 bit biên dịch với _USE_32BIT_TIME_T, hoặc gọi trực tiếp _time32 và __time32_t. Tài liệu của chính Microsoft cảnh báo ứng dụng như vậy có thể hỏng sau ngày 18 tháng 1 năm 2038.
  • Thời gian 64 bit lưu trong int hoặc long. Trên Windows cả hai đều là 32 bit, kể cả trong chương trình 64 bit.
  • Thư viện, định dạng tệp, giao thức mạng và cột cơ sở dữ liệu lưu số giây từ năm 1970 trong 32 bit.
  • Mã cộng thêm năm. Giấy phép hai mươi năm, lịch trả nợ ba mươi năm hay chứng chỉ có hiệu lực đến năm 2040 vượt qua ranh giới này rất lâu trước khi năm 2038 đến.

Vượt qua ranh giới trong một ứng dụng

Ranh giới được định nghĩa theo UTC và --at được đọc theo múi giờ của phiên, nên hãy cố định múi giờ là UTC khi bạn tự viết thời điểm. Kịch bản dựng sẵn đã mang một thời điểm UTC tuyệt đối và không cần múi giờ.

# Kịch bản: phiên bắt đầu ngay tại ranh giới, 03:14:07 UTC
chrono run "C:\apps\test.exe" --preset year-2038 --report session.txt

# Bắt đầu trước mười bảy giây và để ứng dụng vượt qua nó trực tiếp
chrono run "C:\apps\test.exe" --at 2038-01-19T03:13:50 --zone +00:00 --report session.txt

# Bắt đầu sớm hơn và chạy với tốc độ x60 - ranh giới đến sau khoảng 14 giây
chrono run "C:\apps\test.exe" --at 2038-01-19T03:00:00 --zone +00:00 --mode x60

# Hoặc chạy với ngày hôm nay và nhảy qua nó khi ứng dụng đang mở
chrono run "C:\apps\test.exe" --jump-after 5:2038-01-19T03:14:05 --zone +00:00

Một giây sau ranh giới, bộ đếm 32 bit có dấu trở thành -2.147.483.648, được đọc là ngày 13 tháng 12 năm 1901, 20:45:52 UTC. Một ngày thuộc năm 1901, một số âm, một mục đột nhiên hết hạn hoặc bị xếp lên đầu, một ngoại lệ ném ra từ mã xử lý ngày - đó là dáng vẻ của hiện tượng tràn số nhìn từ bên ngoài.

Đặt đồng hồ thật về năm 2038 là con đường khác để đến đây, và là con đường làm hỏng nhiều nhất. Điều gì xảy ra khi bạn đổi ngày hệ thống →

Kiểm tra rằng nó đã đến được chương trình

Một bài kiểm thử đạt chỉ vì chương trình chưa bao giờ thấy năm 2038 còn tệ hơn không có bài kiểm thử. Báo cáo ở cuối mỗi phiên cho biết chương trình đã đọc đồng hồ nào và bao nhiêu lần:

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)

Dòng session xác nhận đồng hồ của ứng dụng đã vượt qua ranh giới. Kết luận works cùng số lần gọi nghĩa là chương trình đã đọc đồng hồ và nhận được ngày năm 2038; works partially nêu tên các kênh nó đọc qua đường khác. Các kết luận có nghĩa là gì →

Điều một bài kiểm thử đạt không chứng minh

  • Chỉ đồng hồ của chính chương trình đã dịch chuyển. Ngày nó nạp từ tệp hoặc cơ sở dữ liệu là ngày đang lưu ở đó, nên một ngày năm 2038 nằm trong dữ liệu là một bài kiểm thử riêng. Máy tính ngày sẽ tính những ngày như vậy cho bạn: chrono calc --base 2038-01-19T03:14:07 --zone +00:00 --shift +1s
  • Máy chủ mà chương trình giao tiếp vẫn chạy theo ngày thật. Giới hạn 32 bit ở phía đó nằm ngoài tầm với, và phiên sẽ cảnh báo khi thấy chương trình mở kết nối mạng.

Dùng thử