exponenta event banner

Аргумент Throw вызывает непредвиденное исключение

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

Описание

Этот дефект возникает, когда выражение аргумента инструкции throw может вызвать исключение. Выражения, которые могут вызывать исключения, включают:

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

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

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

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

Риск

При явном вызове исключения с помощью throw сначала компилятор создает ожидаемое исключение путем оценки аргумента инструкции throw, а затем вызывает ожидаемое исключение. Если непредвиденное исключение возникает, когда компилятор создает ожидаемое исключение в throw непредвиденное исключение распространяется вместо ожидаемого. Это непредвиденное исключение может стать необработанным исключением. В зависимости от среды компилятор может вызывать std::abort аварийно завершить выполнение программы без разматывания стека, когда исключения становятся необработанными, что приводит к утечке ресурсов и уязвимостям безопасности. Рассмотрим этот код, если 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 заявление.

Примеры

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

int f_throw() noexcept(false);
int foo(){
	try{
		//...
		throw f_throw();
	}
	catch(...){
		//...
	}
}

В этом примере функция f_throw() указывается как noexcept(false). Если исключение возникает в f_throw(), это может привести к завершению программы без размотки стека, что приведет к утечке ресурсов и уязвимостям безопасности.

Коррекция - использовать функции, указанные как noexcept(true) как выражение аргумента throw Заявления

Одной из возможных корректировок является использование функций, которые не вызывают исключений в выражении аргумента throw заявление. Эти функции указаны как noexcept(true).

int f_throw() noexcept(true);
int foo(){
	try{
		//...
		throw f_throw();
	}
	catch(...){
		//...
	}
}
class WithDynamicAlloc {
public:
	WithDynamicAlloc(int n) {
		m_data = new int[n];   
	}
	~WithDynamicAlloc() {
		delete[] m_data;
	}
private:
	int* m_data;
};
int foo(){
	try{
		//...
		throw WithDynamicAlloc(10); 
	}
	catch(WithDynamicAlloc& e){
		//... 
	}
}

В этом примере конструктор объекта WithDynamicAlloc выполняет операцию динамического выделения памяти. Этот конструктор может вызвать исключение, например bad_alloc это может привести к завершению программы без размотки стека, что приведет к утечке ресурсов и уязвимостям безопасности.

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

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

class WithoutDynamicAlloc {
public:
	WithoutDynamicAlloc(int n) : m_data(n){   
	}
	~WithoutDynamicAlloc() {
	}
private:
	int m_data;
};
int foo(){
	try{
		//...
		throw WithoutDynamicAlloc(10); 
	}
	catch(WithoutDynamicAlloc& e){
		//... 
	}
}
int MightThrow(bool b) {
	if (b) {
		throw 2.1;
	}
	return 42;
}
int foo(){
	try{
		//...
		throw MightThrow(false);
		throw MightThrow(true);
	}
	catch(int e){
		//... 
	}
}

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

Исправление - использование комментариев для выравнивания результата

Поскольку MightThrow(false) не вызывает исключения, возможное исправление заключается в использовании комментариев для обоснования утверждения throw MightThrow(false).SeyAddress Polyspace Результаты с помощью исправлений ошибок или обоснований

int MightThrow(bool b) {
	if (b) {
		throw 2.1;
	}
	return 42;
}
int foo(){
	try{
		//...
		throw MightThrow(false);// polyspace DEFECT:THROW_THROWS [Justified:Low] "Does not Throw"
		throw MightThrow(true);
	}
	catch(int e){
		//... 
	}
}

Информация о результатах

Группа: C++ Исключение
Язык: C++
По умолчанию: Вкл для рукописного кода, выкл для сгенерированного кода
Синтаксис командной строки: THROW_ARGUMENT_EXPRESSION_THROWS
Воздействие: Высокое
Представлен в R2020b