Operator new not overloaded for possibly overaligned class

Выделенное хранилище может быть меньше, чем требование выравнивания объекта

Описание

Этот дефект возникает, когда вы не должным образом перегружаете оператора 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 not perloaded для возможно переопределенного класса не повышает дефект, если вы не перегрузите оператор new/new[] и вы используете версию C++ 17 или более позднюю Стандартную. Оператор по умолчанию new/new[] в C++ 17 или более поздней версии поддерживает выравнивание путем передачи требования выравнивания в качестве аргумента типа std::align_val_t, для образца void* operator new(std::size_t size, std::align_val_t alignment).

Риск

Оператор по умолчанию new/new[] выделяет хранилище с требованиями выравнивания std::align_val_t самое большее. Если вы не перегружаете оператор, когда вы создаете объект с выровненным выше типом, результирующий объект может быть смещен. Доступ к этому объекту может привести к ошибкам доступа или ненормальным завершениям программы.

Зафиксировать

Если вы используете версию C++ 14 или более раннюю версию Standard, передайте требование выравнивания по выровненным типам оператору 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

Одна возможная коррекция, если вы используете C11 stdlib.h или POSIX-C malloc.h, определяет перегруженный оператор new который использует aligned_alloc() или posix_memalign() или получить хранение с правильной выравниванием.

#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++
По умолчанию: On для рукописного кода, off для сгенерированного кода
Синтаксис командной строки : MISSING_OVERLOAD_NEW_FOR_ALIGNED_OBJ
Влияние: Средний
Введенный в R2019b