Is it true?
Yes. Technically speaking, no part of:
int *p = (int*)malloc(sizeof(int));
actually creates an object of type int, so dereferencing p is UB since there is no actual int there.
Do we really have to call default constructor that is trivial to start the life time of the object?
Do you have to per the C++ object model to avoid undefined behavior pre-C++20? Yes. Will any compiler actually cause harm by you not doing this? Not that I’m aware of.
[…] Is it still undefined behavior?
Yes. Pre-C++20, you still didn’t actually create an int object anywhere so this is UB.