Playstation 3 e o bug do ano bissexto

Em 04/03/2010, em Linguagem C, Segurança, por Sergio Prado

Como profis­sional da área de tec­nolo­gia, sou um leitor assí­duo de notí­cias da área. Gosto em espe­cial de dois sites, o Giz­modo e o Engad­get. Na segunda pela manhã uma notí­cia me chamou a atenção, mil­hões de videogames PlaySta­tion 3 da Sony haviam parado de fun­cionar da noite para o dia.

No decor­rer do dia, descobriu-se que o prob­lema estava no reló­gio interno do apar­elho, que iden­ti­fi­cou 2010 como um ano bis­sexto, e pas­sou do dia 28/02 para 29/02 ao invés de 01/03. Como diver­sas funções do videogame depen­diam do valor cor­reto da data do sis­tema para fun­cionar, o apar­elho começou a apre­sen­tar vários problemas.

Mas antes de falar mais sobre este prob­lema, vamos anal­isar um caso mais antigo, de 2008, do media player portátil Zune da Microsoft.

O caso Zune

No dia 31/12/2008, todos os Zune’s mod­elo 30G reini­cia­ram soz­in­hos e travaram no processo de boot do equipa­mento. Fontes descrevendo o prob­lema podem ser encon­tradas aqui e aqui.

Descobriu-se depois que o prob­lema foi cau­sado por um bug no dri­ver do reló­gio interno do equipa­mento, especi­fi­ca­mente no trata­mento de anos bis­sex­tos. A solução dada pela Microsoft era esperar até o fim do dia, que “mila­grosa­mente” o prob­lema se resolvia sozinho.

Este prob­lema cau­sou um barulho imenso. Mais tarde descobriu-se que o Zune usa um chip de RTC (Real-Time Clock) da Freescale, e o código-fonte do dri­ver deste chip é aberto e disponível para down­load. Uma cópia dos fontes do dri­ver pode ser aces­sada aqui.

O código-fonte foi anal­isado e o tre­cho do código com o prob­lema foi identificado:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    year = ORIGINYEAR; /* = 1980 */
 
    while (days > 365)
    {
        if (IsLeapYear(year))
        {
            if (days > 366)
            {
                days -= 366;
                year += 1;
            }
        }
        else
        {
            days -= 365;
            year += 1;
        }
    }

O obje­tivo deste tre­cho de código é cal­cu­lar o ano atual. Ele usa a vari­avel “days” que pos­sui a quan­ti­dade de dias deste 01/01/1980, e cal­cula a quan­ti­dade de anos a par­tir de “days”, armazenando o resul­tado em “years”.

Em cir­cun­stân­cias nor­mais, o código exe­cuta sem prob­le­mas. Porém existe uma situ­ação onde é ano bis­sexto (linha 5) porém “days” não é maior do que 366 (linha 7). Ou seja, o fluxo de exe­cução cai den­tro do if da linha 5 mas não cai no if da linha 7, e isso faz com que o código entre em um loop infinito. Como este código é exe­cu­tado no boot, o dis­pos­i­tivo trava. Esta situ­ação acon­tece sem­pre que é ano bis­sexto e último dia do ano, no nosso caso — 31/12/2008.

A cor­reção é sim­ples, e uma pos­sível solução é inserir uma condição de “else” após a linha 11 do código acima, con­forme abaixo:

1
2
3
4
5
6
7
8
9
10
11
........
             if (days > 366)
             {
                 days -= 366;
                 year += 1;
             }
             else
             {
                 break;
             }
........

Pode­ria este erro ter sido evi­tado? Com testes sim­ples, é bem provável que não, já que envolve uma situ­ação bem especí­fica (último dia de um ano bis­sexto). Com um bom code review, provavel­mente sim. Com testes mais com­ple­tos, pre­vendo todas as situ­ações, com certeza o bug seria identificado.

Aparente­mente, este é um dri­ver antigo e não existe uma cor­reção da Freescale. Então, se você tem um Zune, no dia 31/12/2012, desligue-o, vá para um mosteiro bud­ista e relaxe!

Voltando ao caso do PS3

Este é bem mais recente, na pas­sagem do último domingo (28/02/2010) para segunda-feira (01/03/2010) cerca de 24 mil­hões de apar­el­hos PS3 pararam de fun­cionar, e apre­sen­taram os seguintes sintomas:

  1. Não se conec­tavam à rede (PSN — PlaySta­tion Network).
  2. Alguns jogos não fun­cionavam, nem mesmo em modo offline (usando os disco ao invés de jogos baixados).
  3. Não era pos­sível con­fig­u­rar a data/hora do equipamento.

Foi um caos. A Sony deixou muitos pre­ocu­pa­dos sem dar notí­cias por algu­mas horas. E então no meio do dia foi divul­gado um comu­ni­cado pela própria Sony de que o prob­lema havia sido iden­ti­fi­cado. Havia um bug no dri­ver do rel­o­gio interno do equipa­mento, que estava recon­hecendo 2010 como um ano bis­sexto! Ou seja, de 28/02/2010, em vez de ir para 01/03/2010, foi para 29/02/2010!

A Sony pas­sou instruções para os usuários não lig­aram o apar­elho durante todo o dia, e de que no dia seguinte o sis­tema se nor­malizaria, e isso real­mente aconteceu.

Mas como uma gigante como a Sony deixou que isso acon­te­cesse? Um erro em uma rotina tão básica. Como desen­volve­dor, fiquei imag­i­nando o que pode­ria ter acon­te­cido com a rotina de ano bis­sexto deles. Escrevi a minha (abaixo), e fiquei imag­i­nando onde eles pode­riam ter errado.

1
2
3
4
5
6
7
int anoBissexto(int ano)
{
    if( (ano % 400 == 0) || (ano % 4 == 0 && ano % 100 != 0) )
        return 1;
    else
        return 0;
}

Sabe­mos que um ano é bis­sexto se:

  1. É divi­sivel por 400, ou
  2. É divisível por 4 mas não por 100, ou
  3. É ano de olimpíadas

OK, o item 3 é brin­cadeira, ape­sar de ser ver­dade…:) Pen­sando bas­tante, cheguei a uma conclusão.

É bem provável que exista um bug no código deles onde todo ano par é con­sid­er­ado bis­sexto. Como o con­sole foi lançado no final de 2006, este ano não foi prob­lema. Como 2008 era um ano bis­sexto, tam­bém não foi prob­lema. E agora em 2010 foi a primeira “aparição” deste prob­lema. É claro que isso é só uma espec­u­lação minha, já que não tenho os fontes, e não vejo nen­huma outra lóg­ica para isso ter acon­te­cido. De qual­quer forma, só pra previnir, em ano de Copa do Mundo, não liguem o PS3 no dia 1 de março!

É tam­bém inter­es­sante notar aqui como um prob­lema sim­ples e local­izado de cál­culo de ano bis­sexto pode prej­u­dicar o fun­ciona­mento básico do equipa­mento e impactar mil­hões de pes­soas ao redor do mundo. Além é claro de man­char um pouco a imagem da empresa. E isso acon­te­ceu com três grandes empre­sas de tec­nolo­gia (Microsoft, Freescale e Sony).

OK, somos propen­sos a erros, mas é por isso que exis­tem os proces­sos de qual­i­dade. Para garan­tir que, em primeiro lugar, nao colo­que­mos bugs no código, e se isso acon­te­cer, que estes erros sejam iden­ti­fi­ca­dos o cor­rigi­dos antes de chegar ao mercado.

Mas infe­liz­mente os proces­sos de qual­i­dade brigam às vezes com coisas como pra­zos aper­ta­dos e time-to-market, e nós desen­volve­dores acabamos “pagando o pato” pelos prob­le­mas que pode­riam ter sido evi­ta­dos. Mas mesmo isso não tira de nós a respon­s­abil­i­dade de desen­volver um pro­jeto de qualidade.

Um abraço a todos,

Ser­gio Prado

VN:F [1.9.13_1145]
Rat­ing: 0.0/10 (0 votes cast)

Sem posts relacionados.

Tags:  
  • jose

    casos de testes resolve­riam metade dos prob­le­mas de desen­volvi­mento de soft­ware. prazo curto? corte os testes!

    VA:F [1.9.13_1145]
    Rating: 0.0/5 (0 votes cast)
  • Felipe

    Parabéns Serginho pelo exce­lente post…

    VA:F [1.9.13_1145]
    Rating: 0.0/5 (0 votes cast)
  • http://DiarioDeCodigos.info Alexan­dre Santos

    Exce­lente! con­tinue assim! to gostando muito dos seus posts, bem expli­ca­dos e objetivos.

    Abraços!

    VA:F [1.9.13_1145]
    Rating: 0.0/5 (0 votes cast)
  • Cor­rine Mangiamele

    Muito inter­es­sante… Parabens pelo site. =]

    VA:F [1.9.13_1145]
    Rating: 0.0/5 (0 votes cast)
  • http://www.fdavid.com.br Fran­cis David

    time-to-market sem­pre passo por isso, solu­cao, coloca no mer­cado e vai cor­rigindo bugs con­forme vao apare­cendo :-/

    VA:F [1.9.13_1145]
    Rating: 0.0/5 (0 votes cast)
  • Thi­ago

    muito bom o artigo! con­tinue escrevendo por favor rsrs
    abraco

    VA:F [1.9.13_1145]
    Rating: 0.0/5 (0 votes cast)