MEM54-CPP. 为 placement new 提供足够内存容量的正确对齐的指针
原文链接:
MEM54-CPP. Provide placement new with properly aligned pointers to sufficient storage capacity
当为给定类型调用 new
表达式, operator new
的默认全局 non-placement 形式试图给该类型对象分配足够的内存空间, 如果成功, 返回一个对齐指针–适用于任何有基本对齐要求的对象. 然而, 默认 placement new
操作符简单地将已知的指针返回给调用者–不保证有足够的内存空间去构造对象或者确保该指针满足正确的对齐要求. C++ 标准, [expr.new], 段落 16 [ISO/IEC 14882-2014], 非规范陈述如下:
[备注: 当分配函数返回了一个非空值, 这必须是一个指向已经被预留的存储区块的指针. 这个存储区块假设被正确对齐且具有所申请的尺寸大小. 如果对象是数组, 所创建的对象地址不必和该存储区块的地址相同. —备注结束]
[Note: when the allocation function returns a value other than null, it must be a pointer to a block of storage in which space for the object has been reserved. The block of storage is assumed to be appropriately aligned and of the requested size. The address of the created object will not necessarily be the same as that of the block if the object is an array. —end note]
(这个备注是 C++ 标准所规定的常规要求的提醒, [basic.stc.dynamic.allocation], 段落 1, 借助 [basic.stc.dynamic], 段落 3, 作用于 placement new
操作符)
此外, 标准在这章节后面提供了一个例子:
1 new(2, f) T[5] `results in a call` of operator new[](sizeof(T) * 5 + y, 2, f).这里,
...
和y
是未指明的非负值, 表示数组分配的开销; new 表达式的结果将会补偿operator new[]
返回值的大小. 这个开销可能被作用于所有的 new 表达式, 包括那些引用于库函数operator new[](std::size_t, void*)
和其他 placement 分配函数. 这个开销大小可能因每次 new 调用的不同而不同.Here,
...
andy
are non-negative unspecified values representing array allocation overhead; the result of the new-expression will be offset by this amount from the value returned byoperator new[]
. This overhead may be applied in all array new-expressions, including those referencing the library functionoperator new[](std::size_t, void*)
and other placement allocation functions. The amount of overhead may vary from one invocation of new to another.
不要向 placement new
传递一个用于构造对象的未正确对齐的指针. 这会导致对象被构造在一个错误对齐的位置, 导致 未定义行为, undefined behavior. 不要传递一个没有足够存储容量来构造对象的指针, 包括数组需补偿的大小. 这可能导致用于构造该对象的内存初始化时越界.
最后, 不要在任何没有指明所需开销限度的平台上使用 placement new[]
.
不合规代码示例
在这个不合规的代码示例中, 一个指向 short
的指针被传入到 placement new
, 试图用来初始化一个 long
. 在 sizeof(short) < sizeof(long)
的架构上, 这导致 未定义行为, undefined behavior. 这个以及后面的例子, 都假设 placement new
返回的指针不会在其生命周期结束后被使用. 举个例子, 该指针不会被存储在一个 静态
全局变量中, 且在 f()
调用结束后不会被解引用. 这个假设符合 MEM50-CPP. Do not access freed memory.
1 |
|
不合规代码示例
这个不合规的代码示例确保 在足够大小的缓冲区中构造 long
. 然而, 这不能保证传入到 placement new
的指针满足对齐要求. 为了使这个例子更加清晰, 声明了另一个局部变量 c
.
1 |
|
合规方案 (alignas
)
在这个合规方案中, 声明修饰符 alignas
被用来确保用于 long
的缓冲区是正确对齐的.
1 |
|
合规方案 (std::aligned_storage
)
这个合规方案确保在足够大小且正确对齐的缓冲区中构造 long
.
1 |
|
不合规代码示例 (Failure to Account for Array Overhead)
这个不合规代码示例试图为对象 S
的数组分配正确对齐且充足的内存空间. 然而, 这错误计算了开销–实现可能会为数组对象增加存储大小. 这类开销 (一般称为 cookie ) 是必需的–存储数组中元素的数目, 以便于数组删除表达式或者异常解构机制 (注: exception unwinding mechanism) 可以调用数组中每个被成功构造元素的析构函数. 但是有些实现在某些情况下能够避免给 cookie 分配空间, 假设它们在所有情况下的操作是不安全的.
1 |
|
合规方案 (Clang/GCC)
数组 new
表达式所需的开销大小是不明确的, 但是理想情况下, 这应该被良好的实现记录下来. 下述的合规方案是特地为 Clang 和 GNU GCC 编译器的, 这保证了动态数组分配的开销是单个类型 size_t
的值. (注意这个值一般会被当做数组的 “第-1个” 元素, 所以实际被使用的空间可能会更大.) 为了证实这个假设实际上是安全的, 该合规方案也重载了 placement new[]
操作符来接受缓冲区大小–作为第三个参数, 并且证实这不比所需的存储空间总大小小.
1 |
|
将该合规方案移植到其他实现需要增加类似开销常数的条件定义–依赖于平台的约束.
风险预估
向 placement new
表达式传递不正确对齐的指针或者指向不充足存储空间的指针会导致 未定义行为, undefined behavior, 包括缓冲区溢出和 异常终止, abnormal termination.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MEM54-CPP | High | Likely | Medium | P18 | L1 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
Axivion Bauhaus Suite | CertC++-MEM54 | ||
Helix QAC | C++3119, C++3128 | ||
LDRA tool suite | 597 S** ** | Enhanced Enforcement | |
Parasoft C/C++test | CERT_CPP-MEM54-a CERT_CPP-MEM54-b | Do not pass a pointer that has insufficient storage capacity or that is not suitably aligned for the object being constructed to placement ‘new’ An overhead should be used when an array of objects is passed to the placement ‘new’ allocation function | |
Polyspace Bug Finder | CERT C++: MEM54-CPP | Checks for placement new used with insufficient storage or misaligned pointers (rule fully covered) | |
PVS-Studio | V752 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
SEI CERT C++ Coding Standard | MEM50-CPP. Do not access freed memory |
---|---|
Bibliography
[ISO/IEC 14882-2014] | Subclause 3.7.4, “Dynamic Storage Duration” Subclause 5.3.4, “New” |
---|---|
本文标题:MEM54-CPP. 为 placement new 提供足够内存容量的正确对齐的指针
文章作者:xwnb
发布时间:2021-11-14
最后更新:2023-04-17
原始链接:https://xwnb.github.io/posts/1817611852/
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!并保留本声明。感谢您的阅读和支持!
分享