ПроблемаЭтот дефект возникает, когда исключение может возникнуть во время конструкции глобальных и статических переменных до main()
начинает выполняться. Если исключение возникает во время фазы запуска, вы не можете записать обработчик исключения, который может выполнить компилятор, чтобы обработать вызванное исключение. Это исключение становится необработанным исключением. Например, можно реализовать main()
как function-try-catch
блок для обработки исключений. Ни одно из catch
блоки могут обрабатывать исключения, возникшие во время фазы запуска, и эти вызванные исключения становятся необработанными исключениями.
Когда вы вызываете вызываемые сущности, чтобы инициализировать или объявить глобальные или статические переменные, эти сущности выполняются во время запуска программы. Polyspace® проверяет, могут ли эти сущности вызывать исключения во время запуска программы, делая определенные допущения.
Функция: Когда вы вызываете функцию инициализатора или конструктор непосредственно, чтобы инициализировать глобальную или статическую переменную, Polyspace проверяет, вызывает ли функция исключение, и помечает объявление переменной, если функция может вызвать исключение. Polyspace определяет, может ли функция вызвать исключение независимо от спецификации исключения. Для образца, если a noexcept
конструктор поднимает исключение, Polyspace помечает его. Если инициализатор или конструктор вызывает другую функцию, Polyspace предполагает, что вызываемая функция может вызвать исключение, только если это задано как noexcept(<false>)
. Некоторые стандартные функции библиотеки, такие как конструктор std::string
, используйте указатели на функции для выполнения выделения памяти, что может вызвать исключения. Polyspace не помечает объявление переменной, когда используются эти функции.
Внешняя функция: Когда вы вызываете внешние функции, чтобы инициализировать глобальную или статическую переменную, Polyspace помечает объявление, если внешняя функция задана как noexcept(<false>)
.
Виртуальная функция: Когда вы вызываете виртуальную функцию, чтобы инициализировать глобальную или статическую переменную, Polyspace помечает ее, если виртуальная функция задана как noexcept(<false>)
в любом производном классе. Например, если вы используете функцию виртуального инициализатора, которая объявлена как noexcept(<true>)
в базовом классе и noexcept(<false>)
в последующем производном классе Polyspace помечает его.
Указатели на функцию: Когда вы используете указатель на функцию для инициализации глобальной или статической переменной, Polyspace принимает, что указатель на функцию не вызывает исключений.
Polyspace игнорирует:
Исключения, вызванные деструкторами
Исключения, высказанные в atexit()
операции
Polyspace также игнорирует динамический контекст при проверке на исключения. Например, можно инициализировать глобальную или статическую переменную с помощью функции, которая вызывает исключения только в определенном динамическом контексте. Polyspace помечает такое объявление, даже если исключение может никогда не быть поднято. Обосновать такое нарушение можно при помощи комментариев в Polyspace.
РискКогда исключения не обрабатываются, компилятор может ненормально прекратить выполнение кода, не разматывая стек в зависимости от используемого набора оборудования и программного обеспечения. Рассмотрим этот код, где конструкция статического объекта obj
может вызвать исключение.
class A{
A(){throw(0);}
};
static A obj;
main(){
//...
}
Статический объект
obj
создается путем вызова
A()
перед
main()
запускается. Когда
A()
вызывает исключение, обработчик не может совпадать с вызванным исключением. Исходя из того набора программного и оборудования, который вы используете, такое исключение может привести к прекращению работы программы без размотки стека, что приведет к утечке памяти и уязвимостям безопасности.
ЗафиксироватьИзбегайте операций, которые могут вызвать исключение в частях вашего кода, которое может быть выполнено до запуска или после завершения программы. Например, избегайте операций, которые могут вызвать исключения в конструкторе и деструкторе статических или глобальных объектов.
ПримерРассмотрим этот код, где конструкция глобального указателя arr
требует динамического выделения памяти.
#include <stdexcept>
void* alloc(size_t s) noexcept {
return new int[s];
}
int* arr = (int*)alloc(5);//Noncompliant
int main(){
//..
return 0;
}
Динамическое выделение памяти при помощи new
оператор может вызвать исключение. Потому что построение arr
может вызвать исключение перед main()
начинает выполнение, Polyspace помечает объявление.
КоррекцияИзбегайте операций, которые могут вызвать исключение при построении глобальных объектов. Например, можно инициализировать глобальный указатель мыши arr
при помощи nullptr
. Затем выделите память для arr
в main()
в try-catch
кодовый блок.
#include <stdexcept>
#include<vector>
void* alloc(size_t s) noexcept {
return new int[s];
}
int* arr =nullptr;
int main(){
try{
arr = (int*)alloc(5);
}
catch(std::bad_alloc e){
//..
}
//..
return 0;
}
В этом случае операция динамического выделения памяти поднимает std::bad_alloc
исключение в main()
где это может быть обработано блоками catch кода.