https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96946
--- Comment #2 from Jonathan Wakely <redi at gcc dot gnu.org> --- Ah I see what's wrong. We do the static_cast before creating an object at that address: #include <new> namespace x __attribute__((visibility("default"))) { template<typename T> struct buffer { alignas(__alignof__(T)) unsigned char buf[sizeof(T)]; void* addr() { return static_cast<void*>(buf); } T* ptr() { return static_cast<T*>(addr()); } }; } struct IReporterFactory { virtual ~IReporterFactory() = default; }; class ReporterFactory : public IReporterFactory {}; int main() { auto p = new x::buffer<ReporterFactory>; auto p2 = p->ptr(); // undefined here ::new(static_cast<void*>(p2)) ReporterFactory; p->ptr()->~ReporterFactory(); delete p; } But we have to do this, because we need to pass a T* to the allocator_traits::construct function. This clang sanitizer seems incompatible with any allocator that allocates bytes and then casts std::byte* or unsigned char* to T*. For example, this also fails at runtime: #include <memory> struct IReporterFactory { virtual ~IReporterFactory() = default; }; class ReporterFactory : public IReporterFactory {}; int main() { alignas(alignof(ReporterFactory)) unsigned char b[sizeof(ReporterFactory)]; using A = std::allocator<ReporterFactory>; A a; std::allocator_traits<A>::construct(a, reinterpret_cast<ReporterFactory*>(b)); std::allocator_traits<A>::destroy(a, reinterpret_cast<ReporterFactory*>(b)); }