From 1e7b733a217b2e92f6188b27951dfaf22ac1e2f3 Mon Sep 17 00:00:00 2001 From: Aliaksey Kandratsenka Date: Sun, 4 Oct 2015 21:12:28 -0700 Subject: [PATCH] implemented (disabled by default) sized delete support gcc 5 and clang++-3.7 support sized deallocation from C++14. We are taking advantage of that by defining sized versions of operator delete. This is off by default so that if some existing programs that define own global operator delete without sized variant are not broken by tcmalloc's sized delete operator. There is also risk of breaking exiting code that deletes objects using wrong class (i.e. base class) without having virtual destructors. --- configure.ac | 32 +++++++++++++++++++--------- src/gperftools/tcmalloc.h.in | 2 ++ src/libc_override_gcc_and_weak.h | 7 ++++++ src/libc_override_redefine.h | 6 ++++++ src/tcmalloc.cc | 18 ++++++++++++++++ src/windows/gperftools/tcmalloc.h | 2 ++ src/windows/gperftools/tcmalloc.h.in | 2 ++ 7 files changed, 59 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 1148c21..321a0f3 100644 --- a/configure.ac +++ b/configure.ac @@ -323,16 +323,28 @@ AC_CACHE_CHECK([if the compiler supports -Wno-unused-result], AM_CONDITIONAL(HAVE_W_NO_UNUSED_RESULT, test "$perftools_cv_w_no_unused_result" = yes) -AC_CACHE_CHECK([if C++ compiler supports -fsized-deallocation], - perftools_cv_sized_deallocation_result, - [AC_LANG_PUSH(C++) - OLD_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS -fsized-deallocation" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,)], - perftools_cv_sized_deallocation_result=yes, - perftools_cv_sized_deallocation_result=no) - CXXFLAGS="$OLD_CXXFLAGS" - AC_LANG_POP(C++)]) +AC_ARG_ENABLE([sized-delete], + [AS_HELP_STRING([--enable-sized-delete], + [build sized delete operator])], + [enable_sized_delete="$enableval"], + [enable_sized_delete="no"]) +AS_IF([test "x$enable_sized_delete" = xyes], + [AC_DEFINE([ENABLE_SIZED_DELETE], 1, [Build sized deletion operators]) + AC_MSG_NOTICE([Will build sized deallocation operators])], + [AC_MSG_NOTICE([Will not build sized deallocation operators])]) + +AS_IF([test "x$enable_sized_delete" = xyes], + [AC_CACHE_CHECK([if C++ compiler supports -fsized-deallocation], + perftools_cv_sized_deallocation_result, + [AC_LANG_PUSH(C++) + OLD_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fsized-deallocation" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,)], + perftools_cv_sized_deallocation_result="$enable_sized_delete", + perftools_cv_sized_deallocation_result=no) + CXXFLAGS="$OLD_CXXFLAGS" + AC_LANG_POP(C++)])]) + AM_CONDITIONAL(HAVE_SIZED_DEALLOCATION, test "$perftools_cv_sized_deallocation_result" = yes) diff --git a/src/gperftools/tcmalloc.h.in b/src/gperftools/tcmalloc.h.in index 0334d3f..0eaa21a 100644 --- a/src/gperftools/tcmalloc.h.in +++ b/src/gperftools/tcmalloc.h.in @@ -122,12 +122,14 @@ extern "C" { PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void tc_delete(void* p) __THROW; + PERFTOOLS_DLL_DECL void tc_delete_sized(void* p, size_t size) throw(); PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void* tc_newarray(size_t size); PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void tc_deletearray(void* p) __THROW; + PERFTOOLS_DLL_DECL void tc_deletearray_sized(void* p, size_t size) throw(); PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p, const std::nothrow_t&) __THROW; } diff --git a/src/libc_override_gcc_and_weak.h b/src/libc_override_gcc_and_weak.h index 818e43d..5c0def2 100644 --- a/src/libc_override_gcc_and_weak.h +++ b/src/libc_override_gcc_and_weak.h @@ -71,6 +71,13 @@ void operator delete(void* p, const std::nothrow_t& nt) __THROW void operator delete[](void* p, const std::nothrow_t& nt) __THROW ALIAS(tc_deletearray_nothrow); +#ifdef ENABLE_SIZED_DELETE +void operator delete(void *p, size_t size) throw() + ALIAS(tc_delete_sized); +void operator delete[](void *p, size_t size) throw() + ALIAS(tc_deletearray_sized); +#endif + extern "C" { void* malloc(size_t size) __THROW ALIAS(tc_malloc); void free(void* ptr) __THROW ALIAS(tc_free); diff --git a/src/libc_override_redefine.h b/src/libc_override_redefine.h index a1e50f8..4c61116 100644 --- a/src/libc_override_redefine.h +++ b/src/libc_override_redefine.h @@ -66,6 +66,12 @@ void operator delete(void* ptr, const std::nothrow_t& nt) __THROW { void operator delete[](void* ptr, const std::nothrow_t& nt) __THROW { return tc_deletearray_nothrow(ptr, nt); } + +#ifdef ENABLE_SIZED_DELETE +void operator delete(void* p, size_t s) __THROW { tc_delete_sized(p, s); } +void operator delete[](void* p, size_t s) __THROW{ tc_deletearray_sized(p); } +#endif + extern "C" { void* malloc(size_t s) __THROW { return tc_malloc(s); } void free(void* p) __THROW { tc_free(p); } diff --git a/src/tcmalloc.cc b/src/tcmalloc.cc index f168dfd..d1e7167 100644 --- a/src/tcmalloc.cc +++ b/src/tcmalloc.cc @@ -1595,6 +1595,24 @@ extern "C" PERFTOOLS_DLL_DECL void tc_free_sized(void *ptr, size_t size) __THROW do_free_with_callback(ptr, &InvalidFree, true, size); } +#if defined(__GNUC__) && !defined(WIN32) + +extern "C" PERFTOOLS_DLL_DECL void tc_delete_sized(void *p, size_t size) throw() + __attribute__((alias("tc_free_sized"))); +extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_sized(void *p, size_t size) throw() + __attribute__((alias("tc_free_sized"))); + +#else + +extern "C" PERFTOOLS_DLL_DECL void tc_delete_sized(void *p, size_t size) throw() { + tc_free_sized(p, size); +} +extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_sized(void *p, size_t size) throw() { + tc_free_sized(p, size); +} + +#endif + extern "C" PERFTOOLS_DLL_DECL void* tc_calloc(size_t n, size_t elem_size) __THROW { void* result = do_calloc(n, elem_size); diff --git a/src/windows/gperftools/tcmalloc.h b/src/windows/gperftools/tcmalloc.h index 5867c7c..9c4753f 100644 --- a/src/windows/gperftools/tcmalloc.h +++ b/src/windows/gperftools/tcmalloc.h @@ -112,12 +112,14 @@ extern "C" { PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void tc_delete(void* p) __THROW; + PERFTOOLS_DLL_DECL void tc_delete_sized(void* p, size_t size) throw(); PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void* tc_newarray(size_t size); PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void tc_deletearray(void* p) __THROW; + PERFTOOLS_DLL_DECL void tc_deletearray_sized(void* p, size_t size) throw(); PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p, const std::nothrow_t&) __THROW; } diff --git a/src/windows/gperftools/tcmalloc.h.in b/src/windows/gperftools/tcmalloc.h.in index a7ec70f..c963e31 100644 --- a/src/windows/gperftools/tcmalloc.h.in +++ b/src/windows/gperftools/tcmalloc.h.in @@ -112,12 +112,14 @@ extern "C" { PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void tc_delete(void* p) __THROW; + PERFTOOLS_DLL_DECL void tc_delete_sized(void* p, size_t size) throw(); PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void* tc_newarray(size_t size); PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void tc_deletearray(void* p) __THROW; + PERFTOOLS_DLL_DECL void tc_deletearray_sized(void* p, size_t size) throw(); PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p, const std::nothrow_t&) __THROW; }