CERT C++: EXP63-CPP

Не полагайтесь на значение перемещенного объекта

Описание

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

Не полагайтесь на значение перемещенного объекта.[1]

Реализация Polyspace

Эта проверка проверяет на чтение значения перемещенного объекта.

Примеры

расширить все

Проблема

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

  • Исходным объектом явной операции перемещения являются следующие типы:

    • std::unique_ptr

    • std::shared_ptr

    • std::weak_ptr

    • std::basic_ios

    • std::basic_filebuf

    • std::thread

    • std::unique_lock

    • std::shared_lock

    • std::promise

    • std::future

    • std::shared_future

    • std::packaged_task

    Эти объекты не остаются в неопределенном состоянии после явного перемещения их состояния.

  • Операция перемещения выполняется неявно. Для образца - функция std::remove может получить доступ к состоянию исходного объекта после неявной операции перемещения. Polyspace не помечает его. Лучшая практика состоит в том, чтобы избегать таких операций и использовать более безопасные альтернативы, которые предотвращают случайный доступ, такие как std::erase.

  • Исходный объект является встроенным базовым типом, таким как: int, enum, float, double, указатель, std::intptr_t, std::nullptr_t.

Риск

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

Зафиксировать

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

Пример - Чтение значения исходного объекта после вызова std::move
#include<string>
#include<iostream>
void F1()
{
	std::string s1{"string"};
	std::string s2{std::move(s1)}; 
	// ...
	std::cout
	<<  // Noncompliant
	s1
	<< "\n";
	// value after move operation
}
void g(std::string v)
{
	std::cout << v << std::endl; 
}

void F3()
{
	std::string s;
	for (unsigned i = 0; i < 10; ++i) {
		s.append(1, static_cast<char>('0' + i));  //Noncompliant 
		g(std::move(s));
	}
}

  • В функциональном F1, строка s1 явно перемещается в s2 по вызову std::move. После операции перемещения функция пытается считать s1. Polyspace помечает эту попытку чтения исходного объекта после явного перемещения.

  • В функциональном F3, строка s явно перемещается, а затем считывается std::string::append функция. Polyspace помечает эту попытку чтения исходного объекта после явного перемещения.

Коррекция - Чтение значений исходных объектов в заданном состоянии
#include<string>
#include<iostream>
void F2()
{
	std::unique_ptr<std::int32_t> ptr1 = std::make_unique<std::int32_t>(0);
	std::unique_ptr<std::int32_t> ptr2{std::move(ptr1)};
	std::cout << ptr1.get() << std::endl; // Compliant by exception
}
void g(std::string v)
{
	std::cout << v << std::endl; 
}
void F4()
{
	for (unsigned i = 0; i < 10; ++i) {
		std::string s(1, static_cast<char>('0' + i)); // Compliant
		g(std::move(s));  
	}
}

  • В функциональном F2, уникальный указатель ptr1 явно перемещается в ptr2. Потому что состояние std::unique_ptr остается в заданном состоянии после перемещения, считывая исходный уникальный указатель после того, как явное перемещение соответствует.

  • В функциональном F4, строка s явно перемещается. В каждой итерации цикла s инициируется к конкретному содержимому перед срабатыванием операции перемещения. В результате состояние s задается перед доступом к объекту. Этот метод доступа к исходному объекту после операции перемещения соответствует этому правилу.

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

Группа: Правило 02. Выражения (EXP)
Введенный в R2021a

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

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

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