heapprofd_client: avoid destruction re-entrancy issues, and global destructor
(1) use unhooked malloc functions for the g_client shared_ptr.
(2) wrap g_client in a base::NoDestructor to avoid the global destructor
(and therefore the associated at-exit issues).
See bug & the contents of the patch for a detailed description of the issue.
Plus new e2e test that would've failed without this fix.
Bug: 129749217
Change-Id: I3d1c34ae133e9b9a43d2a6b6be2ceddbc90ba307
diff --git a/src/profiling/memory/client.h b/src/profiling/memory/client.h
index 9de433c..f39af55 100644
--- a/src/profiling/memory/client.h
+++ b/src/profiling/memory/client.h
@@ -27,6 +27,7 @@
#include "perfetto/base/unix_socket.h"
#include "src/profiling/memory/sampler.h"
#include "src/profiling/memory/shared_ring_buffer.h"
+#include "src/profiling/memory/unhooked_allocator.h"
#include "src/profiling/memory/wire_protocol.h"
namespace perfetto {
@@ -43,15 +44,23 @@
//
// Methods of this class are thread-safe unless otherwise stated, in which case
// the caller needs to synchronize calls behind a mutex or similar.
+//
+// Implementation warning: this class should not use any heap, as otherwise its
+// destruction would enter the possibly-hooked |free|, which can reference the
+// Client itself. If avoiding the heap is not possible, then look at using
+// UnhookedAllocator.
class Client {
public:
// Returns a client that is ready for sampling allocations, using the given
// socket (which should already be connected to heapprofd).
//
// Returns a shared_ptr since that is how the client will ultimately be used,
- // and to take advantage of std::make_shared putting the object & the control
- // block in one block of memory.
- static std::shared_ptr<Client> CreateAndHandshake(base::UnixSocketRaw sock);
+ // and to take advantage of std::allocate_shared putting the object & the
+ // control block in one block of memory.
+ static std::shared_ptr<Client> CreateAndHandshake(
+ base::UnixSocketRaw sock,
+ UnhookedAllocator<Client> unhooked_allocator);
+
static base::Optional<base::UnixSocketRaw> ConnectToHeapprofd(
const std::string& sock_name);
@@ -72,8 +81,8 @@
return sampler_.SampleSize(alloc_size);
}
- // Public for std::make_shared. Use CreateAndHandshake() to create instances
- // instead.
+ // Public for std::allocate_shared. Use CreateAndHandshake() to create
+ // instances instead.
Client(base::UnixSocketRaw sock,
ClientConfiguration client_config,
SharedRingBuffer shmem,