S>>>Причем падает оно именно на mktime. Приложение — VC++ 6.0 / MFC, операционка у пользователя, судя по всему, XP. Пойти на компьютер пользователя и посмотреть, что происходит, не получается из-за физической удаленности (Австралия); у нас у самих не воспроизводится.
AF>>Видел код, в подробности не вдавался, но скомпилял, запустил. Ничего не падает в обычном режиме, ни debug ни release, ни на xp, ни на 2k3. Но поменяв на xp часовой пояс на +10 melburne sydney, тут же получил падение. На 2k3 такого эффекта не было. Так что меняйте пояс на xp и дебаггер в зубы. Удачи. Отпишите чем эпопея закончится, интересно все таки в чем дело
S>Ага, точно, после смены часового пояса release на XP падает как часы . Спасибо! Будем разбираться; результат обязательно сообщу
В общем, если кому интересно — бага в crt. Связанная с летним временем. В отличие от почти всех нормальных стран, в Австралии 1.1.1970 неожиданно было ... лето
Поэтому crt неправильно считает range и впоследствии вываливается (подробности мне уже было выяснять лениво, поскольку задача фиксить crt не стояла). Примерно там вот что:
78029019 a120e80378 mov eax,[MSVCRT!_dstbias (7803e820)]
7802901e 014508 add [ebp+0x8],eax
78029021 8d4508 lea eax,[ebp+0x8]
78029024 50 push eax
78029025 e8e4fcffff call MSVCRT!localtime (78028d0e)
7802902a 59 pop ecx
7802902b 6a09 push 0x9
7802902d 8bf0 mov esi,eax
7802902f 8b4508 mov eax,[ebp+0x8]
78029032 59 pop ecx
78029033 f3a5 rep movsd ds:00000000=???????? es:0012ff04=00000000
В crt это соответствует этому кусочку:
if ( (tb->tm_isdst > 0) || ((tb->tm_isdst < 0) &&
(tbtemp->tm_isdst > 0)) ) {
tmptm1 += _dstbias;
tbtemp = localtime(&tmptm1); /* reconvert, can't get NULL */
}
}
else {
if ( (tbtemp = gmtime(&tmptm1)) == NULL )
goto err_mktime;
}
/***** HERE: tmptm1 holds number of elapsed seconds, adjusted *****/
/***** for local time if requested *****/
*tb = *tbtemp;
Соответственно, обламывает всю малину localtime, возвращая NULL, несмотря на горячее пожелание ей не делать этого хлопцев из m$ в комментах. Молодцы, умеют.
Ну и был придуман следующий ход — для даты 1.1.1970 день увеличивался на единичку, затем из результата вычиталось 3600*24 (естественно, с контролем переполнения). Помогло
Кстати, по пути же еще нашлись несколько неприятных багов в дебажных версиях crt — они неправильно летнее время учитывают для различных часовых поясов. Видимо, в более позднем рантайме (релизный рантайм crt вышел гораздо после 6-ки) это дело поправили. А вообще, функции виндовс работы со временем — это просто песня
Оказалось, что и они весьма "специфично" работают со временем — например, GetDateFormat\GetTimeFormat и, похоже, вообще все функции работы со временем, считают летнее время не от обрабатываемой даты, а от текущей. В результате получаются феерические эффекты
Спасибо m$, в очередной раз испортили день и отняли веру в прекрасное...