AUTOSAR C++14 Rule M15-3-4

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

Описание

Управляйте определением

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

Объяснение

На C++, когда операция повышает исключение, компилятор пытается совпадать с исключением совместимому обработчику исключений в текущих и смежных осциллографах. Если никакой совместимый обработчик исключений для повышенного исключения не существует, компилятор вызывает функциональный std::terminate() неявно. Функциональный std::terminate() отключает выполнение программы заданным реализацией способом. Таким образом, точный процесс завершения программы зависит от определенного набора программного и аппаратного обеспечения, которое вы используете. Например, std::terminate() может вызвать std::abort() неправильно прерывать выполнение, не раскручивая стек. Если стек не раскручен перед завершением программы, то деструкторы переменных в стеке не вызываются, ведя к утечке ресурсов и уязвимостям системы обеспечения безопасности.

Рассмотрите этот код, где несколько исключений повышены в блоке кода попытки.

class General{/*...  */};
class Specific : public General{/*...*/};
class Different{}
void foo() noexcept
{
	try{
		//...
		throw(General e);
		//..
		throw( Specific e);
		// ...
		throw(Different e);
	}
	catch (General& b){

	}
}
Блок кода выгоды принимает ссылки на базовый класс General. Этот блок выгоды совместим за исключениями базового класса General и производный класс Specific. Исключение класса Different не имеет совместимого обработчика. Это необработанное исключение нарушает это правило и может привести к утечкам ресурсов и уязвимостям системы обеспечения безопасности.

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

Реализация Polyspace

  • Polyspace® отмечает throw оператор в функции, если совместимый оператор выгоды отсутствует в пути к вызову функции. Если функция не задана как noexcept, Polyspace игнорирует его, если его путь к вызову испытывает недостаток в точке входа как main().

  • Polyspace отмечает throw оператор, который использует catch(…) оператор, чтобы обработать повышенные исключения.

  • Polyspace не отмечает операторы переброска, то есть, throw операторы в блоках выгоды.

  • У вас могут быть совместимые блоки выгоды для throw операторы в вашей функции во вложенном Polyspace блока try-catch игнорируют вложенные блоки try-catch. Выровняйте по ширине throw операторы, которые имеют совместимые блоки выгоды во вложенной структуре при помощи комментариев. В качестве альтернативы используйте один уровень try-catch в ваших функциях.

Поиск и устранение проблем

Если вы ожидаете нарушение правила, но не видите его, обратитесь к Кодированию Стандартных Нарушений, Не Отображенных.

Примеры

развернуть все

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

#include <stdexcept>

class MyException : public std::runtime_error {
public:
	MyException() : std::runtime_error("MyException") {}
};

void ThrowingFunc() {
	throw MyException(); //Noncompliant
}

void CompliantCaller() {
	try {
		ThrowingFunc();
	} catch (std::exception& e) {
		/* ... */
	}
}

void NoncompliantCaller() {
	ThrowingFunc(); 
}

int main(void) {
	CompliantCaller();
	NoncompliantCaller(); 
}

void GenericHandler() {
	try {
		throw MyException(); //Noncompliant
	} catch (...) { 
		/* ... */
	}
}

void TrueNoexcept() noexcept {
	try {
		throw MyException();//Compliant
	} catch (std::exception& e) {
		/* ... */
	}
}

void NotNoexcept() noexcept {
	try {
		throw MyException(); //Noncompliant
	} catch (std::logic_error& e) {
		/* ... */
	}
} 
  • Функциональный ThrowingFunc() повышает исключение. Эта функция имеет пути ко множественному вызову:

    • main()->CompliantCaller()->ThrowingFunc(): В этом пути к вызову, функциональном CompliantCaller() имеет блок выгоды, который совместим за исключением, повышенным ThrowingFunc(). Этот путь к вызову совместим с правилом.

    • main()->NoncompliantCaller()->ThrowingFunc(): В этом пути к вызову нет никаких совместимых обработчиков для исключения, повышенного ThrowingFunc(). Polyspace отмечает throw оператор в ThrowingFunc() и подсвечивает путь к вызову в коде.

    Функциональный main() точка входа для обоих из этих путей к вызову. Если main() комментируется, Polyspace игнорирует оба из этих путей к вызову. Если вы хотите анализировать путь к вызову, который испытывает недостаток в точке входа, задайте самую верхнюю функцию вызова как noexcept.

  • Функциональный GenericHandler() повышает исключение при помощи throw оператор и обрабатывает повышенное исключение при помощи типового всеобъемлющего блока. Поскольку Polyspace полагает, что такой всеобъемлющий обработчик несовместим за исключениями, которые повышены явным throw операторы, Polyspace отмечает throw оператор в GenericHandler().

  • noexcept функциональный TrueNoexcept() содержит явный throwоператор и блок выгоды совместимого типа. Поскольку этот throw оператор является соответствующим совместимому catch блокируйтесь, это совместимо с правилом.

  • noexcept функциональный NotNoexcept() содержит явный throw оператор, но блок выгоды не совместим за повышенным исключением. Поскольку этот throw оператор не является соответствующим совместимому блоку выгоды, Polyspace отмечает throw оператор в NotNoexcept().

Проверяйте информацию

Группа: Обработка исключений
Категория: необходимый, автоматизированный
Введенный в R2020b