メインコンテンツ

CERT C++: MEM56-CPP

Do not store an already-owned pointer value in an unrelated smart pointer

R2021a 以降

説明

ルール定義

Do not store an already-owned pointer value in an unrelated smart pointer.1

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-> の戻り値である。

リスク

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

修正方法

std::make_shared を使用してスマート ポインターを作成してから、コピー構築を使用して関連するスマート ポインターを作成します。基となるポインター値は両方のスマート ポインターによって管理され、ポインターが指すメモリは両方のスマート ポインターが破棄されるまで割り当て解除されません。

複数のスマート ポインターで同じポインター値を管理できるようにすることを意図していない場合は、std::make_unique を使用してスマート ポインター std::unique_ptr を作成します。std::unique_ptr は移動することしかできません。移動すると、基となる管理対象のポインター値の所有権が放棄されます。

例 — 所有済みポインターの使用

#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

}

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

修正 — std::make_shared とコピー構築を使用して関連するスマート ポインターを作成

#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 func2(){

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

}

修正方法の 1 つとして、std::make_shared を使用して player1_shared を宣言してから、コピー構築を使用して関連するスマート ポインター top_rank_shared を作成します。基となるポインター値は、すべてのスマート ポインターが破棄されるまで削除されません。

チェック情報

グループ: Rule 06.メモリ管理 (MEM)

バージョン履歴

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.