LINUX.ORG.RU

Архитектурный вопрос: как предусмотреть сачок для багов.


0

2

Допустим есть приложение и в нем есть баги (если нет то будут).

Мы его оттестируем, прогоним всякими унит тестами и прочими, натравим толпу тестеров, год будем вылизывать и зальем на продакшен (допустим это сервер)

и допустим раз в два месяца будем иметь злую но невоспроизводимую ошибку (да на практике сервер просто ребутнут и сделают вид шо так и було)

теперь вопрос: как на этапе проектирования архитектуры предусмотреть механизмы улова таких ошибок(языки и софт любой, нужны примеры)

в моей практике в десктопный софт мы просто встроили js-коносоль (java), а чужой глючносервер пришлось в продакшене месяц держать под отладчиком чтобы в момент глюка подцепиться и посмотреть (да помоголо, но это не дело)

ps.навеяно личным опытом, кучей страшных историй и этим постом (хотя тут воспроизводимость 100%, но этож везение)

Deleted

1. Больше ассертов, хороших и разных. Отлавливать undefined behavior нужно на самых ранних этапах.

2. Распечатка состояния потоков, стека, регистров в момент падения с последующей отправкой разработчикам и раскруткой на их стороне.

3. Сериализация команд управления данными, сохранение в файл и последующее воспроизведение со сравнением с референсным образцом. Рассинхронизация на любом этапе точно бьёт в цель с указанием на проблему.

Ну и, конечно же, максимальная автоматизация вышесказанного.

Dendy ★★★★★
()
Ответ на: комментарий от Dendy

Сериализация команд управления данными, сохранение в файл и последующее воспроизведение со сравнением с референсным образцом.

во это занятнее, есть примеры реализаций?

Deleted
()

Единственный способ получить хоть что-то работающее — это решать множество проблем по мере их возникновения, а не пытаться предрешить всевозможные проблемы с помощью одной супер-идеи.Л.Торвальдс
Вот такие пироги.

Spirit_of_Stallman ★★★
()
Ответ на: комментарий от Deleted

Да, у него всего лишь работающее ядро, используемое почти на всех супер-компьютерах.

frozenix ★★★
()
Ответ на: комментарий от Dendy

2. Распечатка состояния потоков, стека, регистров в момент падения

Для отладочной версии проги это было было бы очень неплохо. Но разобраться с этой инфой для оптимизированного варианта вряд ли будет просто. Куча «optimized out» вместо данных. И что с этим делать?

gag ★★★★★
()
Ответ на: комментарий от Deleted

от багов многопоточности

Сложно будет. Не логгить же каждую переменную.

и дедлоков не спасет

А тут проще: перед каждым локом мьютекса выводить «лочу мьютекс такой-то», а потом «успех». Быстро можно будет найти место, где лочат уже залоченный.

gag ★★★★★
()
Ответ на: комментарий от Deleted

во это занятнее, есть примеры реализаций?

Каждая реализация будет сильно заточена под конкретный случай. К примеру, я сейчас делаю подобное для игрового движка, в котором состояние игры есть инвариант, управляемый строго по протоколу извне. Сохранение протокола в файл позволяет воспроизвести любой игровой процесс на локалхосте и автоматически обнаружить неполадку.

Dendy ★★★★★
()
Ответ на: комментарий от Spirit_of_Stallman

Единственный способ получить хоть что-то работающее — это решать множество проблем по мере их возникновения, а не пытаться предрешить всевозможные проблемы с помощью одной супер-идеи.Л.Торвальдс

Думаю, Торвальдс скорее говорил про идею с достаточно размытой реализацией. В принципе, типичный случай, ведь заранее правильно можно решить только ту задачу, которая была решена N раз до этого. Понять в каком направлении двигаться лучше отталкаваясь от конкретной реализации со своими косяками.

В данном случае косяки вполне понятны, это отладка случайного поведения у клиента на другом конце земного глобуса.

Dendy ★★★★★
()
Ответ на: комментарий от gag

Для отладочной версии проги это было было бы очень неплохо. Но разобраться с этой инфой для оптимизированного варианта вряд ли будет просто. Куча «optimized out» вместо данных. И что с этим делать?

Для себя я пришёл к выводу, что нужно строить логику программы на основе инвариантов. В этом случае достаточно протоколировать не сами данные, а только команды их меняющие. Так называемый тонкий протокол. В таком случае имея снапшот данных + протокол можно точно воспроизвести цепочку событий.

Dendy ★★★★★
()

Прочитал статью. Если бы не читая документации, писав только гкод, научится отлавливать такие «баги», думаю все нанимали индусов и ставили подобную систему. Больше ничего делать не надо, какое счастье.

Если код умеет себя контролировать, в случает отклонения от норм поведения (не исключения) можно дропнуть трейс для анализа.

gh0stwizard ★★★★★
()

навеяно личным опытом, кучей страшных историй и этим постом

Тоже могу рассказать историю. Место действия... а не важно. Действующие лица: ядерный модуль, вызываемый им kernel panic, я.

Акт 1. Kernel panic случается из-за разыменования нулевого указателя. Указатель лежит в секции глобальных данных и обнуляться не должен в принципе. В общем, memory corruption. Радует, что воспроизводимость бага 100%.

Акт 2. Проверяю, что проблема действительно в том, что кто-то пишет не в свою память — добавляю 4-байтную переменную до обнуляемого указателя. Баг больше не воспроизводится. Гипотеза подтверждена.

Акт 3. Так кто же зануляет указатель? Опытным путем выясняю: виноват memset в другом модуле, который зануляет какую-то свою структуру, тоже глобальную. Исходный код выглядит корректно. В самом деле, что может быть проще memset(&s, 0, sizeof(s))? Остается только одно — дизассемблировать.

Акт 4. Дизассемблер показывает, что компилятор решил заинлайнить memset и применить хитрую оптимизацию:

1:
movl    $0xffffe800,%eax
movl    $0x00000000,0x0002e48c(%eax)
addl    $0x04,%eax
jne     1b
То есть выход из цикла произойдет когда %eax переполнится и станет нулевым. Соответственно, 0x100000000-0xffffe800 = sizeof(s), а 0x0002e48c+0xffffe800 = &s. Вроде всё правильно.

Акт 5. Раз базовый адрес и размер структуры правильные, то почему этот код затирает не свою память? Собака зарыта в константе 0x0002e48c. На самом деле это не тот адрес, который будет использоваться в run time. При загрузке ядерного модуля в память динамический линкер пропишет туда адрес с учетом базы модуля. Дизассемблирование из-под удаленного отладчика показало, что в run time там адрес неправильный. Это баг компилятора, сгенерировавшего некорректную команду для линкера.

Эпилог. Обновление компилятора помогло.

Relan ★★★★★
()
Ответ на: комментарий от gag

не не, попадается индусокод где делается wait после того как другой поток сделает notify - типичная гонка, но оттестировать и поймать ее проблема.

Deleted
()
Ответ на: комментарий от Dendy

ну это тебе в многопоточности также не поможет, это хорошо чтобы не спрашивать пользователя - а что вы сделали прежде чем все повисло .

Deleted
()
Ответ на: комментарий от Deleted

У этого вашего торвальдса нет стабильного api ядра в том числе и по этой причине.

зато у Дениса Попова вообще ничего нет, кроме супер-идеи.

drBatty ★★
()

Я думал про такую штуку, правда не видел нигде. Суть в хитрой системе логгирования. Внутри есть кольцевой буфер достаточно большой. Каждый вызов трейса и других вызовов добавляет лог запись в буфер. В файлы все логгируется как обычно, согласно настройкам. При возникновении исключения или по пользовательскому вызову весь буфер логгируется. Таким образом будет видно, что происходило в системе за некоторое время до ошибки без раздувания логов. Мне бы во многих случаях это помогло бы.

Еще хочется возможность для логов включить trace для определенного клиента (в случае сервлетов), ну т.е. для потока, бывает, что глючит у человека, а у других все нормально.

Legioner ★★★★★
()

Есть одна серебрянопулевая панацея - Erlang.

dismal_faun ★★
()
Ответ на: комментарий от Legioner

Суть в хитрой системе логгирования.

Примерно то что ты описал есть в mybatis, там при вызовах заполняется ErrorContext для почти каждого вызова, но по факту он больше мешает - ибо раздает стектрейс

Deleted
()

let it crash

anonymous
()

Прочитал пост по ссылке. Решил и свою историю сюда запилить.

Итак есть устройство на OMAP3530 + своя плата + монитор и кнопки. Все это упакованно в корпус, туда залито самосборное ядро, библиотеки и т.п., собранные через buildroot. Там же стоит Qt и пользовательская аппликуха.

В какой-то момент времени тестеры сообщают, что раз в 3-4 дня непрерывной работы устройство может намертво зависнуть, помогает только перезагрузка. Виснет не постояно, может зависнуть в первые полчаса-час, но чаще до зависания проходит порядка 20 часов.

Начинаем разбираться. Выясняем, что устройство зависает намертво. После зависания не отвечает ни JTAG, ни сеть.

Несколько недель тратим на игры с версиями компилятора, профилированием собственного кода. Результат 0. (Подробно расписывать лень, да и не в этом суть).

В итоге начали аудит всего внешнего кода и в libpixman нашли код, добавленный каким-то клоуном из Nokia.
Ассемблерный.
Содержащий инструкции, отсутствующие на нашем процессоре.

За последующие 2 часа этот челове к должен был умереть от икоты, а все окружающие значительно пополнили свой словарный запас абсцентной лексики.

trex6 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.