Testando o problema do ano 2038 no Windows
Em 19 de janeiro de 2038, às 03:14:07 UTC, acaba um contador de 32 bits com sinal de segundos desde 1970. O relógio do Windows segue adiante - os programas, formatos de arquivo e bibliotecas que guardaram a própria cópia de 32 bits, não. Veja como encontrá-los em um único aplicativo, sem colocar a data da máquina inteira em 2038.
Onde o bug ainda pode estar
O relógio do Windows é um contador de 64 bits de passos de 100 nanossegundos desde 1601, então não
conhece 2038. O tipo time_t da biblioteca de execução do C é de 64 bits por padrão
desde o Visual Studio 2005. Sobra o código que escolheu um tempo de 32 bits ou perdeu a metade
alta pelo caminho:
- Compilações de 32 bits feitas com
_USE_32BIT_TIME_T, ou que chamam_time32e__time32_tdiretamente. A documentação da Microsoft avisa que esse aplicativo pode falhar depois de 18 de janeiro de 2038. - Um tempo de 64 bits guardado em um
intoulong. No Windows os dois têm 32 bits, mesmo em um programa de 64 bits. - Bibliotecas, formatos de arquivo, protocolos de rede e colunas de banco de dados que guardam segundos desde 1970 em 32 bits.
- Código que soma anos. Uma licença de vinte anos, um cronograma de financiamento de trinta ou um certificado válido até 2040 cruzam o limite muito antes de 2038 chegar.
Cruzando o limite em um único aplicativo
O limite é definido em UTC e --at é lido no fuso da sessão, então fixe o fuso em UTC
quando você mesmo escrever o instante. O cenário pronto já traz um instante UTC absoluto e não
precisa de fuso.
# O cenário: a sessão começa no próprio limite, 03:14:07 UTC chrono run "C:\apps\test.exe" --preset year-2038 --report session.txt # Começar dezessete segundos antes e deixar o aplicativo cruzá-lo ao vivo chrono run "C:\apps\test.exe" --at 2038-01-19T03:13:50 --zone +00:00 --report session.txt # Começar antes e rodar a velocidade x60 - o limite chega em cerca de 14 segundos chrono run "C:\apps\test.exe" --at 2038-01-19T03:00:00 --zone +00:00 --mode x60 # Ou rodar com a data de hoje e saltar por cima dele com o aplicativo aberto chrono run "C:\apps\test.exe" --jump-after 5:2038-01-19T03:14:05 --zone +00:00
Um segundo depois do limite, um contador de 32 bits com sinal passa a -2.147.483.648, que se lê como 13 de dezembro de 1901, 20:45:52 UTC. Uma data de 1901, um número negativo, um item que de repente expirou ou foi para o início da ordenação, uma exceção lançada pelo código de datas - é assim que o estouro aparece visto de fora.
Colocar o relógio real em 2038 é a outra forma de chegar aqui, e a que mais quebra coisas. O que acontece quando você altera a data do sistema →
Conferindo que chegou ao programa
Um teste que passa porque o programa nunca viu 2038 é pior que nenhum teste. O relatório no fim de cada sessão diz qual relógio o programa leu e quantas vezes:
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)
A linha session confirma que o relógio do aplicativo passou do limite. Um veredito works com contagens de chamadas significa que o programa leu o relógio e recebeu a data de 2038; works partially nomeia os canais que ele leu por outro caminho. O que significam os vereditos →
O que um teste aprovado não prova
- Só o relógio do próprio programa se moveu. Uma data que ele carrega de um
arquivo ou de um banco de dados é a que está gravada lá, então uma data de 2038 dentro dos dados
é outro teste. A calculadora de datas calcula essas datas para você:
chrono calc --base 2038-01-19T03:14:07 --zone +00:00 --shift +1s - Um servidor com o qual o programa conversa continua na data real. Um limite de 32 bits desse lado está fora do alcance, e a sessão avisa quando vê o programa abrir uma conexão de rede.