Noexcept function exits with exception

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

Описание

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

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

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

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

  • Виртуальная функция: Когда функция вызывает виртуальную функцию, Polyspace помечает объявление функции, если виртуальная функция задана как noexcept(<false>) в производном классе. Для образца, если a 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 (...) {
	}
}

The 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;
	//..
	
}

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

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

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