ПроблемаЭтот дефект возникает, когда noexcept
сущность может выйти за исключением. Компилятор опускает процесс передачи исключений для noexcept
сущности. Когда такая сущность выходит за исключением, исключение становится необработанным, что приводит к ненормальному завершению программы.
Когда noexcept
сущность вызывает другие вызываемые сущности, Polyspace® делает определенные предположения, чтобы вычислить, могут ли быть необработанные исключения.
Функция: Когда noexcept
функция вызывает другую функцию, Polyspace проверяет, может ли вызываемая функция вызвать исключение, только если оно задано как noexcept(<false>)
. Если вызываемая функция задана как noexcept
Polyspace принимает, что это не вызывает исключение. Некоторые стандартные функции библиотеки, такие как конструктор 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 помечает такую функцию, даже если исключение может не быть вызвано.
РискЕсли a noexcept
функция выходит за исключением, компилятор вызывает std::terminate()
неявно. Функция std::terminate()
завершает выполнение программы определенным в реализации способом. То есть точный процесс завершения программы зависит от конкретного набора программного и оборудования, которое вы используете. Для образца, std:terminate()
может вызвать std::abort()
аномально прервать выполнение без размотки стека, что приводит к утечке ресурсов и уязвимостям безопасности.
ЗафиксироватьЗадайте функцию следующим noexcept
или noexcept(true)
только когда вы знаете, что функция не выходит за исключением. Если вы не уверены, задайте его при помощи noexcept(false)
ПримерРассмотрим этот код, где две функции заданы как noexcept
. Polyspace статически анализирует эти функции и функции, которые они вызывают.
#include <stdexcept>
#include <typeinfo>
bool f(bool flag){
if(flag==true)
throw flag;
return flag;
}
void LibraryFunc_noexcept_false() noexcept(false);
void SpecFalseCT() noexcept // Noncompliant
{
try {
LibraryFunc_noexcept_false();
} catch (int &e) {
LibraryFunc_noexcept_false();
} catch (std::exception &e) {
} catch (...) {
}
}
bool flag = false;
void Caller() noexcept { //Noncompliant
try {
if(f(flag)){
//...
}
} catch (int i) {
//...
}
}
Polyspace помечает noexcept
функциональные SpecFaleCT()
потому что эта функция вызывает noexcept(false)
внешние функциональные LibraryFunc_noexcept_false()
без обработки каких-либо исключений, которые могут быть вызваны из него. Эти исключения могут вызвать noexcept
функция для выхода за исключением.
Polyspace помечает noexcept
функциональные Caller
потому что эта функция вызывает noexcept(false)
функциональные f()
, который содержит явное throw
оператор. Хотя и throw
оператор не выполняется, когда flag
является false
Polyspace игнорирует динамический контекст и флаги Caller
.
КоррекцияПри определении функций задайте их как noexcept
только при обработке всех возможных исключений в функции. В противном случае задайте их следующим noexcept(false)
. В тех случаях, когда исключение не возникает в динамическом контексте, разъясните этот дефект с помощью комментариев.
#include <stdexcept>
#include <typeinfo>
bool f(bool flag){
if(flag==true)
throw flag;
return flag;
}
void LibraryFunc_noexcept_false() noexcept(false);
void SpecFalseCT() noexcept(false)// Compliant
{
try {
LibraryFunc_noexcept_false();
} catch (int &e) {
LibraryFunc_noexcept_false();
} catch (std::exception &e) {
} catch (...) {
}
}
bool flag = false;
void Caller() noexcept{//Noncompliant // polyspace CERT-CPP:ERR55-CPP
//[Justified:Unset] "Exception is not thrown when flag is false"
try {
if(f(flag)){
//...
}
} catch (int i) {
//...
}
}
Функция SpecFalseCT
теперь задается как noexcept(false)
потому что она вызывает внешнюю функцию, которая может вызывать исключения. Эта функция соответствует этому правилу.
Функция f()
не вызывает исключение, когда flag
является false
. Функция Caller
поддерживает спецификацию исключения, но Polyspace помечает ее, потому что Polyspace игнорирует динамический контекст. Этот дефект обоснован использованием комментария.