ПроблемаРазмещение, новое используемый с недостаточным устройством хранения данных или неправильно выровненными указателями, происходит, когда указатель передал размещению new оператор не имеет достаточного устройства хранения данных для выделения памяти или правильно не выравнивается.
Предположим что указатель ptr предварительно выделенный m байты памяти на стеке и имеют выравнивание n. Например, если ptr массив:
выделенным устройством хранения данных является
sizeof(uint8_t) * 5 и выравниванием является
alignof(uint8_t). Если вы выделяете больше, чем
m байты к этому указателю в размещении
new выражение или если выравнивание, требуемое для выделения, больше
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, &c точки к uint8_t значение и имеет однобайтовую память в стеке с однобайтовым выравниванием. Указатель передается размещению new, который создает экземпляр uint64_t это требует 8 байтов памяти и 4-байтового выравнивания. Это использование нарушает правило.
В функциональном Bar, указатель buf правильно выделяется и имеет достаточную емкость памяти. Но, потому что это указывает на uint8_t тип данных, это имеет однобайтовое выравнивание. Это использование все еще нарушает правило.
Функциональный Baz вызывает std::align функция, чтобы создать указатель с правильной емкостью памяти (8 байтов) и выравниванием (4 байта) для uint64_t. Это использование выполняет правило.