Skip to content

Commit

Permalink
Add a test suitable for exercising malloc under sanitizers.
Browse files Browse the repository at this point in the history
When sanitizers are linked in, they provide their own implementations of
malloc/new/etc.  To run this test, we work directly with TCMalloc's
implementation details for these methods.

PiperOrigin-RevId: 573020105
Change-Id: I15631f724f003b7bd52fcf071df01bb7483667c4
  • Loading branch information
ckennelly authored and copybara-github committed Oct 12, 2023
1 parent 188865b commit 0cb7acb
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 0 deletions.
20 changes: 20 additions & 0 deletions tcmalloc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,26 @@ cc_library(
alwayslink = 1,
)

cc_library(
name = "tcmalloc_internal_methods_only",
srcs = [
"tcmalloc.cc",
"tcmalloc.h",
],
copts = TCMALLOC_DEFAULT_COPTS + [
"-DTCMALLOC_INTERNAL_METHODS_ONLY",
],
linkstatic = 1,
visibility = ["//tcmalloc:__subpackages__"],
deps = tcmalloc_deps + [
":common_8k_pages",
"//tcmalloc/internal:allocation_guard",
"//tcmalloc/internal:overflow",
"//tcmalloc/internal:page_size",
],
alwayslink = 1,
)

# Provides tcmalloc always; use per-thread mode.
cc_library(
name = "tcmalloc_deprecated_perthread",
Expand Down
9 changes: 9 additions & 0 deletions tcmalloc/tcmalloc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,12 @@ using tcmalloc::tcmalloc_internal::MallocAlignPolicy;
using tcmalloc::tcmalloc_internal::MultiplyOverflow;

// depends on TCMALLOC_HAVE_STRUCT_MALLINFO, so needs to come after that.
#ifndef TCMALLOC_INTERNAL_METHODS_ONLY
#include "tcmalloc/libc_override.h"
#else
#define TCMALLOC_ALIAS(tc_fn) \
__attribute__((alias(#tc_fn), visibility("default")))
#endif // !TCMALLOC_INTERNAL_METHODS_ONLY

extern "C" ABSL_CACHELINE_ALIGNED void* TCMallocInternalMalloc(
size_t size) noexcept {
Expand All @@ -1110,6 +1115,7 @@ extern "C" ABSL_CACHELINE_ALIGNED void* TCMallocInternalNewNothrow(
return fast_alloc(CppPolicy().Nothrow(), size);
}

#ifndef TCMALLOC_INTERNAL_METHODS_ONLY
extern "C" ABSL_CACHELINE_ALIGNED ABSL_ATTRIBUTE_SECTION(google_malloc)
tcmalloc::sized_ptr_t tcmalloc_size_returning_operator_new(size_t size) {
return fast_alloc(CppPolicy().SizeReturning(), size);
Expand Down Expand Up @@ -1146,6 +1152,7 @@ extern "C" ABSL_CACHELINE_ALIGNED ABSL_ATTRIBUTE_SECTION(google_malloc)
.SizeReturning(),
size);
}
#endif // !TCMALLOC_INTERNAL_METHODS_ONLY

extern "C" ABSL_CACHELINE_ALIGNED void* TCMallocInternalMemalign(
size_t align, size_t size) noexcept {
Expand Down Expand Up @@ -1540,6 +1547,7 @@ static TCMallocGuard module_enter_exit_hook;
} // namespace tcmalloc
GOOGLE_MALLOC_SECTION_END

#ifndef TCMALLOC_INTERNAL_METHODS_ONLY
ABSL_CACHELINE_ALIGNED void* operator new(
size_t size, tcmalloc::hot_cold_t hot_cold) noexcept(false) {
if (hot_cold >= Parameters::min_hot_access_hint()) {
Expand Down Expand Up @@ -1623,3 +1631,4 @@ ABSL_CACHELINE_ALIGNED void* operator new[](
size);
}
}
#endif // !TCMALLOC_INTERNAL_METHODS_ONLY
15 changes: 15 additions & 0 deletions tcmalloc/testing/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -903,3 +903,18 @@ create_tcmalloc_testsuite(
"@com_google_googletest//:gtest_main",
],
)

cc_test(
name = "parallel_test",
srcs = ["parallel_test.cc"],
copts = TCMALLOC_DEFAULT_COPTS,
malloc = "//tcmalloc/internal:system_malloc",
tags = ["nomsan"],
deps = [
"//tcmalloc:tcmalloc_internal_methods_only", # buildcleaner: keep
"@com_google_absl//absl/base:config",
"@com_google_absl//absl/random",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
],
)
94 changes: 94 additions & 0 deletions tcmalloc/testing/parallel_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright 2023 The TCMalloc Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <atomic>
#include <cstddef>
#include <thread>
#include <vector>

#include "gtest/gtest.h"
#include "absl/base/config.h"
#include "absl/random/random.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"

extern "C" {

void* TCMallocInternalNew(size_t);
void TCMallocInternalDelete(void*);
void TCMallocInternalDeleteSized(void*, size_t);

} // extern "C"

namespace tcmalloc {
namespace {

struct Allocator {
Allocator(std::atomic<bool>& stop, bool do_sized_delete)
: stop(stop), do_sized_delete(do_sized_delete) {}

void operator()() {
const int kNumAllocations = 65536;
std::vector<void*> v;
v.reserve(kNumAllocations);

absl::BitGen rng;

while (!stop.load(std::memory_order_acquire)) {
const size_t size = 1u << absl::LogUniform(rng, 1, 12);
for (int i = 0; i < kNumAllocations; ++i) {
v.push_back(TCMallocInternalNew(size));
}

for (void* ptr : v) {
if (do_sized_delete) {
TCMallocInternalDeleteSized(ptr, size);
} else {
TCMallocInternalDelete(ptr);
}
}
v.clear();
}
}

std::atomic<bool>& stop;
bool do_sized_delete;
};

TEST(ParallelTest, Stable) {
#ifdef ABSL_HAVE_MEMORY_SANITIZER
// TODO(b/148986845): Enable this.
GTEST_SKIP() << "Skipping under msan.";
#endif
#ifdef ABSL_HAVE_THREAD_SANITIZER
// TODO(b/274996721): Enable this when Span::nonempty_index_ does not
// conflict with other bitfields.
GTEST_SKIP() << "Skipping under tsan.";
#endif
std::atomic<bool> stop{false};
Allocator a1(stop, /*do_sized_delete=*/true),
a2(stop, /*do_sized_delete=*/true), a3(stop, /*do_sized_delete=*/false);

std::thread t1(a1), t2(a2), t3(a3);

absl::SleepFor(absl::Seconds(1));

stop.store(true, std::memory_order_release);
t1.join();
t2.join();
t3.join();
}

} // namespace
} // namespace tcmalloc

0 comments on commit 0cb7acb

Please sign in to comment.