MISRA C++:2008 Rule 15-3-4

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

Описание

Определение правила

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

Объяснение

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

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

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

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

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

Реализация Polyspace

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

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

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

  • У вас могут быть совместимые блоки catch для throw операторы в функции во вложенном блоке try-catch Polyspace игнорирует вложенные блоки try-catch. Обоснование throw операторы, которые имеют совместимые блоки catch во вложенной структуре с помощью комментариев. Кроме того, используйте один уровень 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() имеет блок catch, который совместим за исключением, вызванным ThrowingFunc(). Этот путь вызова соответствует правилу.

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

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

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

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

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

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

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