使用placement new操作符时如何检查是否超出范围?

Lea*_*rog 2 c++ valgrind placement-new c++17

在下面的代码中

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
}
Run Code Online (Sandbox Code Playgroud)

c2并且c3建造在错误的地方。但如何检测呢?在这种情况下,valgrind和valgrind 都-fsanitize=address不起作用。

我想知道如何检测这种错误的用法?

use*_*522 5

c1也放置不正确。的大小SimpleChar必须至少是8因为alignas(8). 因此,在8数组偏移处,不再有足够的空间。

根据您显示的选项,我假设您使用 GCC 或 Clang。

在这种情况下-fsanitize=undefined,具体来说-fsanitize=alignment,可能会抱怨,因为示例中的偏移量与类型不对齐。

事实上,通常您的所有展示位置新闻都有 UB,因为不能保证与slab对齐8。如果您想在其中alignas(SimpleChar)存储 s,您还需要添加到它的声明中。SimpleChar

-fsanitize=undefined具体来说,在 Clang 上-fsanitize=array-bounds,还会抱怨存储阵列上的访问越界。

GCC 似乎不支持array-boundsUB 消毒剂检查,而是抱怨 中包含警告-Wall,特别是-Wplacement-new

(此外,从技术上讲,用于为其他对象提供存储的数组应该具有元素类型unsigned charstd::byte,而不是char。)