exponenta event banner

CERT C++: ERR58-CPP

Обрабатывать все исключения, возникающие перед началом выполнения main ()

Описание

Определение правила

Обрабатывать все исключения, возникшие перед началом выполнения main (). [ 1]

Внедрение Polyspace

Эта проверка проверяет наличие исключений, возникших при запуске программы.

Примеры

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

Проблема

Этот дефект возникает, когда может возникнуть исключение при построении глобальных и статических переменных до main() начинает выполнение. Если на этапе запуска возникает исключение, нельзя записать обработчик исключений, который компилятор может выполнить для обработки возникшего исключения. Это исключение становится необработанным. Например, можно внедрить main() в качестве function-try-catch блок для обработки исключений. Ни один из catch блоки могут обрабатывать исключения, возникшие на этапе запуска, и эти возникшие исключения становятся необработанными исключениями.

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

  • Функция: При прямом вызове функции инициализатора или конструктора для инициализации глобальной или статической переменной Polyspace проверяет, вызывает ли функция исключение, и помечает объявление переменной, если функция может вызвать исключение. Polyspace выводит, может ли функция вызвать исключение независимо от ее спецификации исключения. Например, если 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() где он может обрабатываться блоками захвата кода.

Проверить информацию

Группа: 08. Особые ситуации и обработка ошибок (ERR)
Представлен в R2020b

[1] Данное программное обеспечение было создано компанией MathWorks и включает в себя следующие компоненты: «Веб-сайт SEI CERT-C», © 2017 Университет Карнеги-Меллон, веб-сайт SEI CERT-C + + © 2017 Университет Карнеги-Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги-Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги-Меллон, со специальным разрешением от его Института программного обеспечения.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ МЕЛЛОНА И/ИЛИ ЕГО ПРОГРАММНОГО ИНЖЕНЕРНОГО ИНСТИТУТА, СОДЕРЖАЩИЙСЯ В НАСТОЯЩЕМ ДОКУМЕНТЕ, ПОСТАВЛЯЕТСЯ КАК ЕСТЬ. УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ, ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ЛЮБЫХ ВОПРОСОВ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИИ ПРИГОДНОСТИ ДЛЯ ЦЕЛЕЙ ИЛИ ТОВАРНОЙ ПРИГОДНОСТИ, ИСКЛЮЧИТЕЛЬНОСТИ ИЛИ РЕЗУЛЬТАТОВ, ПОЛУЧЕННЫХ ОТ ИСПОЛЬЗОВАНИЯ УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ В ОТНОШЕНИИ СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКИХ ПРАВ.

Данное программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллона или его Институтом разработки программного обеспечения.