メインコンテンツ

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

CERT C++: MEM54-CPP

Provide placement new with properly aligned pointers to sufficient storage capacity

説明

ルール定義

Provide placement new with properly aligned pointers to sufficient storage capacity1

Polyspace 実装

ルール チェッカーは、"不十分なストレージまたは正しくアライメントされていないポインターと一緒に使用された配置 new" をチェックします。

すべて展開する

問題

不十分なストレージまたは正しくアライメントされていないポインターと一緒に使用された配置 new は、配置 new 演算子に渡されたポインターがメモリ割り当てに十分なストレージを指していないか、適切にアライメントされていない場合に発生します。

ポインター ptr がスタック上に事前割り当てされた m バイトのメモリを指し、アライメントが n であるものとします。たとえば、ptr が配列である場合、次のようになります。

uint8_t ptr[5];
割り当てられるストレージは sizeof(uint8_t) * 5 で、アライメントは alignof(uint8_t) です。配置 new 式でこのポインターに m バイトを超える割り当てを行ったり、割り当てで必要なアライメントが n より大きい場合、チェッカーは違反を報告します。ポインター アライメントを判断する際、チェッカーは std::align などの明示的なアライメントを考慮に入れます。

チェッカーはヒープ上に事前割り当てされたメモリのポインターを考慮に入れません。使用可能なストレージは使用可能なメモリに依存するからです。これは実行時にならないとわかりません。

リスク

new 演算子は単一操作で、オブジェクトの保存に必要な量のメモリをヒープ上に割り当て、割り当てられたメモリに新しいオブジェクトを構築します。割り当てと構築を分離し、オブジェクトをスタック上またはヒープ上の事前割り当てメモリに配置するには、配置 new を使用します。配置 new は特定の状況、たとえば、オブジェクトを既知のメモリ位置に配置する必要がある場合などに、new よりも有利です。

new 演算子は、オブジェクトに必要な正しい量のアライメント済みメモリを自動的に割り当てます。一方、配置 new を使用する場合は、渡すポインターに十分なストレージ容量があり、正しくアライメントされていることを手動で確認しなければなりません。この制約に違反すると、オブジェクトがアライメントされていない場所に構築されたり、割り当て境界外のメモリが初期化されたりして、予期しない動作、あるいは実装によって異なる動作を引き起こす可能性があります。

修正方法

配置 new の演算で使用されるポインターが割り当てに十分なメモリを指し、アライメントが一致することを確認します。

例 — 不十分なストレージ容量と正しくアライメントされていないポインターと一緒に使用された配置 new
#include <new>
#include<memory>
#include <cstdint>

void Foo()
{
  uint8_t c;                
  uint64_t* ptr =
      new    // Non-compliant (insufficient storage, misaligned)
      (&c) uint64_t;
}

void Bar()
{
  uint8_t buf[sizeof(uint64_t)];    
  uint64_t* ptr =
      new            // Non-compliant (sufficient storage, misaligned)
      (buf) uint64_t;
}

void Baz()
{
  void* buf;
  std::size_t sp = 64;
  std::align(alignof(uint64_t), sizeof(uint64_t), buf, sp);
  uint64_t* ptr =
      new            // Compliant (sufficient storage, aligned)
      (buf) uint64_t;
}

関数 Foo では、&cuint8_t 値を指し、1 バイト アライメントのスタックに 1 バイトのメモリを持っています。ポインターが配置 new に渡され、8 バイトのメモリと 4 バイト アライメントを必要とする uint64_t のインスタンスを構築します。この使用方法はルールに違反します。

関数 Bar では、ポインター buf は正しく割り当てられ、十分なストレージ容量があります。しかし、uint8_t データ型を指し、1 バイト アライメントです。この使用方法もルールに違反します。

関数 Baz は関数 std::align を呼び出して、uint64_t に対して正しいストレージ容量 (8 バイト) で正しいアライメント (4 バイト) のポインターを作成します。この使用方法はルールに準拠しています。

チェック情報

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

バージョン履歴

R2020b で導入


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.