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?
c1is also placed incorrectly. The size ofSimpleCharmust be at least8because of thealignas(8). So at offset8into 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
slabis aligned to8. You'll need to addalignas(SimpleChar)to its declaration as well if you want to storeSimpleChars 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-boundsUB 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 charorstd::byte, notchar.)