メインコンテンツ

AUTOSAR C++14 Rule A20-8-1

An already-owned pointer value shall not be stored in an unrelated smart pointer

R2021a 以降

説明

ルール定義

An already-owned pointer value shall not be stored in an unrelated smart pointer.

根拠

スマート ポインターを使用する目的は、たとえばポインターがスコープから外れた場合など、ポインターが破棄される際にポインターが指すメモリが必ず自動的に割り当て解除されるようにするためです。複数の無関係のスマート ポインターが同じポインター値を管理する場合、スマート ポインターのいずれか 1 つが、他のスマート ポインターによって既に割り当て解除されたメモリの割り当て解除を試みる可能性があります。これによって生じる二重解放の脆弱性により、プログラムのメモリ管理データ構造体が破損します。

スマート ポインターは、スマート ポインターの初期化に使用されるポインター値を所有します。ポインター値が既に std::shared_ptr などのスマート ポインターによって所有されている場合は、そのスマート ポインターを使用して、2 つのスマート ポインターが関連するコピー操作などで別のスマート ポインターを初期化します。基となるポインター値は両方のスマート ポインターによって管理され、ポインターが指すメモリは両方のスマート ポインターが破棄されるまで割り当て解除されません。

Polyspace 実装

Polyspace® は、所有済みのポインターを以下の引数として使用した場合にフラグを設定します。

  • スマート ポインター コンストラクター。たとえば、このコード スニペットでは、既に s_ptr1 に所有されている raw_ptrs_ptr2 の初期化に使用されます。

    char *raw_ptr = new char;
    std::shared_ptr<char> s_ptr1(raw_ptr);
    std::shared_ptr<char> s_ptr2(raw_ptr); //raw_ptr is already owned by s_ptr1

  • スマート ポインター リセット演算。たとえば、このコード スニペットでは、s_ptr2 のリセットにより、raw_ptr2 が所有済み raw_ptr1 で置き換えられます。

    char *raw_ptr1 = new char;
    char *raw_ptr2 = new char;
    
    std::shared_ptr<char> s_ptr1(raw_ptr1);
    std::shared_ptr<char> s_ptr2(raw_ptr2);
    
    s_ptr2.reset(raw_ptr1); // s_ptr2 releases raw_ptr2 and owns already owned raw_ptr1

Polyspace は、スマート ポインターの std::shared_ptr 型および std::unique_ptr 型のみをチェックし、ユーザー定義のアロケーターとデリーターの割り当て動作、割り当て解除動作が標準的なものであると見なします。

ポインターの型が std::nullptr_t ではなく、以下のいずれかの場合、ポインターはスマート ポインターに既に所有されています。

  • ポインターがスマート ポインターの初期化に使用された。

  • ポインターがスマート ポインターのメンバー関数 reset() への引数として使用された。

  • ポインターがスマート ポインターのメンバー関数 get() の戻り値である。

  • ポインターがスマート ポインターのメンバー関数 operator-> の戻り値である。

トラブルシューティング

ルール違反が想定されるものの、Polyspace から報告されない場合は、コーディング規約違反が想定どおりに表示されない理由の診断を参照してください。

すべて展開する


#include <memory>
#include <string>

struct Profile
{
    virtual ~Profile()=default;
};

struct Player : public Profile
{
    std::string name;
    std::int8_t rank;

    Player();
    Player(const std::string& name_, const std::int8_t& rank_) :
        name{ name_ }, rank{ rank_ } {}
};

void func(){

    Player * player = new Player("Richard Roll",1);
    std::shared_ptr<Player> player1(player);
    std::shared_ptr<Player> top_rank(player); //Non-compliant

}

void func2(){

    std::shared_ptr<Player> player1_shared =
        std::make_shared<Player>("Richard Roll",1);
    std::shared_ptr<Player> top_rank_shared(player1_shared); //Compliant

}

この例では、関数 func でポインター値 player を使用してスマート ポインター top_rank を作成するのは非準拠です。player はスマート ポインター player1 に既に所有されています。player1 は破棄される際に、既に top_rank によって削除されたポインター値 player を削除しようと試みます。

複数のスマート ポインターに同じポインター値を管理させる場合は、std::make_shared を使用して player1_shared を宣言してから、コピー構築を使用して、関連するスマート ポインター top_rank_sharedfunc2 などで作成します。基となるポインター値は、すべてのスマート ポインターが破棄されるまで削除されません。

複数のスマート ポインター間でポインター値を共有しない場合は、std::make_unique を使用して std::unique_ptr 型のスマート ポインターを構築します。std::unique_ptr は移動することしかできません。移動すると、基となる管理対象のポインター値の所有権が放棄されます。

チェック情報

グループ: General utilities library
カテゴリ: Required、Automated

バージョン履歴

R2021a で導入