ПроблемаЭтот дефект происходит когда noexcept сущность может выйти за исключением. Компилятор не использует процесс вручения исключения для noexcept сущности. Когда такие выходы сущности за исключением, исключение становится необработанным, ведя к аварийному завершению программы.
Когда noexcept сущность вызывает другие вызываемые сущности, 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 игнорирует:
Polyspace также игнорирует динамический контекст при проверке на исключения. Например, функциональное повышение силы необработанные исключения только в определенных динамических контекстах. Polyspace отмечает такую функцию, даже если исключение не может быть повышено.
РискЕсли 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 игнорирует динамический контекст. Этот дефект выравнивается по ширине при помощи комментария.