Запутанный анализ потока управления из теста Parasoft C++
Мы используем тест Parasoft C++ для статического анализа нашего кода. У него проблемы с кодом, подобным следующему:
void foo(int* x) {
try {
bar();
} catch(...) {
delete x;
throw;
}
*x;
}
Он предупреждает о *x;
линия что:
Освобожденная память не должна быть доступна ни при каких обстоятельствах
Каким-то образом сделан вывод, что поток управления может перейти в catch(...)
заблокировать, удалить x
, пройти мимо throw;
и сделать это *x;
, Я старался throw std::exception("");
и пару других и получили то же самое. Parasoft наверняка знает об исключениях и включает их в свой поток управления, потому что есть много других тестов, которые включают проверку исключений. Это просто сбивает с толку в этом случае, или на самом деле есть какой-то способ для выполнения этой программы ударить оба delete x;
а также *x;
?
3 ответа
Так что инструмент не тот (об этом я уже говорил, я знаю), и я полагаю, что вы не хотите скрывать предупреждение.
Я согласен с комментарием @Pascal о том, что несколько опасно переписывать код, чтобы обойти ограничения некоторых инструментов. Что вы можете сделать, это отключить эту очистку только для файлов, где у вас есть эта проблема.
Затем у вас есть начальная сборка без предупреждения, без инструмента, предлагающего переписать существующий допустимый код.
Для нового кода вам нужно будет принять стиль, понятный инструменту. Это не такая большая проблема, потому что это будет код, над которым вы сейчас работаете, поэтому будет меньше проблем, если вам придется немного переписать его, чтобы избавиться от предупреждений.
Несмотря на правильность, существующий стиль далек от идеала.
Я бы рекомендовал хранить указатели, такие как x
в auto_ptr. Это автоматически удалит содержимое auto_ptr, если оно выходит из области видимости - если вы явно не удалите его из auto_ptr. Это намного проще для глаз, а также хорошо документирует, что эта функция становится владельцем указателя.
void foo(auto_ptr<int> x)
{
bar();
*x;
}
Я ожидаю, что ParaSoft не будет иметь проблем с этим кодом.
Быстрое обновление:
1) Вышеупомянутое правило вообще не является правилом анализа потока. При этом правило (ID MRM-31) было улучшено в тесте C++ 9.2.0 и более поздних версиях. Для этого в тесте C++ существует соответствующее правило анализа потока (ID: BD-RES-FREE), которое должно выполнять то, что вы хотите.
Возможно, это глупое предложение, но что скажет Parasoft, если вы оставите улов на конец? Т.е.
void foo(int* x)
{
try
{
bar();
*x;
}
catch(...)
{
delete x;
throw;
}
}
Я понимаю, что это может не сработать для всех комбинаций операторов и исключений, например, если у вас есть несколько типов исключений для разной обработки на разных этапах foo, но по крайней мере это может дать вам начало обходного пути, если вы действительно хотите избавиться от предупреждения.