AUTOSAR C++14 Rule A15-2-1

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

Описание

Управляйте определением

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

Объяснение

На C++ компилятор отвечает на исключение путем выполнения этих шагов:

  • Компилятор пытается совпадать с исключением обработчику в текущем осциллографе или более высоком осциллографе.

  • Если соответствия исключения с обработчиком, то обработчик принимает исключение и начинает раскручивание стека. Во время раскручивания стека выполнение программы перемещается от осциллографа, который производит исключение для внешних осциллографов в обратном порядке. Выполнение программы затем вызывает деструкторы для каждой переменной на стеке, которые еще не уничтожаются. После раскручивания стека выполнение программы сразу возобновляется от линии после инициированного обработчика.

  • Если исключение не совпадает с обработчиком, то компилятор отключает выполнение заданным реализацией способом. Таким образом, точный процесс завершения программы зависит от определенного набора программного и аппаратного обеспечения, которое вы используете. Например, компилятор может вызвать std::terminate(), который в свою очередь может вызвать std::abort() неправильно прерывать выполнение. На основе реализации не может быть раскручен стек, прежде чем программа прерывается. Если стек не раскручен перед завершением программы, то деструкторы переменных в стеке не вызываются, ведя к утечке ресурсов и уязвимостям системы обеспечения безопасности.

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

class A{
	A(){
		
		//...
	}	
};

static A obj;

main(){
	//...
}
Статический объект obj создается путем вызова A() перед main() запускается. Поскольку A() называется перед запуском программы никакой обработчик исключений не может быть соответствующим за исключениями, повышенными A(). На основе реализации такое исключение может привести к завершению программы без раскручивания стека, ведя к утечке памяти и уязвимостям системы обеспечения безопасности.

Поскольку исключения, повышенные конструкторами статических или глобальных объектов, не могут быть соответствующими к обработчику исключений, объявите этих конструкторов как noexcept.

Реализация Polyspace

Polyspace® отмечает операторы где non-noexcept конструкторы статического или глобального объекта непосредственно вызываются. Это также подсвечивает несовместимых конструкторов.

Поиск и устранение проблем

Если вы ожидаете нарушение правила, но не видите его, обратитесь к Кодированию Стандартных Нарушений, Не Отображенных.

Примеры

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

В этом примере показано, как Polyspace отмечает конструкторов статических или глобальных объектов.

#include <cstdint>
#include <stdexcept>
#include <string>
class A
{
public:
	A() noexcept : x(0){}
	A(std::int32_t n) : x(n) {
		throw std::runtime_error("Unexpected error"); 
	}
	A(std::int32_t i, std::int32_t j) noexcept : x(i + j)
	{
		try {
			throw std::runtime_error("Error");
		}
		catch (std::exception& e) {
		}
	}
private:
	std::int32_t x;
};

static A a1;     // Compliant
static A a2(5);  // Noncompliant
static A a6(5);  // Ignored because unused
static A a3(5, 10); // Compliant
A a4(5);  //Noncompliant          
A a5(5, 10); //Compliant
int foo_A(A a) { };

int bar_A(int value) {
	A a{value};   //Compliant
	return foo_A(a);
}
int value2b = bar_A(20);   // Compliant
std::string s{"Hello World"};//Noncompliant
int value2a = foo_A(20);   //Noncompliant
int convert(){

	
	return  foo_A(a2);   
}

  • Polyspace отмечает оператор std::string s{"Hello World"}; потому что этот оператор вызывает non-noexcept конструктор строки s перед запуском программы.

  • Polyspace отмечает оператор A a4(5); потому что этот оператор вызывает non-noexcept конструктор A(std::int32_t n) перед запуском программы.

  • Polyspace отмечает оператор static A a2(5); потому что этот оператор вызывает non-noexcept конструктор A(std::int32_t n) перед запуском программы.

  • Polyspace отмечает оператор int value2a = foo_A(20); потому что неявное преобразование из int к A требует вызова non-noexcept конструктор A(std::int32_t n) перед запуском.

  • Polyspace не отмечает оператор static A a6(5);. Поскольку a6 не используется в этом коде, компилятор не создает объект. В результате non-noexcept конструктор A(std::int32_t n) не вызывается перед запуском программы.

  • Polyspace не отмечает оператор A a{value}; в теле функционального bar_A() потому что объект a локально, и это не создается во время запуска программы.

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

Группа: Обработка исключений
Категория: необходимый, автоматизированный