exponenta event banner

Новый оператор не перегружен для класса, возможно, перекалиброванного

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

Описание

Этот дефект возникает при недостаточной перегрузке оператора 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[] и вы используете версию 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 или более ранняя версия стандарта, передайте оператору требование выравнивания для выровненных типов 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++
По умолчанию: Вкл для рукописного кода, выкл для сгенерированного кода
Синтаксис командной строки: MISSING_OVERLOAD_NEW_FOR_ALIGNED_OBJ
Воздействие: среднее
Представлен в R2019b