exponenta event banner

Правило AUTOSAR C++ 14 M15-1-1

Назначение-выражение оператора throw не должно само по себе вызывать исключение

Описание

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

Назначение-выражение оператора throw не должно само по себе вызывать исключение.

Объяснение

В C++ можно использовать throw для явного создания исключений. Компилятор выполняет такую throw оператор в два шага:

  • Во-первых, он создает аргумент для throw заявление. Компилятор может вызвать конструктор или вычислить выражение назначения для создания объекта аргумента.

  • Затем он поднимает созданный объект как исключение. Компилятор пытается сопоставить объект исключения совместимому обработчику.

Если непредвиденное исключение возникает, когда компилятор создает ожидаемое исключение в throw непредвиденное исключение создается вместо ожидаемого. Рассмотрим этот код, если throw оператор вызывает явное исключение класса myException.

class myException{
	myException(){
		msg = new char[10];
		//...
	}
	//...
};

foo(){
	try{
		//..
		throw myException();
	}
	catch(myException& e){
		//...
	}
}
При строительстве временного myException объект, new оператор может поднять bad_alloc исключение. В таком случае throw заявление вызывает bad_alloc исключение вместо myException. Поскольку myException было ожидаемым исключением, блок catch несовместим с bad_alloc. bad_alloc исключение становится необработанным исключением. Это может привести к аварийному прерыванию работы программы без разматывания стека, что приведет к утечке ресурсов и уязвимостям системы безопасности.

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

Внедрение Polyspace

Polyspace ® помечает выражения вthrow операторы, которые могут вызвать исключение. Выражения, которые могут вызывать исключения, могут включать:

  • Функции, указанные как noexcept(false)

  • Функции, содержащие одну или несколько явных throw заявления

  • Конструкторы, выполняющие операции выделения памяти

  • Выражения, включающие динамическое литье

Поиск неисправностей

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

Примеры

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

В этом примере показано, как Polyspace помечает выражения в throw операторы, которые могут вызвать неожиданные исключения.

int f_throw() noexcept(false);

class WithDynamicAlloc {
public:
	WithDynamicAlloc(int n) {
		m_data = new int[n];   
	}
	~WithDynamicAlloc() {
		delete[] m_data;
	}
private:
	int* m_data;
};

class MightThrow {
public:
	MightThrow(bool b) {
		if (b) {
			throw 42;
		}
	}
};

class Base {
	virtual void bar() =0;
};
class Derived: public Base {
	void bar();
};
class UsingDerived {
public:
	UsingDerived(const Base& b) {
		m_d = 
		dynamic_cast<const Derived&>(b);
	}
private:
	Derived m_d;
};
class CopyThrows {
public:
	CopyThrows() noexcept(true);
	CopyThrows(const CopyThrows& other) noexcept(false);
};
int foo(){
	try{
		//...
		throw WithDynamicAlloc(10); //Noncompliant
		//...
		throw MightThrow(false);//Noncompliant
		throw MightThrow(true);//Noncompliant
		//...
		Derived d;
		throw  UsingDerived(d);// Noncompliant
		//... 
		throw f_throw(); //Noncompliant
		CopyThrows except;
		throw except;//Noncompliant
	}
	catch(WithDynamicAlloc& e){
		//... 
	}
	catch(MightThrow& e){
		//... 
	}
	catch(UsingDerived& e){
		//... 
	}
}

  • При создании WithDyamicAlloc путем вызова конструктора WithDynamicAlloc(10), исключения могут возникать во время динамического выделения памяти. Потому что выражение WithDynamicAlloc(10) может вызвать исключение, Polyspace помечает throw заявление throw WithDynamicAlloc(10);

  • При создании UsingDerived путем вызова конструктора UsingDervide(), исключения могут возникать во время операции динамического литья. Потому что выражение UsingDerived(d) может вызывать исключения, Polyspace помечает оператор throw UsingDerived(d).

  • В функции MightThrow(), исключения могут увеличиваться в зависимости от входных данных функции. Поскольку Polyspace анализирует функции статически, он предполагает, что функция MightThrow() может вызывать исключения. Polyspace помечает операторы throw MightThrow(false) и throw MightThrow(true).

  • В заявлении throw except, объект except копируется путем неявного вызова конструктора копирования класса CopyThrows. Поскольку конструктор копирования указан как noexcept(false), в Polyspace предполагается, что операция копирования может вызвать исключения. Polyspace помечает оператор throw except

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

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

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