Chrono Mock
IdiomaEspañol

Probar el problema del año 2038 en Windows

El 19 de enero de 2038 a las 03:14:07 UTC se agota un contador con signo de 32 bits de segundos desde 1970. El reloj de Windows sigue más allá - los programas, formatos de archivo y bibliotecas que guardaron su propia copia de 32 bits, no. Así los encuentras en una sola aplicación, sin poner la fecha de toda la máquina en 2038.

Dónde puede seguir el fallo

El reloj de Windows es un contador de 64 bits de pasos de 100 nanosegundos desde 1601, así que no conoce el 2038. El tipo time_t de la biblioteca de ejecución de C es de 64 bits por defecto desde Visual Studio 2005. Queda el código que eligió una hora de 32 bits o perdió la mitad alta por el camino:

  • Compilaciones de 32 bits con _USE_32BIT_TIME_T, o que llaman directamente a _time32 y __time32_t. La documentación de Microsoft advierte de que esa aplicación puede fallar después del 18 de enero de 2038.
  • Una hora de 64 bits guardada en un int o un long. En Windows ambos son de 32 bits, incluso en un programa de 64 bits.
  • Bibliotecas, formatos de archivo, protocolos de red y columnas de bases de datos que guardan los segundos desde 1970 en 32 bits.
  • Código que suma años. Una licencia de veinte años, un plan de préstamo a treinta o un certificado válido hasta 2040 cruzan el límite mucho antes de que llegue 2038.

Cruzar el límite en una sola aplicación

El límite se define en UTC y --at se lee en la zona de la sesión, así que fija la zona en UTC cuando escribas tú el instante. El escenario ya preparado lleva un instante UTC absoluto y no necesita zona.

# El escenario: la sesión empieza en el propio límite, 03:14:07 UTC
chrono run "C:\apps\test.exe" --preset year-2038 --report session.txt

# Empezar diecisiete segundos antes y dejar que la aplicación lo cruce en directo
chrono run "C:\apps\test.exe" --at 2038-01-19T03:13:50 --zone +00:00 --report session.txt

# Empezar antes y correr a velocidad x60 - el límite llega en unos 14 segundos
chrono run "C:\apps\test.exe" --at 2038-01-19T03:00:00 --zone +00:00 --mode x60

# O correr con la fecha de hoy y saltarlo mientras la aplicación está abierta
chrono run "C:\apps\test.exe" --jump-after 5:2038-01-19T03:14:05 --zone +00:00

Un segundo después del límite, un contador con signo de 32 bits pasa a ser -2.147.483.648, que se lee como 13 de diciembre de 1901, 20:45:52 UTC. Una fecha de 1901, un número negativo, un elemento que de pronto caduca o se ordena el primero, una excepción lanzada desde el código de fechas - así se ve el desbordamiento desde fuera.

Poner el reloj real en 2038 es la otra forma de llegar aquí, y la que más rompe. Qué pasa cuando cambias la fecha del sistema →

Comprobar que llegó al programa

Una prueba que pasa porque el programa nunca vio 2038 es peor que ninguna prueba. El informe del final de cada sesión dice qué reloj leyó el programa y cuántas veces:

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 línea session confirma que el reloj de la aplicación pasó el límite. Un veredicto works con contadores de llamadas significa que el programa leyó el reloj y recibió la fecha de 2038; works partially nombra los canales que leyó por otra vía. Qué significan los veredictos →

Lo que una prueba superada no demuestra

  • Solo se movió el reloj del propio programa. Una fecha que carga de un archivo o una base de datos es la que está guardada ahí, así que una fecha de 2038 dentro de los datos es otra prueba. La calculadora de fechas calcula esas fechas por ti: chrono calc --base 2038-01-19T03:14:07 --zone +00:00 --shift +1s
  • Un servidor con el que habla el programa sigue en la fecha real. Un límite de 32 bits de ese lado queda fuera de alcance, y la sesión avisa cuando ve que el programa abre una conexión de red.

Pruébalo