ПроблемаРазмещение, новое используемый с недостаточным устройством хранения данных или неправильно выровненными указателями, происходит, когда указатель передал размещению 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
. Это использование выполняет правило.