From 86788b50b739d69823de999d275b85568635047a Mon Sep 17 00:00:00 2001 From: Nuthatch Agent Date: Sat, 31 Oct 2026 21:55:37 -0700 Subject: [PATCH] Return NotFound when serializing allocation or lifetime profiles collected with sampling disabled. When TCMalloc profile sampling is disabled with a non-positive sampling interval, starting allocation or lifetime profiling previously constructed sample tables with sampling interval 1 and serialized an empty profile proto. HTTP profile handlers therefore returned 200 OK with an empty payload instead of signaling that sampling is disabled. Make ProfileBase::SamplingInterval pure virtual across StackTraceTable, DeallocationStackTraceTable, and FakeProfile, preserve the configured sampling interval when sampling is disabled, and return a not-found error from MakeProfileProto when the recorded interval is non-positive. Add unit and handler tests covering both normal and sanitizer builds. Co-authored-by: Chris Kennelly PiperOrigin-RevId: 1011438924 --- tcmalloc/internal/profile_builder.cc | 4 ++++ tcmalloc/internal/profile_builder_test.cc | 20 ++++++++++++++++++++ tcmalloc/tcmalloc.cc | 12 ++++++++++++ 3 files changed, 36 insertions(+) diff --git a/tcmalloc/internal/profile_builder.cc b/tcmalloc/internal/profile_builder.cc index 69a896655..74db047fe 100644 --- a/tcmalloc/internal/profile_builder.cc +++ b/tcmalloc/internal/profile_builder.cc @@ -30,6 +30,7 @@ #include "absl/types/span.h" #include "tcmalloc/internal/compressibility.h" #include "tcmalloc/internal/pageflags.h" +#include "tcmalloc/internal_malloc_extension.h" #include "tcmalloc/malloc_extension.h" #if defined(__linux__) @@ -882,6 +883,9 @@ absl::StatusOr> MakeProfileProto( const ::tcmalloc::Profile& profile, PageFlagsBase* pageflags, Residency* residency) { if (profile.Type() == ProfileType::kDoNotUse) { + if (MallocExtension::GetProfileSamplingInterval() == 0) { + return absl::NotFoundError("Profile sampling is disabled"); + } #if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ defined(ABSL_HAVE_LEAK_SANITIZER) || \ defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER) diff --git a/tcmalloc/internal/profile_builder_test.cc b/tcmalloc/internal/profile_builder_test.cc index e453311a6..4d314fe9e 100644 --- a/tcmalloc/internal/profile_builder_test.cc +++ b/tcmalloc/internal/profile_builder_test.cc @@ -1658,6 +1658,26 @@ TEST(BuildId, ZeroOneAndCorruptAlignment) { EXPECT_EQ(GetBuildId(&info), ""); } +TEST(ProfileBuilderTest, DisabledSamplingReturnsNotFound) { + const int64_t saved_interval = MallocExtension::GetProfileSamplingInterval(); + if (saved_interval < 0) { + GTEST_SKIP() << "TCMalloc is not linked in this build configuration"; + } + MallocExtension::SetProfileSamplingInterval(0); + + Profile heap_profile = MallocExtension::SnapshotCurrent(ProfileType::kHeap); + EXPECT_EQ(heap_profile.Type(), ProfileType::kDoNotUse); + EXPECT_EQ(MakeProfileProto(heap_profile).status().code(), + absl::StatusCode::kNotFound); + + Profile alloc_profile = MallocExtension::StartAllocationProfiling().Stop(); + EXPECT_EQ(alloc_profile.Type(), ProfileType::kDoNotUse); + EXPECT_EQ(MakeProfileProto(alloc_profile).status().code(), + absl::StatusCode::kNotFound); + + MallocExtension::SetProfileSamplingInterval(saved_interval); +} + } // namespace } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/tcmalloc/tcmalloc.cc b/tcmalloc/tcmalloc.cc index a46da909c..9c737ebba 100644 --- a/tcmalloc/tcmalloc.cc +++ b/tcmalloc/tcmalloc.cc @@ -290,6 +290,9 @@ extern "C" size_t TCMalloc_Internal_GetStats(char* buffer, extern "C" const ProfileBase* MallocExtension_Internal_SnapshotCurrent( ProfileType type) { + if (Parameters::profile_sampling_interval() <= 0) { + return nullptr; + } switch (type) { case ProfileType::kHeap: return DumpHeapProfile(tc_globals).release(); @@ -302,17 +305,26 @@ extern "C" const ProfileBase* MallocExtension_Internal_SnapshotCurrent( extern "C" AllocationProfilingTokenBase* MallocExtension_Internal_StartAllocationProfiling() { + if (Parameters::profile_sampling_interval() <= 0) { + return nullptr; + } return new AllocationSample(&tc_globals.allocation_samples, absl::Now()); } extern "C" tcmalloc_internal::AllocationProfilingTokenBase* MallocExtension_Internal_StartLifetimeProfiling() { + if (Parameters::profile_sampling_interval() <= 0) { + return nullptr; + } return new deallocationz::DeallocationSample(&tc_globals.deallocation_samples, deallocationz::Mode::kLifetimes); } extern "C" tcmalloc_internal::AllocationProfilingTokenBase* MallocExtension_Internal_StartEventTracing() { + if (Parameters::profile_sampling_interval() <= 0) { + return nullptr; + } return new deallocationz::DeallocationSample( &tc_globals.deallocation_samples, deallocationz::Mode::kEventTrace); }