Arithmetic Overflow
Дивна бага переслідувала Stargazer протягом останніх 2-3 версій. Для деяких користувачів через певний час переставала працювати авторизація. При чому лікувалось це тільки рестартом демона. І дедлоки тут не винні - бо авторизацією займається лише одна "нитка", і якби стався дедлок - ніхто б не зміг авторизуватись. При чому відтворити проблему у себе ні я, ні Боря не змогли. Лише 1 раз я зміг проспостерігати її, коли займався налаштуванням авторизації 802.1x у Fort-DKS. Я швиденько додав verbosity (не зміг відтворити українською) до логу, але бага зникла.
Вчора один із користувачів системи зміг отримати лог зміни фаз в процесі виникнення багу і надіслав його мені. Помилка виявилась банальною: часові проміжки ми обчислювали у мікросекундах, використовуючи функцію gettimeofday (жахлива назва). Код був приблизно такий:
int64_t newTime = newPhaseTime.tv_sec * 1000000 + newPhaseTime.tv_usec;
int64_t oldTime = oldPhaseTime.tv_sec * 1000000 + oldPhaseTime.tv_usec;
int64_t dt = newTime - oldTime;
А тепер подумаємо. Скоро наступає *nix-апокаліпсис (а-ля "помилка 2000 року" для timestamp). time_t у нас, зазвичай, 32-бітний. Максимальне значення int64_t - 2^32 - 1. Візьмемо якесь число, близьке до 4 мільярдів (1 218 702 861, вчора міряв) та ще помножимо його на 1e6. Маємо 1e15, що значно перевищує верхню межу int32_t. От вам і арифметичне переповнення! І коли виникає ситуація, що oldTime стає від'ємним - юзер "зависає".
Сьогодні переписав часову арифметику. На тестах, поки що, все в порядку. Ввечері віддам на суд ком'юніті.
Вчора один із користувачів системи зміг отримати лог зміни фаз в процесі виникнення багу і надіслав його мені. Помилка виявилась банальною: часові проміжки ми обчислювали у мікросекундах, використовуючи функцію gettimeofday (жахлива назва). Код був приблизно такий:
int64_t newTime = newPhaseTime.tv_sec * 1000000 + newPhaseTime.tv_usec;
int64_t oldTime = oldPhaseTime.tv_sec * 1000000 + oldPhaseTime.tv_usec;
int64_t dt = newTime - oldTime;
А тепер подумаємо. Скоро наступає *nix-апокаліпсис (а-ля "помилка 2000 року" для timestamp). time_t у нас, зазвичай, 32-бітний. Максимальне значення int64_t - 2^32 - 1. Візьмемо якесь число, близьке до 4 мільярдів (1 218 702 861, вчора міряв) та ще помножимо його на 1e6. Маємо 1e15, що значно перевищує верхню межу int32_t. От вам і арифметичне переповнення! І коли виникає ситуація, що oldTime стає від'ємним - юзер "зависає".
Сьогодні переписав часову арифметику. На тестах, поки що, все в порядку. Ввечері віддам на суд ком'юніті.