In the following code
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
and c3
are constructed in a wrong place. But how to detect it?
In this case, both valgrind and -fsanitize=address
don't work.
I'm wondering how to detect such wrong usage?
c1
is also placed incorrectly. The size of SimpleChar
must be at least 8
because of the alignas(8)
. So at offset 8
into the array there isn't enough space for one anymore.
Based on the options you showed, I assume you use GCC or Clang.
In that case -fsanitize=undefined
, specifically -fsanitize=alignment
, may complain because the offsets in your example are misaligned for the type.
In fact, generally all of your placement-news have UB, because it isn't guaranteed that slab
is aligned to 8
. You'll need to add alignas(SimpleChar)
to its declaration as well if you want to store SimpleChar
s in it.
On Clang -fsanitize=undefined
, specifically -fsanitize=array-bounds
, will also complain for access out-of-bounds on the storage array.
GCC doesn't seem to support the array-bounds
UB sanitizer check, but instead complains with a warning included in -Wall
, specifically -Wplacement-new
.
(Also, technically, an array that is used to provide storage for other objects should have element type unsigned char
or std::byte
, not char
.)