Нахождение деления на ноль в большом проекте - PullRequest
9 голосов
/ 01 февраля 2010

Недавно наш большой проект начал рушиться при необработанном делении на ноль. Похоже, что в недавнем коде нет вероятных элементов, поэтому это могут быть новые наборы данных, влияющие на старый код. Проблема в том, что база кода довольно большая и работает на встроенном устройстве без удобного доступа к отладке (отладка выполняется многими printf () через последовательную консоль, GDB для устройства не существует, и даже если бы он был, двоичный файл, скомпилированный с символами отладки, не подходит).

Наиболее жизнеспособным способом, вероятно, было бы найти все операции деления (они относительно редки) и проанализировать код, окружающий каждую из них, чтобы увидеть, была ли какая-либо из переменных делителя оставлена ​​без присмотра.

Тогда возникает вопрос, как найти все операции деления в большом (~ 200 файлах, несколько больших) проекте C ++, или, если у вас есть лучшее представление о том, как найти ошибку, укажите их.

дополнительная информация: проект выполняется на встроенном ARM9, небольшом пользовательском дистрибутиве Linux, кросс-компилированном с кросс-инструментами Cygwin / Windows, IDE - это Eclipse, но есть и Cygwin со всеми соответствующими вкусностями. Дело в том, что проект очень специфичен для оборудования, и сбои происходят только при работе на полную мощность, когда все необходимые взаимосвязанные модули активны. Ограниченный «режим отказа», когда активны только голые кости, не создает их.

Ответы [ 10 ]

8 голосов
/ 01 февраля 2010

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

Посмотрите, реализует ли ваш набор инструментов разделение на ноль так же, как Набор инструментов ARM (вероятно, он делает что-то хотя бы похожее). Если это так, вы можете установить обработчик, который вызывается при возникновении проблемы, и вы можете printf() регистрировать и составлять стеки, чтобы вы могли определить, где возникает проблема. Возможная аналогичная альтернатива - ваш маленький дистрибутив Linux выдает сигнал, который вы можете поймать.

Я не уверен, как вы получаете информацию о том, что происходит деление на ноль, но если это происходит из-за того, что среда выполнения выдает сообщение об этом, у вас всегда есть возможность узнать, где это обрабатывается. во время выполнения, и заменив его своим более информативным сообщением. Однако я предполагаю, что есть более «спроектированный» способ заставить ваш код работать (обработчик сигнала или метод ARM).

8 голосов
/ 01 февраля 2010

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

Посмотрите на этот вопрос или просто поищите в Google информацию, касающуюся перехвата исключений в вашей конкретной среде.

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

6 голосов
/ 01 февраля 2010

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

6 голосов
/ 01 февраля 2010

Поиск всех подразделений не должен быть трудным с пользовательским поиском grep . Вы можете легко отличить это использование от других случаев использования символов / и % в C ++.

Кроме того, если вы знаете, что делите, вы можете глобально перегрузить операторы / и %, чтобы получить утверждение информирования __FILE__ и __LINE__. При использовании make-файла не составит труда включить пользовательский код оператора во все связанные файлы, не касаясь кода.

2 голосов
/ 02 февраля 2010

Обработка исключения.

Обычно исключение передается структуре, содержащей адрес, вызвавший исключение, и другую информацию. Возможно, вам придется ознакомиться с таблицей микроконтроллера или руководством по RTOS.

2 голосов
/ 01 февраля 2010

PC-Lint может помочь, это как Findbugs для C ++.Это коммерческий продукт, но есть гарантия возврата денег.

1 голос
/ 12 февраля 2010

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

см. http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4061.html

я бы предложил предоставить __rt_raise (), как сказано на странице выше.

__rt_raise (2,2) будет вызван, когда процедура деления обнаружит деление на ноль. так что вы можете распечатать регистр LR. а затем используйте addr2line для перекрестной ссылки на исходную строку

1 голос
/ 01 февраля 2010

Используйте -save-temps для gcc и найдите соответствующую сборку для разделения в сгенерированном файле .s. Если вам повезет, это будет нечто особенное, возможно, даже вызов функции. Если это вызов функции, вы можете использовать слабое связывание, чтобы переопределить его собственной проверенной версией. В противном случае расположение разделов в сборке должно дать вам очень хорошее представление о том, где они находятся в коде C / C ++, и вы можете напрямую их обрабатывать.

0 голосов
/ 02 февраля 2010

Исключение уже имеет адрес расположения ошибочного деления на ноль кода. Процессор сохраняет содержимое регистра при возникновении исключения, включая ПК (программный счетчик). Ваша ОС должна передавать эту информацию (я предполагаю, что именно так вы узнаете, что она делится на ноль). Распечатай адрес и иди посмотри в своем коде. Если вы сможете напечатать трассировку стека, это будет еще проще решить.

Другим вариантом будет проверка различий в программном обеспечении для контроля версий между последней известной рабочей версией и первой нерабочей версией. Это должно дать вам ограниченный набор изменений для поиска проблемы.

0 голосов
/ 01 февраля 2010

Единственный способ найти эти условия - обычный:

  1. попытайтесь воспроизвести проблему, не глядя на источник (поскольку ошибка уже произошла, у вас должна быть информация о той части программы, которая затронута)
  2. если найдено, проверьте источник для этой точки и исправьте его, иначе:
    2.1. grep для каждого / не следует * или / (grep "/ [^ / *]" я думаю)
    2.2. найти условия выполнения кода и воспроизвести его
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...