MISRA C++:2008 Rule 15-1-1

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

Описание

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

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

Объяснение

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

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

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

Если при создании компилятором ожидаемого исключения в throw возникает непредвиденное исключение оператор, непредвиденное исключение возникает вместо ожидаемого. Рассмотрим этот код, где a 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. The 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