Tester le bug de l'an 2038 sous Windows
Le 19 janvier 2038 à 03:14:07 UTC, un compteur signé de 32 bits de secondes depuis 1970 arrive au bout. L'horloge de Windows continue au-delà - pas les programmes, formats de fichier et bibliothèques qui ont gardé leur propre copie sur 32 bits. Voici comment les trouver dans une seule application, sans régler la date de toute la machine sur 2038.
Où le bug peut encore se cacher
L'horloge de Windows est un compteur sur 64 bits de pas de 100 nanosecondes depuis 1601, elle
ignore donc 2038. Le type time_t de la bibliothèque d'exécution C est sur 64 bits
par défaut depuis Visual Studio 2005. Reste le code qui a choisi une heure sur 32 bits, ou perdu
la moitié haute en chemin :
- Les builds 32 bits compilés avec
_USE_32BIT_TIME_T, ou qui appellent directement_time32et__time32_t. La documentation de Microsoft prévient qu'une telle application peut échouer après le 18 janvier 2038. - Une heure sur 64 bits rangée dans un
intou unlong. Sous Windows, les deux font 32 bits, même dans un programme 64 bits. - Les bibliothèques, formats de fichier, protocoles réseau et colonnes de bases de données qui gardent les secondes depuis 1970 sur 32 bits.
- Le code qui ajoute des années. Une licence de vingt ans, un échéancier de prêt sur trente ans ou un certificat valable jusqu'en 2040 franchissent la limite bien avant l'arrivée de 2038.
Franchir la limite dans une seule application
La limite est définie en UTC et --at se lit dans le fuseau de la session :
fixez donc le fuseau sur UTC quand vous écrivez l'instant vous-même. Le scénario prêt à l'emploi
porte déjà un instant UTC absolu et n'a pas besoin de fuseau.
# Le scénario : la session démarre sur la limite elle-même, 03:14:07 UTC chrono run "C:\apps\test.exe" --preset year-2038 --report session.txt # Démarrer dix-sept secondes avant et laisser l'application la franchir en direct chrono run "C:\apps\test.exe" --at 2038-01-19T03:13:50 --zone +00:00 --report session.txt # Démarrer plus tôt et tourner à vitesse x60 - la limite arrive en 14 secondes environ chrono run "C:\apps\test.exe" --at 2038-01-19T03:00:00 --zone +00:00 --mode x60 # Ou tourner à la date d'aujourd'hui et sauter par-dessus pendant que l'application est ouverte chrono run "C:\apps\test.exe" --jump-after 5:2038-01-19T03:14:05 --zone +00:00
Une seconde après la limite, un compteur signé de 32 bits devient -2 147 483 648, ce qui se lit 13 décembre 1901, 20:45:52 UTC. Une date en 1901, un nombre négatif, un élément soudain expiré ou trié en premier, une exception levée par le code des dates - voilà à quoi ressemble le dépassement vu de l'extérieur.
Régler la vraie horloge sur 2038 est l'autre manière d'y arriver, et celle qui casse le plus. Ce qui se passe quand on change la date système →
Vérifier que cela a atteint le programme
Un test qui réussit parce que le programme n'a jamais vu 2038 est pire que pas de test. Le rapport de fin de chaque session dit quelle horloge le programme a lue et combien de fois :
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)
La ligne session confirme que l'horloge de l'application a dépassé la limite. Un verdict works avec des compteurs d'appels signifie que le programme a lu l'horloge et reçu la date de 2038 ; works partially nomme les canaux qu'il a lus par un autre chemin. Ce que signifient les verdicts →
Ce qu'un test réussi ne prouve pas
- Seule l'horloge du programme a bougé. Une date qu'il charge depuis un fichier
ou une base est celle qui y est stockée, donc une date de 2038 dans les données est un autre
test. Le calculateur de dates calcule ces dates pour vous :
chrono calc --base 2038-01-19T03:14:07 --zone +00:00 --shift +1s - Un serveur avec lequel le programme dialogue tourne toujours à la vraie date. Une limite de 32 bits de ce côté est hors de portée, et la session avertit quand elle voit le programme ouvrir une connexion réseau.