メインコンテンツ

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

オーバーアラインの可能性のあるクラスの演算子 new がオーバーロードされていません

割り当てられたストレージがオブジェクトのアライメント要件よりも小さい可能性がある

説明

この欠陥は、演算子 new/new[] を適切にオーバーロードせずに、その演算子を使用して、alignas で指定されたアライメント要件をもつオブジェクトを作成した場合に発生します。チェッカーは、以下のバージョンのスロー演算子および非スロー演算子 new/new[] に対して欠陥を報告します。

  • void* operator new(std::size_t size)

  • void* operator new(std::size_t size, const std::nothrow_t&)

  • void* operator new[](std::size_t size)

  • void* operator new[](std::size_t size, const std::nothrow_t&)

alignas の使用は、既定の演算子 new/new[] がアライメント要件またはオブジェクト型が保証されることを期待していないこと、またはそのオブジェクトがオーバーアラインされる可能性があることを示します。型がオーバーアラインされるのは、alignas を使用して、その型のアライメント要件を std::max_align_t よりも大きくした場合です。たとえば、このコード スニペットにおいて、foo はアライメント要件が 32 バイトであるためオーバーアラインされていますが、std::max_align_t はほとんどの実装において 16 バイトのアライメントをもちます。

struct alignas(32) foo {
  char elems[32];
}

オーバーアラインの可能性のあるクラスの演算子 new がオーバーロードされていませんは、演算子 new/new[] をオーバーロードせずに C++17 以降の規格を使用した場合、欠陥を報告しません。C++17 以降の既定の演算子 new/new[] は、アライメント要件を std::align_val_t 型の引数として渡すことにより (たとえば、void* operator new(std::size_t size, std::align_val_t alignment))、オーバーアラインをサポートします。

リスク

既定の演算子 new/new[] により、最大で std::align_val_t となるアライメント要件がストレージに割り当てられます。オーバーアライン型をもつオブジェクトの作成時に演算子をオーバーロードしない場合、得られるオブジェクトはミスアライメントとなる可能性があります。そのオブジェクトにアクセスすると、不正アクセス エラーやプログラムの異常終了が引き起こされる可能性があります。

修正方法

C++14 以前のバージョンの規格を使用する場合、演算子 new/new[] をオーバーロードすることにより、オーバーアラインされた型のアライメント要件をこの演算子に渡します。

すべて展開する

#include <new>
#include <cstdlib>
#include <iostream>

struct alignas(64) foo {
    char elems[32];
};

foo*  func()
{
    foo*  bar = 0x0;
    try {
        bar =  new  foo ;
    } catch (...) { return nullptr; }
    delete bar;
}

この例では、構造体 foo のアライメント要件が 32 バイトであると宣言されています。既定の演算子 new を使用してオブジェクト bar を作成する場合、bar に割り当てられたメモリは foo 型のアライメント要件よりも小さくなり、bar がミスアライメントとなる可能性があります。

修正 — オーバーロードされた演算子 new を定義して foo 型のアライメント要件を処理

1 つの修正方法として、C11 stdlib.h または POSIX-C malloc.h を使用するのであれば、aligned_alloc() または posix_memalign() を使用するオーバーロードされた演算子 new を定義するか、正しいアライメントのストレージを取得します。

#include <new>
#include <cstdlib>
#include <iostream>

struct alignas(64) foo {
    char elems[32];
    static void* operator new (size_t nbytes)
    {
        if (void* p =
                ::aligned_alloc(alignof(foo), nbytes)) {
            return p;
        }
        throw std::bad_alloc();
    }
    static void operator delete(void *p) {
        free(p);
    }
};

foo*  func()
{
    foo*  bar = 0x0;
    try {
        bar =  new  foo ;
    } catch (...) { return nullptr; }
    delete bar;
} 

結果情報

グループ: オブジェクト指向
言語: C++
既定値: 手書きコードはオン、生成コードはオフ
コマンド ライン構文: MISSING_OVERLOAD_NEW_FOR_ALIGNED_OBJ
影響度: Medium

バージョン履歴

R2019b で導入