domingo, 16 de dezembro de 2007

Primeiro foi em 2000.... agora em 2038

Hoje um post no blog Nerdson.com, me deixou curioso sobre a mais nova catástrofe antecipada, o bug do ano 2038.

Porem, antes de falar sobre o ano 2038, vamos relembrar o do ano 2000. O que foi aquilo? Além de um escândalo em massa criado pelas agências de notícias? =]

Qual era o problema naquela época (meu deus, falando assim, até me sinto velho.. well, eu tinha... 11 anos)? Simples, alguns aplicativos quando calculavam a data, calculavam apenas os dois últimos dígitos do ano. Então era 19 + [DOIS DÍGITOS]. Claro, só uma besta quadrada não sabia que isso não era bom. Então, o que fazer? Muitos programadores já tinham empregado seus PoGs e o aplicativo simplesmente não iria crashar e destruir tudo de uma hora para a outra. Era apenas um problema lógico a ser arrumado. Mesmo assim foi anunciado como uma catástrofe mundial da virada do milênio. Bem, acho que na idade média as pessoas também tiveram medo quando teve a virada de ano de 999 para 1000, vai que os moinhos, enxadas e cavalos parassem com uma BSOD =/
(E aquilo deixou uma criança de 11 anos muito triste que ficou esperando a virada do ano... e... nada aconteceu ¬¬' Que chato!)

Enfim... voltando ao ano 2007. Ou melhor, vamos entender o problema do ano 2038. Este problema esta principalmente sendo discutido em ambientes unix-like, ou seja, Unixes, Linuxes, BSDs, etc...
Nestes sistemas, temos uma estrutura chamada time_t que é responsável pela representação do tempo.

O tempo atual é calculado, somando-se o valor desta variável a seguinte data: 01 de Janeiro de 1970 00:00.

Porém, temos 2 problemas:
1)Esta variável é do tipo signed int. Ou seja, 1 bit é reservado para o sinal.
2)A maioria dos sistemas hoje ainda é 32 bits. Ou seja, o valor máximo que pode ser armazenado nesta estrutura é 2^31. (O último bit foi para o sinal =])

Então, 2^31 nos dá 2,147,483,648 segundos... o que nos leva a aproximadamente 68 anos. Mais precisamente, 68 anos, 19 dias, 3 horas, 14 minutos e 7 segundos.

Mas o que acontece quando somamos + 1 aqui? Bem, temos o que é conhecido como integer overflow. Ou seja, o bit de sinal é ativado e o resto todo é zerado. Sim, isso vai dar merda capitão.

O site http://www.deepsky.com/~merovech/2038.html fez um teste de simulação em um Debian GNU/Linux (kernel 2.4.22) e obteve o seguinte resultado:
Terça, 19 de Janeiro de 2038 03:14:01
Terça, 19 de Janeiro de 2038 03:14:02
Terça, 19 de Janeiro de 2038 03:14:03
Terça, 19 de Janeiro de 2038 03:14:04
Terça, 19 de Janeiro de 2038 03:14:05
Terça, 19 de Janeiro de 2038 03:14:06
Terça, 19 de Janeiro de 2038 03:14:07 (time_t em 32 bits está em seu maior valor possível)
Sexta, 13 de Dezembro de 1901 20:45:52
Sexta, 13 de Dezembro de 1901 20:45:52
Sexta, 13 de Dezembro de 1901 20:45:52

Em um Windows 2000, era mais legal ainda, depois da data limite, não imprimiu mais nada.

Como pode ver... no good!
Será que teremos notícias falando sobre o bug da Sexta-Feira 13? :P


Além disso, hoje já enfrentamos outro problema. Se desejarmos calcular o tempo médio entre 2 datas em sistemas 32 bits, normalmente seria feito (t1 + t2)/2.
Mas quando t1 + t2 for somado, e os dois tiverem o 31º bit como 1, ou então houver carry, pode acontecer o problema de overflow e obtermos um tempo negativo! Bem, isto pode ser facilmente contornado com algumas soluções simples, 2 delas demonstradas pelo site http://www.2038bug.com/index.html:
1)Utilizando-se type-casting, assim: (((long long) t1 + t2) / 2), padrão POSIX/SuS ou (((double) t1 + t2) / 2), padrão ANSI.
2)Utilizando a seguinte conta, indicada por Brian Shand: (t1/2 + t2/2 + (t1&t2&1)).

Eu pessoalmente acho que prefiro a segunda.

Bem, mas como isto pode ser resolvido?
1) Transformando o time_t em um unsigned int, assim teríamos 1 bit a mais. Ou seja, teríamos mais 68 anos para pensar em como arrumar isso. Mas temos um problema, o time_t também é usado para calcular diferença entre datas. Para saber se uma data veio antes de outra por exemplo. Então, não poderíamos simplesmente tirar o bit de sinal dele

2)Passando-se a utilizar ints de 64 bits (long ints em sistemas de 32 bits). Bem não podemos de uma hora para outra simplesmente alterar o tipo do time_t, isso irá quebrar a compatibilidade com muitos softwares existentes. E ficar usando type-casting no programa inteiro deve ser um saco.

A solução mais viável é a utilização de sistemas de 64 bits, que utilizam time_t de 64 bits por padrão. Eu REALMENTE creio que 30 anos seja tempo suficiente para a maioria das máquinas estarem rodando sistemas operacionais de 64 bits. Uma preocupação são com os sistemas embarcados... bem, alguns até hoje são de 8 ou 16 bits... então creio que a preocupação com eles seja um caso a parte. Além disso, o tempo médio de atualização de um sistemas desse é de 18 a 24 meses.
De qualquer forma, conforme-se, o seu IPOD e o seu celular que toca MP3 podem parar de funcionar em 2038. Eu sugiro que você vá fazendo seu pé de meia (a, vamos la, são 30 anos... se você juntar 10 centavos por dia, terá 1.000 reais no final) para comprar seu celular novo.

Para efeitos de curiosidade, um sistema de 64 bits, guardando até 2^63 bits, poderia armazenar 9,223,372,036,854,775,808 segundos, o equivalente a aproximadamente 292 bilhões de anos, 22 vezes a idade do universo. Se até lá, alguem se preocupar e os sistemas já forem em 128 bits, ou seja, o time_t armazenaria até 2^127, isto da 170,141,183,460,469,231,731,687,303,715,884,105,728 segundos. Bem deixo para vocês calcularem isso.


O site www.howstuffworks.com informa alguns outros dados:
Em PCs IBM, o início é em 1 de Janeiro de 1980, e é utilizado um unsigned int de 32 bits. Por volta de 2116 o integer ira sofrer overflow.
O WindowsNT utiliza um int de 64 bits para armazenar a contagem do tempo. Porem ele utiliza incremento de 100 nano segundos e a data inicial é em 1 de Janeiro de 2006. Por volta de 2184 o NT sofreria o problema de overflow.
Em um link - quebrado ¬¬' - a Apple afirma que o Mac suporta até o ano 29,940.

E alguns, já começaram o artigo na Wikipedia sobre o bug do ano 10.000.


Referências:

The Year-2038 Bug:
http://www.2038bug.com/index.html
The Year 2038 Bug and Common Solution:
http://www.gsp.com/2038/
The Project 2038 Frequently Asked Questions (FAQ):
http://www.deepsky.com/~merovech/2038.html
The Year 2038 Problem:
http://pw1.netcom.com/~rogermw/Y2038.html
HowStuffWorks: What is the Year 2038 problem?
http://www.howstuffworks.com/question75.htm
Wikipédia - Year 2038 problem
http://en.wikipedia.org/wiki/Year_2038_problem
Wikipédia - Problema do ano 2038:
http://pt.wikipedia.org/wiki/Problema_do_ano_2038
Wikipédia - Bug do milênio:
http://pt.wikipedia.org/wiki/Bug_do_mil%C3%AAnio
Wikipédia - Year 10,000 problem:
http://en.wikipedia.org/wiki/Year_10%2C000_problem

2 comentários:

Anônimo disse...

Nossa, tu foi longe hein, maluco?!
Nerd demais :)

Felipe Luchi disse...

muito interessante o artigo...
vlws
[]'s