Bug afeta todas as distros

Quer ver se o seu Linux tem o bug? Digite no terminal: "date -d 01/19/2038". Veja o resultado e depois digite: "date -d 01/20/2038". Quer concertar? Veja o artigo.

[ Hits: 18.198 ]

Por: M4iir1c10 em 04/03/2008 | Blog: https://github.com/mauricioph


A solução



Esse é um programa que deve ser colocado na pasta /bin após a compilação, ao criar um programa que se baseie em tempo envés de usar a função gmtime(), você deve escrever o seu código com privotal_gmtime().

/*bug 2038 vai acontecer em 19 de Janeiro de 2038*/

const char pivotal_gmtime_r_stamp[] =
    "pivotal_gmtime_r. Copyright (C) 2005  Paul Sheer. Terms and "
    "conditions apply. Visit http://2038bug.com/ for more info.";

/*

pivotal_gmtime_r() retorna o mesmo resultado que gmtime() até 19 de Janeiro de 2038,  a partir daí o resultado será o esperado e não haverá o retorno para 01 de Janeiro de 1901.

*/


#include <stdlib.h>
#include <stdio.h>
#include <time.h>

static const int days[4][13] = {
    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
    {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
};

#define LEAP_CHECK(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0)
#define WRAP(a,b,m) ((a) = ((a) <  0  ) ? ((b)--, (a) + (m)) : (a))

long long pivot_time_t (const time_t * now, long long *_t)
{
    long long t;
    t = *_t;
    if (now && sizeof (time_t) == 4) {
        time_t _now;
        _now = *now;
        if (_now < 1106500000 /* Jan 23 2005 - date of writing */ )
            _now = 2147483647;
        if ((long long) t + ((long long) 1 << 31) < (long long) _now)
            t += (long long) 1 << 32;
    }
    return t;
}

static struct tm *_gmtime64_r (const time_t * now, long long *_t, struct tm *p)
{
    int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday, v_tm_tday;
    int leap;
    long long t;
    long m;
    t = pivot_time_t (now, _t);
    v_tm_sec = ((long long) t % (long long) 60);
    t /= 60;
    v_tm_min = ((long long) t % (long long) 60);
    t /= 60;
    v_tm_hour = ((long long) t % (long long) 24);
    t /= 24;
    v_tm_tday = t;
    WRAP (v_tm_sec, v_tm_min, 60);
    WRAP (v_tm_min, v_tm_hour, 60);
    WRAP (v_tm_hour, v_tm_tday, 24);
    if ((v_tm_wday = (v_tm_tday + 4) % 7) < 0)
        v_tm_wday += 7;
    m = (long) v_tm_tday;
    if (m >= 0) {
        p->tm_year = 70;
        leap = LEAP_CHECK (p->tm_year);
        while (m >= (long) days[leap + 2][12]) {
            m -= (long) days[leap + 2][12];
            p->tm_year++;
            leap = LEAP_CHECK (p->tm_year);
        }
        v_tm_mon = 0;
        while (m >= (long) days[leap][v_tm_mon]) {
            m -= (long) days[leap][v_tm_mon];
            v_tm_mon++;
        }
    } else {
        p->tm_year = 69;
        leap = LEAP_CHECK (p->tm_year);
        while (m < (long) -days[leap + 2][12]) {
            m += (long) days[leap + 2][12];
            p->tm_year--;
            leap = LEAP_CHECK (p->tm_year);
        }
        v_tm_mon = 11;
        while (m < (long) -days[leap][v_tm_mon]) {
            m += (long) days[leap][v_tm_mon];
            v_tm_mon--;
        }
        m += (long) days[leap][v_tm_mon];
    }
    p->tm_mday = (int) m + 1;
    p->tm_yday = days[leap + 2][v_tm_mon] + m;
    p->tm_sec = v_tm_sec, p->tm_min = v_tm_min, p->tm_hour = v_tm_hour,
        p->tm_mon = v_tm_mon, p->tm_wday = v_tm_wday;
    return p;
}

struct tm *gmtime64_r (const long long *_t, struct tm *p)
{
    long long t;
    t = *_t;
    return _gmtime64_r (NULL, &t, p);
}

struct tm *pivotal_gmtime_r (const time_t * now, const time_t * _t, struct tm *p)
{
    long long t;
    t = *_t;
    return _gmtime64_r (now, &t, p);
}

long long mktime64 (struct tm *t)
{
    int i, y;
    long day = 0;
    long long r;
    if (t->tm_year < 70) {
        y = 69;
        do {
            day -= 365 + LEAP_CHECK (y);
            y--;
        } while (y >= t->tm_year);
    } else {
        y = 70;
        while (y < t->tm_year) {
            day += 365 + LEAP_CHECK (y);
            y++;
        }
    }
    for (i = 0; i < t->tm_mon; i++)
        day += days[LEAP_CHECK (t->tm_year)][i];
    day += t->tm_mday - 1;
    t->tm_wday = (int) ((day + 4) % 7);
    r = (long long) day *86400;
    r += t->tm_hour * 3600;
    r += t->tm_min * 60;
    r += t->tm_sec;
    return r;
}

static struct tm *THIS_FUNCTION_DOES_NOT_WORK_FOR_DAYLIGHT_SAVINGS_localtime64_r (const time_t * now, long long *_t, struct tm *p)
{
    long long tl;
    time_t t;
    struct tm tm, tm_localtime, tm_gmtime;
    _gmtime64_r (now, _t, &tm);
    if (tm.tm_year > (2037 - 1900))
        tm.tm_year = 2037 - 1900;
    t = mktime64 (&tm);
    localtime_r (&t, &tm_localtime);
    gmtime_r (&t, &tm_gmtime);
    tl = *_t;
    tl += (mktime64 (&tm_localtime) - mktime64 (&tm_gmtime));
    _gmtime64_r (now, &tl, p);
    p->tm_isdst = tm_localtime.tm_isdst;
    return p;
}

struct tm *pivotal_localtime_r (const time_t * now, const time_t * _t, struct tm *p)
{
    long long tl;
    tl = *_t;
    return _localtime64_r (now, &tl, p);
}

struct tm *localtime64_r (const long long *_t, struct tm *p)
{
    long long tl;
    tl = *_t;
    return _localtime64_r (NULL, &tl, p);
}

E isso aí pessoal, um grande abraço do seu amigo Mauricio.



Página anterior    

Páginas do artigo
   1. Explicação
   2. A solução
Outros artigos deste autor

Colocando Windows, Linux e Mac Os X em um mesmo PC

Instalando Beryl no Windows XP

Proteção de tela ou vídeo como papel de parede

5 comandos que ninguém nunca deve executar no Linux

GRUB com imagens aleatórias e KDM com vídeo de fundo

Leitura recomendada

A mágica do polimorfismo e seus conceitos na ótica de C/C++

SDL e C - Uma dupla sensacional

Instalando Facebook Folly através do Conan

Tratamento de exceções na linguagem C

Estudando recursividade direta e indireta

  
Comentários
[1] Comentário enviado por elgio em 04/03/2008 - 10:42h

Parabéns pela didática!
Excelente!

Me fez lembrar do bug que a primeira versão do NT tinha: eles usaram uma variável de 32 bits para contar o número de milisegundos que a máquina estava ligada. Em 49 dias esta variável entrava em overflow e o computador se resetava :-O

Mas não se preocupem, foi sem impacto. Ninguém conseguia ficar com um Windows tanto tempo ligado sem ter que reiniciá-lo por outros motivos :-D

hehehehe

[2] Comentário enviado por hellnux em 04/03/2008 - 10:47h

Opa,

Interessante o artigo. No BUG de 2000 nem conhecia Linux e nem windows direito.... e do NT nem sabia x]

Vi algo que pode estar errado, acho que seja assim:

0 = 000
1 = 001
2 = 010
3 = 011
4 = 100
5 = 101

[]´s

[3] Comentário enviado por hlegius em 04/03/2008 - 11:11h

Em 64bits parece que o erro não ocorre mais ...

[[email protected] ~]$ date -d 01/19/2038
Ter Jan 19 00:00:00 BRST 2038
[[email protected] ~]$ date -d 01/20/2038
Qua Jan 20 00:00:00 BRST 2038

Acho que a limitação está na plataforma 32bits...

[4] Comentário enviado por m4tri_x em 04/03/2008 - 11:15h

Valeuu...

[]´s

[5] Comentário enviado por M4iir1c10 em 04/03/2008 - 11:41h

Obrigado pela dica hlegius, eu esqueci de colocar esse detalhe no artigo o bug e em plataformas 32bits.

hellnux esse sitema binario e coisa de computador mesmo... olha so eu erei uma conta de 1 a 5, k-ra-k.... valeu pela correcao.

[6] Comentário enviado por removido em 04/03/2008 - 11:56h

gostei cara,
muito interessante !!!!!!!!!!!!!!!!!!

[7] Comentário enviado por Teixeira em 04/03/2008 - 13:19h

Valeu, muito bom o artigo.
O que eu iria comentar os colegas já comentaram.
( Tá passeando em Sydney? "Gudái, máite!..." Tem "snáiks" por aí?... hehehe!)

[8] Comentário enviado por removido em 04/03/2008 - 14:36h

só uma observação gramatical na introdução...

Seria Consertar, Concertar vêm de Concerto, de Orquestra, música e tal. =)

[9] Comentário enviado por removido em 04/03/2008 - 18:59h

Convenhamos, né cambada... A gente nem sabe se daqui a 32 anos a informática base-ar-se-á (gostaram ?????) em 111110000 e, então, sem exageros.....

Agora, que ficou um muuuuuuuust os códigos mudando constantemente na página, isso ficou..


Aaaaaaaaiiiiiiiiiiiiiii, gamei!!! ;-)

[10] Comentário enviado por M4iir1c10 em 05/03/2008 - 07:48h

Desculpe Rodrigo Campelini mais eu escrevi consertar ou concertar? Eu acho que foi com s e nao com c... qual eu devo usar ? Desculpem pelos erros ja tem um tempo que eu estou sem falar portugues, ai ja viu ne? o verbo to be em portugues "Eu estarei indo comprar chocolate"...rsrsrs


Contribuir com comentário