exponenta event banner

Функция Noexcept выходит с исключением

Функции, указанные как noexcept, noexcept(true) или noexcept(<true condition>) выход с исключением, которое приводит к аварийному завершению выполнения программы, что приводит к утечке ресурсов и уязвимости безопасности

Описание

Этот дефект возникает, когда вызываемый объект указан с помощью noexcept, noexcept(true), или noexcept(<true condition>) может выйти с исключением.

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

  • Функции: При noexcept функция вызывает другую функцию, Polyspace проверяет, может ли вызываемая функция вызвать исключение, только если она указана как noexcept(<false>).Если вызываемая функция указана как noexcept, Polyspace предполагает, что он не вызывает исключения. Некоторые стандартные библиотечные функции, такие как конструктор std::string, используйте указатели на функции для выделения памяти, что может вызвать исключения. Поскольку эти функции не указаны как noexcept(<false>), Polyspace не помечает функцию, которая вызывает эти стандартные библиотечные функции.

  • Внешняя функция: При noexcept функция вызывает внешнюю функцию, Polyspace помечает объявление функции, если внешняя функция указана как noexcept(<false>).

  • Виртуальная функция: Когда функция вызывает виртуальную функцию, Polyspace помечает объявление функции, если виртуальная функция указана как noexcept(<false>) в производном классе. Например, если noexcept функция вызывает виртуальную функцию, которая объявлена как noexcept(<true>) в базовом классе, и noexcept(<false>) в последующем производном классе Polyspace помечает объявление noexcept функция.

  • Указатели на функцию: Когда noexcept функция вызывает указатель на функцию, Polyspace предполагает, что указатель на функцию не вызывает исключений.

При анализе того, вызывает ли функция необработанные исключения, Polyspace игнорирует:

  • Исключения, возникшие в деструкторах

  • Исключения, возникшие в atexit() операции

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

Риск

Можно указать, что вызываемый объект не выходит за исключением, указав его как noexcept, noexcept(true), или noexcept(<true condition>). Компилятор пропускает процесс передачи исключений для noexcept сущности. Когда такая сущность выходит за исключением, компилятор неявно вызываетstd::terminate().

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

Зафиксировать

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

Примеры

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

#include <stdexcept>
#include <typeinfo>
void LibraryFunc(); 
void LibraryFunc_noexcept_false() noexcept(false);  
void LibraryFunc_noexcept_true() noexcept(true);    



void SpecFalseCT() noexcept 
{
	try {
		LibraryFunc_noexcept_false();
	} catch (int &e) {
		LibraryFunc_noexcept_false();  
	} catch (std::exception &e) {
	} catch (...) {
	}
}

class A {
public:
	virtual void f() {}              
};

class B : A {
public:
	virtual void f() noexcept {}     
};

class C : B {
public:
	virtual void f() noexcept {}     
};

class D : A {
public:
	virtual void f() noexcept(false) { throw(2);}
};

void A1(A &a) noexcept {         
	a.f();
}

void D2(D &d) noexcept {          
	try {
		d.f();
	} catch (int i) {
	} catch (...) {
	}
}

void B2(B *b) noexcept {          
	b->f();
}
template <class T>
T f_tp(T a) noexcept(sizeof(T)<=4)    
{
	if (sizeof(T) >4 ) {
		throw std::runtime_error("invalid case");
	}
	return a;
}
void instantiate(void)
{
	f_tp<char>(1);
}
void f() noexcept {               
	throw std::runtime_error("dead code");
}

void g() noexcept {               
	f();
}  

В этом примере существует несколько noexcept функции. Эти функции вызывают другие вызываемые объекты, такие как функции, внешние функции и виртуальные функции.

  • Polyspace помечает объявление шаблона функции f_tp даже несмотря на throw оператор не достигнут, так как Polyspace игнорирует динамический контекст. Polyspace также анализирует только экземпляры шаблонов в коде. Например, если f_tp не создан экземпляр в функции instantiate(), Polyspace не анализирует шаблон.

  • Polyspace помечает noexcept функция SpecFaleCT() потому что эта функция вызывает noexcept(false)внешняя функция LibraryFunc_noexcept_false() не инкапсулируя его в try-catch блок. Любые исключения, вызванные этим вызовом внешней функции, могут вызвать необработанное исключение.

  • Polyspace помечает объявление noexcept функция A1() потому что эта функция может вызвать noexcept(false) функция D.f() когда входной параметр a имеет класс D. В зависимости от класса входного параметра, noexcept полиморфная функция A1() может вызвать необработанное исключение.

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

  • Polyspace doe не пометить noexcept функция D2() несмотря на то, что он вызывает noexcept(false) функция D.f() потому что D2() обрабатывает исключения, которые могут возникнуть при использовании catch(...) блок.

Коррекция - укажите функции как noexcept(false)

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

#include <stdexcept>
#include <typeinfo>
void LibraryFunc_noexcept_false() noexcept(false);
void SpecFalseCT() noexcept(false) 
{
	try {
		LibraryFunc_noexcept_false();
	} catch (int &e) {
		LibraryFunc_noexcept_false();  
	} catch (std::exception &e) {
	} catch (...) {
	}
}

Функция SpecFalseCT() использует внешнюю функцию, которая указана как noexcept(false). Функция SpecFalseCT() указывается как noexcept(false) потому что он может выйти за исключением. Эта функция не приводит к возникновению дефекта.

Исправление - Обработка исключений в noexcept Функции

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

#include <stdexcept>
#include <typeinfo>

void f() noexcept(false) { 
throw(2);
}
void CallerFunc() noexcept {          
	try {
		f();
	} catch (int i) {
	} catch (...) {
	}
}

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

Исправление - обоснование дефектов с помощью комментариев

Вы можете обосновать поднятые дефекты с помощью комментариев: поскольку Polyspace анализирует функции статически, он может поднять этот дефект, чтобы отметить исключения, которые находятся в мертвом коде. Используйте комментарии для обоснования дефектов, если вы считаете, что исключение может не возникнуть.

#include <stdexcept>
#include <typeinfo>
void MightThrow(unsigned int input) noexcept{// polyspace DEFECT:NOEXCEPT_FUNCTION_THROWS [Justified:Unset] "Throw in dead code"
	if(input<0)
		throw 1;
	//..
	
}

noexcept функция MightThrow() выходит за исключением динамического контекста, который может не возникнуть. Например, unsigned int входные данные неотрицательны, и throw инструкция не выполняется. Поскольку Polyspace анализирует функции статически, он поднимает дефект на throw заявление. Обоснование дефекта с помощью комментария. Результаты SureAddress Polyspace с помощью исправлений ошибок или обоснований

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

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