After reading the standard some more, it doesn't say anything about malloc.
It says that if the constructor is not called, there is no object there and therefor is UB to access that object through pointer or reference.
To be C++ complaint it would have to look like something like this:
x* AllocateXFromStorage(storage* Storage);
void Foo()
{
x* X= AllocateXFromStorage(Storage);
new (X) x; // <- add this bullshit
// .. use it here
}
If AllocateXFromStorage returns properly aligned address and new (X) x is called even if it doesn't do anything on POD,
and will get optimized out by the compiler than this is C++ Standard complaint and not a UB.
Without new(X) x; it is but every compiler that I have checked (gcc, clang, msvc) will do what it is expected.
There is even a proposal to fix this for sufficiently trivial types.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0593r4.html