メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

CERT C++: EXP63-CPP

Do not rely on the value of a moved-from object

R2021a 以降

説明

ルール定義

Do not rely on the value of a moved-from object.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 などの偶発的なアクセスが発生しないより安全な代替手段を利用することです。

  • ソース オブジェクトは、次のような組み込みの基本型のオブジェクトです。intenumfloatdouble、pointer、std::intptr_tstd::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 では、std::move の呼び出しによって、文字列 s1s2 に明示的に移動されます。移動演算後に、この関数は 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 では、ユニーク ポインター ptr1ptr2 に明示的に移動されます。std::unique_ptr は移動後も指定された状態のままであるため、明示的な移動の後のソース ユニーク ポインターの読み取りは準拠しています。

  • 関数 F4 では、文字列 s が明示的に移動されます。ループの反復ごとに、移動操作がトリガーされる前に、s が特定の内容に初期化されます。そのため、オブジェクトがアクセスされる前に s の状態が指定されます。この移動操作の後のソース オブジェクトへのアクセス方法はこのルールに準拠しています。

チェック情報

グループ: Rule 02.式 (EXP)

バージョン履歴

R2021a で導入


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.