simplify tcmalloc/sbrk/sbrk-hooks integration
Instead of relying on __sbrk (on subset of Linux systems) or invoking
sbrk syscall directly (on subset of FreeBSD systems), we have malloc
invoke special tcmalloc_hooked_sbrk function. Which handles hooking
and then invokes regular system's sbrk. Yes, we loose theoretical
ability to hook into non-tcmalloc uses of sbrk, but we gain portable
simplicity.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 51664e7..7e969ee 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -187,7 +187,6 @@
check_type_size("struct mallinfo" STRUCT_MALLINFO LANGUAGE CXX)
check_type_size("struct mallinfo2" STRUCT_MALLINFO2 LANGUAGE CXX)
check_function_exists("sbrk" HAVE_SBRK) # for tcmalloc to get memory
-check_function_exists("__sbrk" HAVE___SBRK) # for tcmalloc to get memory
check_function_exists("geteuid" HAVE_GETEUID) # for turning off services when run as root
check_include_file("features.h" HAVE_FEATURES_H) # for vdso_support.h, Where __GLIBC__ is defined
check_include_file("malloc.h" HAVE_MALLOC_H) # some systems define stuff there, others not
diff --git a/cmake/config.h.in b/cmake/config.h.in
index 0c9145f..db9d3f8 100644
--- a/cmake/config.h.in
+++ b/cmake/config.h.in
@@ -143,9 +143,6 @@
/* Define to 1 if compiler supports __environ */
#cmakedefine HAVE___ENVIRON
-/* Define to 1 if you have the `__sbrk' function. */
-#cmakedefine01 HAVE___SBRK
-
/* Always the empty-string on non-windows systems. On windows, should be
"__declspec(dllexport)". This way, when we compile the dll, we export our
functions/classes. It's safe to define this here because config.h is only
diff --git a/configure.ac b/configure.ac
index 85b399e..f5a0ebd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -254,7 +254,6 @@
AC_CHECK_TYPES([struct mallinfo],,, [#include <malloc.h>])
AC_CHECK_TYPES([struct mallinfo2],,, [#include <malloc.h>])
AC_CHECK_FUNCS(sbrk) # for tcmalloc to get memory
-AC_CHECK_FUNCS(__sbrk) # for tcmalloc to get memory
AC_CHECK_FUNCS(geteuid) # for turning off services when run as root
AC_CHECK_HEADERS(features.h) # for vdso_support.h, __GLIBC__ macros
AC_CHECK_HEADERS(malloc.h) # some systems define stuff there, others not
diff --git a/src/mmap_hook.cc b/src/mmap_hook.cc
index e375ad2..9c62209 100644
--- a/src/mmap_hook.cc
+++ b/src/mmap_hook.cc
@@ -161,23 +161,6 @@
}
}
- static MappingEvent FillSbrk(void* result, intptr_t increment) {
- MappingEvent evt;
- evt.is_sbrk = 1;
- if (increment > 0) {
- evt.after_address = result;
- evt.after_length = increment;
- evt.after_valid = 1;
- } else {
- intptr_t res_addr = reinterpret_cast<uintptr_t>(result);
- intptr_t new_brk = res_addr + increment;
- evt.before_address = reinterpret_cast<void*>(new_brk);
- evt.before_length = -increment;
- evt.before_valid = 1;
- }
- return evt;
- }
-
private:
std::atomic<MappingHookDescriptor*> list_head_{};
std::atomic<bool> ran_initial_hooks_{};
@@ -481,62 +464,30 @@
return result;
}
+#endif // __linux__
-#endif
-
-#if defined(__linux__) && HAVE___SBRK
-// glibc's version:
-extern "C" void* __sbrk(intptr_t increment);
-
-#define do_sbrk(i) __sbrk(i)
-
-#define HOOKED_SBRK
-#endif // linux and __sbrk
-
-#if defined(__FreeBSD__) && defined(_LP64) && defined(HAVE_SBRK)
-static void* do_sbrk(intptr_t increment) {
- uintptr_t curbrk = __syscall(SYS_break, nullptr);
- uintptr_t badbrk = static_cast<uintptr_t>(static_cast<intptr_t>(-1));
- if (curbrk == badbrk) {
- nomem:
- errno = ENOMEM;
- return reinterpret_cast<void*>(badbrk);
- }
-
- if (increment == 0) {
- return reinterpret_cast<void*>(curbrk);
- }
-
- if (increment > 0) {
- if (curbrk + static_cast<uintptr_t>(increment) < curbrk) {
- goto nomem;
- }
- } else {
- if (curbrk + static_cast<uintptr_t>(increment) > curbrk) {
- goto nomem;
- }
- }
-
- if (brk(reinterpret_cast<void*>(curbrk + increment)) < 0) {
- goto nomem;
- }
-
- return reinterpret_cast<void*>(curbrk);
-}
-
-#define HOOKED_SBRK
-#endif // FreeBSD
-
-#ifdef HOOKED_SBRK
-extern "C" PERFTOOLS_DLL_DECL ATTRIBUTE_NOINLINE void* sbrk(intptr_t increment) __THROW;
-
-void* sbrk(intptr_t increment) __THROW {
- void *result = do_sbrk(increment);
- if (increment == 0 || result == reinterpret_cast<void*>(static_cast<intptr_t>(-1))) {
+#if defined(HAVE_SBRK)
+extern "C" ATTRIBUTE_VISIBILITY_HIDDEN ATTRIBUTE_NOINLINE
+void* tcmalloc_hooked_sbrk(intptr_t increment) {
+ void *result = sbrk(increment);
+ if (increment == 0 || result == reinterpret_cast<void*>(intptr_t{-1})) {
return result;
}
- tcmalloc::MappingEvent evt = tcmalloc::MappingHooks::FillSbrk(result, increment);
+ tcmalloc::MappingEvent evt;
+ evt.is_sbrk = 1;
+ if (increment > 0) {
+ evt.after_address = result;
+ evt.after_length = increment;
+ evt.after_valid = 1;
+ } else {
+ intptr_t res_addr = reinterpret_cast<uintptr_t>(result);
+ intptr_t new_brk = res_addr + increment;
+ evt.before_address = reinterpret_cast<void*>(new_brk);
+ evt.before_length = -increment;
+ evt.before_valid = 1;
+ }
+
BacktraceHelper helper;
int want_stack = helper.PreInvoke(&evt);
if (want_stack) {
@@ -546,7 +497,7 @@
return result;
}
-#endif // HOOKED_SBRK
+#endif
namespace tcmalloc {
#ifdef HOOKED_MMAP
@@ -554,10 +505,4 @@
#else
const bool mmap_hook_works = false;
#endif
-
-#ifdef HOOKED_SBRK
-const bool sbrk_hook_works = true;
-#else
-const bool sbrk_hook_works = false;
-#endif
} // namespace tcmalloc
diff --git a/src/system-alloc.cc b/src/system-alloc.cc
index e47691e..14c8ae2 100644
--- a/src/system-alloc.cc
+++ b/src/system-alloc.cc
@@ -168,6 +168,17 @@
static const char sbrk_name[] = "SbrkSysAllocator";
static const char mmap_name[] = "MmapSysAllocator";
+#ifdef HAVE_SBRK
+extern "C" {
+ // When we're building "full" tcmalloc with mmap_hook.cc linked-in,
+ // this definition gets overriden by definition in mmap_hook.cc
+ // which handles hooks which is required by heap checker.
+ ATTRIBUTE_VISIBILITY_HIDDEN ATTRIBUTE_WEAK
+ void* tcmalloc_hooked_sbrk(intptr_t increment) {
+ return sbrk(increment);
+ }
+}
+#endif
void* SbrkSysAllocator::Alloc(size_t size, size_t *actual_size,
size_t alignment) {
@@ -205,11 +216,11 @@
// http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libc/port/sys/sbrk.c?a=true
// http://sourceware.org/cgi-bin/cvsweb.cgi/~checkout~/libc/misc/sbrk.c?rev=1.1.2.1&content-type=text/plain&cvsroot=glibc
// Without this check, sbrk may succeed when it ought to fail.)
- if (reinterpret_cast<intptr_t>(sbrk(0)) + size < size) {
+ if (reinterpret_cast<intptr_t>(tcmalloc_hooked_sbrk(0)) + size < size) {
return NULL;
}
- void* result = sbrk(size);
+ void* result = tcmalloc_hooked_sbrk(size);
if (result == reinterpret_cast<void*>(-1)) {
return NULL;
}
@@ -220,7 +231,7 @@
// Try to get more memory for alignment
size_t extra = alignment - (ptr & (alignment-1));
- void* r2 = sbrk(extra);
+ void* r2 = tcmalloc_hooked_sbrk(extra);
if (reinterpret_cast<uintptr_t>(r2) == (ptr + size)) {
// Contiguous with previous result
return reinterpret_cast<void*>(ptr + extra);
@@ -228,7 +239,7 @@
// Give up and ask for "size + alignment - 1" bytes so
// that we can find an aligned region within it.
- result = sbrk(size + alignment - 1);
+ result = tcmalloc_hooked_sbrk(size + alignment - 1);
if (result == reinterpret_cast<void*>(-1)) {
return NULL;
}
diff --git a/src/tests/mmap_hook_test.cc b/src/tests/mmap_hook_test.cc
index a6e205f..206bc49 100644
--- a/src/tests/mmap_hook_test.cc
+++ b/src/tests/mmap_hook_test.cc
@@ -255,13 +255,20 @@
#ifdef HAVE_SBRK
+extern "C" void* tcmalloc_hooked_sbrk(intptr_t increment);
+
+static bool sbrk_works = ([] () {
+ void* result = tcmalloc_hooked_sbrk(8);
+ return result != reinterpret_cast<void*>(intptr_t{-1});
+}());
+
TEST_F(MMapHookTest, Sbrk) {
- if (!tcmalloc::sbrk_hook_works) {
+ if (!sbrk_works) {
puts("sbrk test SKIPPED");
return;
}
- void* addr = sbrk(8);
+ void* addr = tcmalloc_hooked_sbrk(8);
ASSERT_TRUE(got_first_allocation);
@@ -273,7 +280,7 @@
ASSERT_FALSE(HasFatalFailure());
have_last_evt_ = false;
- void* addr2 = sbrk(16);
+ void* addr2 = tcmalloc_hooked_sbrk(16);
EXPECT_TRUE(last_evt_.is_sbrk);
EXPECT_TRUE(!last_evt_.before_valid && !last_evt_.file_valid && last_evt_.after_valid);
@@ -283,7 +290,7 @@
ASSERT_FALSE(HasFatalFailure());
have_last_evt_ = false;
- char* addr3 = static_cast<char*>(sbrk(-13));
+ char* addr3 = static_cast<char*>(tcmalloc_hooked_sbrk(-13));
EXPECT_TRUE(last_evt_.is_sbrk);
EXPECT_TRUE(last_evt_.before_valid && !last_evt_.file_valid && !last_evt_.after_valid);
@@ -295,7 +302,7 @@
}
TEST_F(MMapHookTest, SbrkBacktrace) {
- if (!tcmalloc::sbrk_hook_works) {
+ if (!sbrk_works) {
puts("sbrk backtrace test SKIPPED");
return;
}
@@ -325,7 +332,7 @@
expected_address, reinterpret_cast<void*>(&Helper::trampoline));
// Why cast? Because some OS-es define sbrk as accepting long.
- Helper::trampoline(&addr, reinterpret_cast<void*(*)(intptr_t)>(sbrk));
+ Helper::trampoline(&addr, reinterpret_cast<void*(*)(intptr_t)>(tcmalloc_hooked_sbrk));
ASSERT_NE(nullptr, addr);
ASSERT_EQ(backtrace_address_, expected_address);
}
diff --git a/src/windows/port.cc b/src/windows/port.cc
index a31e866..79043e2 100644
--- a/src/windows/port.cc
+++ b/src/windows/port.cc
@@ -64,11 +64,6 @@
return pagesize;
}
-extern "C" PERFTOOLS_DLL_DECL void* __sbrk(ptrdiff_t increment) {
- LOG(FATAL, "Windows doesn't implement sbrk!\n");
- return NULL;
-}
-
// We need to write to 'stderr' without having windows allocate memory.
// The safest way is via a low-level call like WriteConsoleA(). But
// even then we need to be sure to print in small bursts so as to not
diff --git a/vsprojects/include/config.h b/vsprojects/include/config.h
index db21e16..3e01043 100644
--- a/vsprojects/include/config.h
+++ b/vsprojects/include/config.h
@@ -149,9 +149,6 @@
/* Define to 1 if compiler supports __environ */
/* #undef HAVE___ENVIRON */
-/* Define to 1 if you have the `__sbrk' function. */
-/* #undef HAVE___SBRK */
-
/* Always the empty-string on non-windows systems. On windows, should be
"__declspec(dllexport)". This way, when we compile the dll, we export our
functions/classes. It's safe to define this here because config.h is only