The important pieces of your code line by line…
Allocate memory for one Person object:
auto p = (Person*)malloc(sizeof(Person));
Construct a Person object in that already allocated memory via calling its constructor:
p = new(p)Person();
Free the memory allocated via malloc:
free(p);
Calling the constructor via placement new creates a std::string. That string would be destroyed in the destructor but the destructor is never called. free does not call destructors (just like malloc does not call a constructor).
malloc only allocates the memory. Placement new only constructs the object in already allocated memory. Hence you need to call the destructor before calling free. This is the only case I am aware of where it is correct and necessary to explicitly call a destructor:
auto p = (Person*)malloc(sizeof(Person));
p = new(p)Person();
p->~Person();
free(p);