exponenta event banner

Правило AUTOSAR C++ 14 M15-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 ® throw оператор в функции, если совместимая инструкция catch отсутствует в пути вызова функции. Если функция не указана как noexcept, Polyspace игнорирует его, если его путь вызова не имеет точки входа, как 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().

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

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

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

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