Hi, All!
У некоторых (очень редких) пользователей падает _примерно_ вот такой код:
tm theTime;
ZeroMemory(&theTime, sizeof(theTime));
theTime.tm_sec=0 ;
theTime.tm_min=0 ;
theTime.tm_hour=10 ;
theTime.tm_mday=1 ;
theTime.tm_year=70 ;
theTime.tm_wday=0 ;
theTime.tm_yday=0 ;
theTime.tm_isdst=-1;
DWORD dwBuffer = mktime(&theTime);
Текст ашипки:
AppName: test.exe AppVer: 0.0.0.0 ModName: msvcrt.dll
ModVer: 7.0.2600.2180 Offset: 0003ae80
Причем падает оно именно на mktime. Приложение — VC++ 6.0 / MFC, операционка у пользователя, судя по всему, XP. Пойти на компьютер пользователя и посмотреть, что происходит, не получается из-за физической удаленности (Австралия); у нас у самих не воспроизводится.
Что может быть не так? Исходники тестового проекта (там код немножко не такой, в этом сообщении я упростил для лучшего восприятия) на
www.sushko.ru/mktime.zip (23K).
04.08.06 02:34: Перенесено модератором из 'C/C++' — Павел Кузнецов
Здравствуйте, sushko, Вы писали:
S>Hi, All!
S>У некоторых (очень редких) пользователей падает _примерно_ вот такой код:
S>tm theTime;
S>ZeroMemory(&theTime, sizeof(theTime));
S>theTime.tm_sec=0 ;
S>theTime.tm_min=0 ;
S>theTime.tm_hour=10 ;
S>theTime.tm_mday=1 ;
S>theTime.tm_year=70 ;
S>theTime.tm_wday=0 ;
S>theTime.tm_yday=0 ;
S>theTime.tm_isdst=-1;
S>DWORD dwBuffer = mktime(&theTime);
Фул стоп.
Я правильно понимаю, что это 70 год?
А на других годах не падает?
У меня линух, так что проверить на месте не смогу, но есть подозрение, что т.к. (месяц-то кстати, какой?) в январе тут как раз лето, то в абсолюте с Гривичем получается 11 часов разницы, т.е. возможно что-то в недрах виндовса вылезает в 69 год, чему несказанно удивляется и падает нафиг
Здравствуйте, Alexey Frolov, Вы писали:
S>>Причем падает оно именно на mktime. Приложение — VC++ 6.0 / MFC, операционка у пользователя, судя по всему, XP. Пойти на компьютер пользователя и посмотреть, что происходит, не получается из-за физической удаленности (Австралия); у нас у самих не воспроизводится.
AF>Видел код, в подробности не вдавался, но скомпилял, запустил. Ничего не падает в обычном режиме, ни debug ни release, ни на xp, ни на 2k3. Но поменяв на xp часовой пояс на +10 melburne sydney, тут же получил падение. На 2k3 такого эффекта не было. Так что меняйте пояс на xp и дебаггер в зубы. Удачи. Отпишите чем эпопея закончится, интересно все таки в чем дело
Ага, точно, после смены часового пояса release на XP падает как часы
. Спасибо! Будем разбираться; результат обязательно сообщу
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$, в очередной раз испортили день и отняли веру в прекрасное...