exponenta event banner

Правило AUTOSAR C++ 14 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 ®, где не -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"}; потому что этот оператор вызывает не -noexcept конструктор строки s перед запуском программы.

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

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

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

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

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

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

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