提问人:Leapfrog 提问时间:10/11/2023 最后编辑:Paul FloydLeapfrog 更新时间:10/11/2023 访问量:154
使用放置新运算符时如何检查超出范围?
How to check out-of-range when using placement new operator?
问:
在以下代码中
struct alignas(8) SimpleChar {
SimpleChar(char c_) : c(c_) {}
char c;
};
int main() {
char slab[10] = {'\0'};
// call to 'SimpleChar::SimpleChar(char)' too
SimpleChar* c0 = new (slab) SimpleChar('a');
SimpleChar* c1 = new (slab + 8) SimpleChar('b');
SimpleChar* c2 =
new (std::launder(reinterpret_cast<char*>(slab + 80))) SimpleChar('d'); // But how to detect the wrong usage?
std::cout << c2->c << std::endl; // d
SimpleChar* c3 = new (slab + 180) SimpleChar('e'); // But how to detect the wrong usage?
std::cout << c3->c << std::endl; // e
}
c2
并且建在错误的地方。但是如何检测它呢?
在这种情况下,valgrind 和 don-work 都不起作用。c3
-fsanitize=address
我想知道如何检测这种错误的用法?
答:
c1
也放置不正确。的大小必须至少是因为 .因此,在偏移到数组中时,不再有足够的空间容纳一个。SimpleChar
8
alignas(8)
8
根据您显示的选项,我假设您使用 GCC 或 Clang。
在这种情况下,特别是 ,可能会抱怨,因为示例中的偏移量与类型未对齐。-fsanitize=undefined
-fsanitize=alignment
事实上,通常您的所有展示位置新闻都有 UB,因为不能保证它与 .如果你想在其中存储 s,你也需要添加到它的声明中。slab
8
alignas(SimpleChar)
SimpleChar
在 Clang 上,具体来说,还会抱怨存储阵列上的越界访问。-fsanitize=undefined
-fsanitize=array-bounds
GCC 似乎不支持 UB 消毒剂检查,而是抱怨 ,特别是 .array-bounds
-Wall
-Wplacement-new
(此外,从技术上讲,用于为其他对象提供存储的数组应具有元素类型 或 ,而不是 。unsigned char
std::byte
char
评论
Valgrind memcheck 截获并验证堆分配和释放函数。
placement new 运算符不是这样的函数。
因此,重要的是为放置新提供的记忆。Memcheck 不会对堆栈内存执行边界检查(除非访问偏离)。@user17732522似乎已经回答了 LLVM 消毒剂的问题。
评论
size_t indexToInsert = ...; if(indexToInsert < std::size(slab)) { /* can safely construct a new element */ } else { /* out of range – some appropriate error handling */ }
cN
c0
c1