Один простой, но эффективный отладочный прием
22 ноября 2021
Бывает так, что ошибка в коде воспроизводится лишь при определенном стечение обстоятельств. Эти обстоятельства могут быть довольно сложными, особенно если приложение распределенное и каждый его экземпляр состоит из N процессов. Подцепиться отладчиком к правильному процессу в правильный момент времени практически невозможно. В подобных случаях я использую один незамысловатый прием, речь о котором и пойдет далее.
Идея очень простая. Она заключается в модификации кода приложения так, чтобы он сам определял возникновение ошибки, сигнализировал об этом, а потом ждал, когда программист придет с отладчиком. Рассмотрим упрощенный пример:
#include <unistd.h>
int main() {
/* if( some condition violated ) { */
int ret;
printf("Attach with the debugger, pid = %d\n", getpid());
do {
ret = sleep(1);
} while(ret == 0);
/* } */
printf("sleep() returned %d\n", ret);
return 0;
}
В реальном коде вместо printf(...)
будет какой-нибудь log(WARNING, ...)
. Логи приложения можно мониторирить командой watch:
Компилируем с отладочными символами, запускаем, гоняем тесты, на которых воспроизводится проблема, ждем. (Бывает и так, что нет нормальных шагов для воспроизведения проблемы, но подобный сценарий выходит за рамки статьи.) Когда проблема воспроизвелась, цепляемся к процессу отладчиком:
Ставим бряк на while(ret == 0)
:
Breakpoint 1 at 0x10498: file test.c, line 9.
… и возобновляем работу приложения:
Continuing
Когда встали на бряке, модифицируем переменную ret:
9 } while(ret == 0);
(gdb) p ret=1
Поздравляю, мы оказались в правильном процессе в правильный момент времени. Проблема решена. Далее приложение можно отлаживать, как обычно. Кстати, проверок в коде может быть больше одной. Источник ошибки можно быстро локализовать по принципу бинарного поиска.
Fun fact! В MacOS, в отличие от Linux, системный вызов sleep()
сразу возвращает управление при подключении к процессу с отладчиком. На этой платформе можно написать sleep(1000)
и не добавлять цикл.
Уверен, что опытные разработчики не узнали для себя ничего нового. Но я подумал, что кому-то данная информация все же может пригодится. В примерах были использованы C и GDB, но прием работает с любым стеком технологий, где есть отладчик.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.